[Ltrace-devel] DWARF prototypes: handling symbol aliases

Dima Kogan lists at dima.secretsauce.net
Mon May 12 22:25:28 UTC 2014


As noted in the previous thread, there's an issue with parsing the
prototypes from the DWARF data caused by multiple symbol names referring
to the same address. A simple example is tracing this simple program
with ltrace:

 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <time.h>
 int main(void)
 {
     nanosleep( &(struct timespec){.tv_sec=0,.tv_nsec=33}, NULL);
     usleep(44);
     return 0;
 }

I get this:

 dima at shorty:~/projects/ltrace$ ./ltrace -x '*nanosleep at libc.so*' -e '' /tmp/tst

 nanosleep at libc.so.6(0x7fffd8596b00, 0, 0x7fffd8596c08, 0)        = 0
 nanosleep at libc.so.6(0x7fffd8596ae0, 0, 0, -1)                    = 0
 +++ exited (status 0) +++

Note that the nanosleep() calls do not have the correct prototypes. This
is because we call nanosleep(), but the DWARF defines __nanosleep and
__GI___nanosleep:


 dima at shorty:~/projects/ltrace$ nm -D /tmp/tst | grep nanosleep

                  U nanosleep


 dima at shorty:~/projects/ltrace$ nm -D /lib/x86_64-linux-gnu/libc-2.18.so | grep nanosleep

 00000000000f26f0 T __clock_nanosleep
 00000000000b7070 W __nanosleep
 00000000000f26f0 W clock_nanosleep
 00000000000b7070 W nanosleep


 dima at shorty:~/projects/ltrace$ readelf -w /usr/lib/debug/lib/x86_64-linux-gnu/libc-2.18.so | grep nanosleep

     <20c7cf>   DW_AT_name        : (indirect string, offset: 0x13a95): __nanosleep
     <20c7d5>   DW_AT_linkage_name: (indirect string, offset: 0x13a90): __GI___nanosleep
     <280d67>   DW_AT_name        : (indirect string, offset: 0x13a95): __nanosleep
     <280d6d>   DW_AT_linkage_name: (indirect string, offset: 0x13a90): __GI___nanosleep
     <2dc871>   DW_AT_name        : (indirect string, offset: 0x1d940): __clock_nanosleep
     <3b0b59>   DW_AT_name        : (indirect string, offset: 0x13a95): __nanosleep
     <3b0b5f>   DW_AT_linkage_name: (indirect string, offset: 0x13a90): __GI___nanosleep


We can resolve this discrepancy by noting that the nanosleep symbol in
the libc symbol table has the same address and __nanosleep, and use
__nanosleep's DWARF prototype. I implemented this, and the code is
available in my tree:

 https://github.com/dkogan/ltrace/tree/libsym_aliases

The same ltrace run from before now looks like this:

 dima at shorty:~/projects/ltrace$ ./ltrace -x '*nanosleep at libc.so*' -e '' /tmp/tst

 nanosleep at libc.so.6({ 0, 33 }, nil)                              = 0
 nanosleep at libc.so.6({ 0, 44000 }, nil)                           = 0


So that's good. This doesn't solve the problem completely, however. If
we invoke ltrace with -l, we still see the problematic behavior:


 dima at shorty:~/projects/ltrace$ ./ltrace -l 'libc*' /tmp/tst

 tst->__libc_start_main(0x40054d, 1, '/', 0x400590, 0x400600, 0x7f611a967d50, 0x7fffd468b8b8 <unfinished ...>
 tst->nanosleep(0x7fffd468b7d0, 0, 0x7fffd468b8d8, 0)             = 0
 tst->usleep(44)                                                  = 0
 libc.so.6->__strcasecmp('\001', '\200')                          = 448018048
 +++ exited (status 0) +++


This happens (as I understand it) because the symbols are now read from
/tmp/tst, not from libc.so. The /tmp/tst symbol table only has
nanosleep, and not __nanosleep, so we don't see that those are
equivalent.

I'd like a bit of advice before I try to fix this. The current
implementation looks for aliased symbols in the same bit of code that
places the breakpoints. I'm thinking of moving this logic to the
prototype-generating side, so all the known names of a symbol would have
a reasonable prototype. This doesn't even need to depend on the DWARF.
There could simply be a pass that looks for all aliased symbols where
just one has a known prototype (from a config file or from DWARF), and
assigns this prototype to the aliased symbols. Does that sound like a
good approach?

dima



More information about the Ltrace-devel mailing list