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);
}
tur1ng
  • 3,139
  • 5
  • 24
  • 31
  • 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. – Krzak Jan 22 '15 at 12:30

1 Answers1

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).

Jérôme Pouiller
  • 9,249
  • 5
  • 39
  • 47
  • 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. – tur1ng Jan 29 '15 at 14:24
  • 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`. – Jérôme Pouiller Feb 02 '15 at 16:53