Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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);
}
like image 469
tur1ng Avatar asked Jan 07 '15 09:01

tur1ng


1 Answers

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

like image 75
Jérôme Pouiller Avatar answered Oct 11 '22 19:10

Jérôme Pouiller