Different offset in libc's backtrace_symbols() and libunwind's unw_get_proc_name()
Asked Answered
L

1

9

I make a stack trace at some point in my program. Once with libc's backtrace_symbols() function and once with unw_get_proc_name() from libunwind.

backtrace_symbols() output:

/home/jj/test/mylib.so(+0x97004)[0x7f6b47ce9004]

unw_get_proc_name() output:

ip: 0x7f6b47ce9004, offset: 0x458e4

Here you see that the instruction pointer address (0x7f6b47ce9004) is the same and correct. The function offset 0x97004 from backtrace_symbols() is also correct but not the one I get from unw_get_proc_name() (0x458e4).

Does somebody have a clue what's going on here and what might cause this difference in offsets?

Both methods use a similar code like the following examples:

backtrace():

void *array[10];
size_t size;

size = backtrace(array, 10);
backtrace_symbols_fd(array, size, STDERR_FILENO);

libunwind:

unw_cursor_t    cursor;
unw_context_t   context;

unw_getcontext(&context);
unw_init_local(&cursor, &context);

while (unw_step(&cursor) > 0) {
    unw_word_t  offset, pc; 
    char        fname[64];

    unw_get_reg(&cursor, UNW_REG_IP, &pc);

    fname[0] = '\0';
    (void) unw_get_proc_name(&cursor, fname, sizeof(fname), &offset);

    printf ("%p : (%s+0x%x) [%p]\n", pc, fname, offset, pc);
}
Lanceolate answered 7/1, 2015 at 9:47 Comment(1)
You're not checking the return value from unw_get_proc_name. Perhaps it's not succesful and returns an error code? It doesn't seem to, but IMO you should still. Besides you're not showing the printf for backtrace(). The one for libunwind might suggest that you have your printfs mislabeled.Tamtama
W
1

I think unw_get_proc_name compute offset from an unnamed internal frame.

For example:

void f() {
   int i;
   while (...) {
     int j;
   }
}

Notice there is a variable declaration inside loop block. In this case (and depending of level of optimization), compiler may create a frame (and related unwind information) for the loop. Consequently, unw_get_proc_name compute offset from this loop instead of begin of function.

This is explained in unw_get_proc_name man page:

Note that on some platforms there is no reliable way to distinguish between procedure names and ordinary labels. Furthermore, if symbol information has been stripped from a program, procedure names may be completely unavailable or may be limited to those exported via a dynamic symbol table. In such cases, unw_get_proc_name() may return the name of a label or a preceeding (nearby) procedure.

You may try to test again but without stripping your binary (Since unw_get_proc_name is not able to find name of function, I think your binary is stripped).

Whaling answered 22/1, 2015 at 12:22 Comment(2)
Seen that sentence in the documentation and it makes sense. But why is backtrace() then capable of computing the real offset? It looks to me that my problem is related to another cause.Lanceolate
Well... I finally ask myself the same question... :-( The only thing I am sure is on i386/x86_64, either backtrace (using libgcc_s.so) and libunwind relies on .eh_frame information. Consequently, these differences come from implementation of libunwind and libgcc_s. While libunwind explicitly expose problem, I don't find any reference about that in libgcc_s.so.Bezel

© 2022 - 2024 — McMap. All rights reserved.