[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