15

I am developing a program under Linux.

For debugging purposes I want to trace all calls from my program to a certain (preferably shared) library. (I do not want to trace calls happening inside the library.)

For syscalls there is strace. Is there any instrument to trace calls to a shared library?

porton
  • 5,214
  • 11
  • 47
  • 95
  • What do you mean exactly ? In fact, `strace` is tracing every system call from the program. Including the ones issued by external functions dynamically loaded while execution (shared libraries, plugins). The only possible problem might come from multiprocess programs. – perror Aug 05 '14 at 11:49
  • I don't need to trace system calls. I need to trace all calls to a shared library. It is just *similar* to strace: strace traces syscalls but I want to trace calls to a library (not syscalls) instead. – porton Aug 05 '14 at 11:51
  • okay, got it. I write you an answer. But, waiting for it, look at `ltrace`. – perror Aug 05 '14 at 11:55

1 Answers1

22

The tool you are looking for is called ltrace. It allows to trace any call from the program to all (or a set of given) libraries.

For example, the following call will list any call to an external function loaded by a shared library:

$> ltrace ls /
__libc_start_main(0x4028c0, 2, 0x7fff1f4e72d8, 0x411e60 <unfinished ...>
strrchr("ls", '/')                               = nil
setlocale(LC_ALL, "")                            = "en_US.UTF-8"
bindtextdomain("coreutils", "/usr/share/locale") = "/usr/share/locale"
textdomain("coreutils")                          = "coreutils"
__cxa_atexit(0x40a200, 0, 0, 0x736c6974756572)   = 0
isatty(1)                                        = 0
getenv("QUOTING_STYLE")                          = nil
getenv("COLUMNS")                                = nil
ioctl(1, 21523, 0x7fff1f4e6e80)                  = -1
getenv("TABSIZE")                                = nil
getopt_long(2, 0x7fff1, "abcdfghiklmnopqrstuvw:xABCDFGHI:"..., 0x413080, -1) = -1
...
+++ exited (status 0) +++

If you want to focus on a particular library, then you should use the --library=pattern option:

-l, --library library_pattern
    Display only calls to functions implemented by libraries that match
    library_pattern. Multiple library patterns can be specified with several
    instances of this option. Syntax of library_pattern is described in 
    section FILTER EXPRESSIONS.

    Note that while this option selects calls that might be directed to the 
    selected libraries, there's no actual guarantee that the call won't be 
    directed elsewhere due to e.g. LD_PRELOAD or simply dependency ordering.
    If you want to make sure that symbols in given library are actually called,
    use -x @library_pattern instead.

So, for example, getting the list of calls to libselinux.so.1 is done like this:

$ ltrace -l libselinux.so.1 ls /
ls->freecon(0, 0xffffffff, 0x7f78c4eee628, 0)                           = 0
bin dev media root sbin sys usr boot etc home lib lost+found proc run tmp
+++ exited (status 0) +++

Only one call to the function freecon() is taken out this run.

perror
  • 7,071
  • 16
  • 58
  • 85
  • `run_all_tests->raptor_new_uri_from_counted_string(0x87f8ad0, 0xf76b0958, 22, 0 ` - how to get rid of "unfinished" and print all function arguments? – porton Aug 05 '14 at 12:18
  • In fact, I have no idea on how to get rid of this limitation (it seems that the number of diplayed arguments is always 4)... I first though it was due to the 80-columns constraint, then I tried the `-A` option without success. So, I really don't know. My advice would be to use a debugger (such as `gdb`) once you located the function call. – perror Aug 05 '14 at 12:40
  • @porton If ltrace does not know the function it just assumes it has 4 arguments. You can teach ltrace new functions by writing a prototype file for the library. [This article](https://developers.redhat.com/blog/2014/07/10/ltrace-for-rhel-6-and-7/) has more info. – rveerd Aug 02 '19 at 06:34