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.