7

How does ltrace work?

How does it find out which library functions a program calls?

Is there any common code path that all calls to library functions go through? Maybe ltrace sets breakpoints in this common code path?

Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
Marko Kevac
  • 2,902
  • 30
  • 47
  • Usually debugging symbols left in the compiled binary will provide function call names, program flow, etc. Stripping the binary usually removes this (making debugging harder). – SnakeDoc Aug 25 '15 at 21:08
  • 3
    `ltrace` is open source. So you could just look at the source... – larsks Aug 25 '15 at 21:09

1 Answers1

8

Dynamic executables have a symbol table used by the linker when resolving references that need to be connected to library functions. (You can see this yourself by running objdump -T /path/to/binary).

This symbol table is accessible by other tools -- such as ltrace -- as well, so it's trivial to determine which functions need to be hooked and walk that list individually.

See a talk on ltrace internals presented at the Ottowa Linux Symposium, which provides a detailed, function-by-function breakdown; to follow along the source, see the official repository, or a third-party github mirror.

Some newer releases (more recent than that talk) also hook the dlopen() call, to be able to trace invocation of dynamically loaded libraries as well. The mechanism there should be rather obvious on a moment's thought -- if one can replace dlopen() with a shim (when dlopen() itself is dynamically linked as above), one can then set a breakpoint on any function pointer it returns.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • Thank you for the answer. The symbol table is populated after executable starts, right? So ltrace is probably reading addresses from symbol table just after program starts? – Marko Kevac Aug 25 '15 at 21:42
  • `ld.so` (on Linux) performs linking and loading *before* `main()` is called. See `man ld.so`. – Charles Duffy Aug 25 '15 at 21:45
  • Yes, I am aware of that. So ltrace must stop the program between ld.so populates the tables and main() begins to read addresses from the symbol table. – Marko Kevac Aug 25 '15 at 21:47
  • As I read the paper, it rather does the work that would otherwise be performed by `ld.so` itself, adding hooks along the way. But given as there's primary material here, you'd be better off referring to it directly. :) – Charles Duffy Aug 25 '15 at 21:49