🍗 Wiki

ltrace

ltrace

1. Install

If you’re using Ubuntu or Debian, you can install it with apt.

sudo apt install ltrace

It is also available on Nix.

nix-shell -p ltrace

2. Build

But you might want to build it with the source code. And the ltrace is not available on Raspberry Pi OS.

Basically, the ltrace tool requires GNU Autoconf, libtool, and libelf.

sudo apt install autoconf libtool libelf-dev

100.111.193.65 Then, generate the 'configure' script.

./autogen.sh

If you can see the configure script is exist, run it.

./configure

If the script run successfully, finally you can make to get the 'ltrace' executable.

make

After that, there should be 'ltrace' executable in the root of the source code directory.

In order to make it available on your system, you can run make install command.

3. Usage

ltrace is a tool for tracing the library call. In C and C, even ``printf`` and ``std::cin`` are also functions from the external library called 'libc.so' and 'libstdc.so'. So it is really useful to track which functions are called without manually open IDA or Ghidra, to know which functions are called during its runtime, and to seek the function that I want to investigate was triggered.

In a point of developers' view, it is also useful to track where is the bottleneck. Because it supports printing when the function was called.

This is the basic usage of the ltrace command.

ltrace /bin/busybox

If you want to track that is already executed,

ltrace -p <pid>

3.1. Useful options

The most frequent options I used were -r option and -e option: the -r option for printing relative timestamp, and the -e option for seeking the function that I wanted to follow.

$ ltrace -r fish
  ...
  0.000352 _ZdlPv(0x156d550, 0, 4, 0x156d6e0) = 0x1503010
  0.000299 _ZdlPv(0x156d520, 0x156d540, 5485, 65) = 0x1503010
  0.000323 _ZNSt7__cxx1112basic_stringIwSt11char_traitsIwESaIwEE10_M_disposeEv(0x7ffc1943aa40, 0x156d510, 0x47119b, 49) = 0x7ffc1943aa50
  0.000512 wcslen(0x58aa68, 0x58aa68, 0x47119b, 49) = 1
  0.000339 wmemcpy(0x7ffc1943a980, 0x7ffc1943aa50, 2, 0x7ffc1943aa50) = 0x7ffc1943a980
  0.000356 _Znwm(32, 0x7ffc1943a970, 1, 0x1ffffffffffffff8) = 0x156d520
  0.000432 wcslen(0x595d60, 0, 0x1503010, 0) = 7
  0.000338 _ZNSt7__cxx1112basic_stringIwSt11char_traitsIwESaIwEE9_M_createERmm(0x156d520, 0x7ffc1943a740, 0, 0) = 0x156d6f0
  0.000442 wmemcpy(0x156d6f0, 0x595d60, 7, 7) = 0x156d6f0
  0.000340 wcslen(0x58f110, 0x58f110, 28, 0x156d660) = 7
  0.000432 _ZNSt7__cxx1112basic_stringIwSt11char_traitsIwESaIwEE9_M_createERmm(0x7ffc1943a880, 0x7ffc1943a740, 0, 0x156d660) = 0x156d720
  0.000506 wmemcpy(0x156d720, 0x58f110, 7, 7) = 0x156d720
  0.000449 wcslen(0x58f110, 0x58f110, 28, 7) = 7
  ...

In this case, let’s trace the wmemcpy and its friends for example.

$ ltrace -Cr -e 'wmem* fish'
  ...
  0.000456 libstdc++.so.6->wmemchr(0x592a20, 108, 10, 0xffa6d5e0) = 0
  0.000355 libstdc++.so.6->wmemchr(0x592a20, 105, 10, 0xffa6d5e0) = 0
  0.000367 libstdc++.so.6->wmemchr(0x592a20, 97, 10, 0xffa6d5e0) = 0
  0.000396 libstdc++.so.6->wmemchr(0x592a20, 115, 10, 0xffa6d5e0) = 0
  0.000357 libstdc++.so.6->wmemcpy(0xfc9e50, 0xfdcbe0, 5, 0) = 0xfc9e50
  0.000411 fish->wmemcmp(0xfc9e50, 0x58a5dc, 5, 5)       = 0xffffffff
  0.000539 fish->wmemcmp(0xfc9e50, 0x58a5dc, 5, 5)       = 0xffffffff
  0.000373 libstdc++.so.6->wmemcpy(0xfdcbe0, 0xfa2284, 3, 5) = 0xfdcbe0
  0.000681 fish->wmemcpy(0x7ffeb0d318c0, 0x7ffeb0d316a0, 3, 0x7ffeb0d316a0) = 0x7ffeb0d318c0
  0.000296 libstdc++.so.6->wmemcpy(0xfdcbe0, 0xfa2294, 21, 3) = 0xfdcbe0
  0.000420 libstdc++.so.6->wmemcpy(0xfdcbe0, 0xfa2314, 2, 21) = 0xfdcbe0
  0.000477 fish->wmemcmp(0xfdcbe0, 0x589840, 2, 0x610000006c) = 1
  0.000388 libstdc++.so.6->wmemcpy(0xfdcbe0, 0xfa22fc, 5, 2) = 0xfdcbe0
  0.000509 libstdc++.so.6->wmemcpy(0xfdcbe0, 0xfa22fc, 5, 5) = 0xfdcbe0
  0.000518 libstdc++.so.6->wmemchr(0x592a20, 97, 10, 10) = 0
  0.000311 libstdc++.so.6->wmemchr(0x592a20, 108, 10, 0xffa6d5e0) = 0
  0.000316 libstdc++.so.6->wmemchr(0x592a20, 105, 10, 0xffa6d5e0) = 0
  0.000425 libstdc++.so.6->wmemchr(0x592a20, 97, 10, 0xffa6d5e0) = 0
  0.000463 libstdc++.so.6->wmemchr(0x592a20, 115, 10, 0xffa6d5e0) = 0
  0.000370 libstdc++.so.6->wmemcpy(0xfc9e50, 0xfdcbe0, 5, 0) = 0xfc9e50
  0.000467 fish->wmemcmp(0xfc9e50, 0x58a5dc, 5, 5)       = 0xffffffff
  0.000502 fish->wmemcmp(0xfc9e50, 0x58a5dc, 5, 5)       = 0xffffffff
  ...

Don’t forget to append -C option if you are tracking a C++ application. You might want to see the function name demangled.

Without capitalizing the character, appending -c option will print a summarized report at exit.

% time     seconds  usecs/call     calls      function
------ ----------- ----------- --------- --------------------
 92.97   78.480191        7799     10062 __ctype_get_mb_cur_max
  1.14    0.966177          94     10175 _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_appendEPKcm
  1.14    0.961983          95     10063 wcrtomb
  0.61    0.515963          86      5990 wcslen
  0.51    0.433637          89      4849 iswalnum
  0.50    0.423624          90      4700 _ZdlPv
  0.50    0.418370          88      4732 _Znwm
  0.48    0.408381          91      4472 wmemcpy
  0.42    0.351423          87      4008 wcscmp
  0.26    0.220307          85      2570 _ZNSt7__cxx1112basic_stringIwSt11char_traitsIwESaIwEE10_M_replaceEmmPKwm
  0.26    0.217412          83      2604 wmemcmp
...

For more investigation in depth, you might want to investigate the whole log. With -o option, you will get a dump of log.