Как сопоставить адрес функции с функцией в * .so файлах - PullRequest
32 голосов
/ 26 сентября 2011

Функция обратной трассировки дает набор обратной трассировки, как сопоставить ее с именем функции / именем файла / номером строки?

for ex:-
backtrace() returned 8 addresses
./libtst.so(myfunc5+0x2b) [0xb7767767]
./libtst.so(fun4+0x4a) [0xb7767831]
./libtst.so(fun3+0x48) [0xb776787f]
./libtst.so(fun2+0x35) [0xb77678ba]
./libtst.so(fun1+0x35) [0xb77678f5]
./a.out() [0x80485b9]
/lib/libc.so.6(__libc_start_main+0xe5) [0xb75e9be5]
./a.out() [0x80484f1]

Из вышеприведенного стека, как я могу получить имя файла и номер строки?Я сделал следующие вещи, но не повезло.Поправьте меня, если я ошибаюсь:)

for ex:-
./libtst.so(fun2+0x35) [0xb77dc887]

0xb77dc887(fun2 addr+offset)-0xb77b6000 (lib starting addr) = 0x26887 (result)
result is no way related to function in nm output.

I used addr2line command:-
addr2line -f -e libtst.so 0xb77dc887
??
??:0

Итак, как я могу решить или во время выполнения или после выполнения?Заранее спасибо ...

nm:-
00000574 T _init
00000680 t __do_global_dtors_aux
00000700 t frame_dummy
00000737 t __i686.get_pc_thunk.bx
0000073c T myfunc5
000007e7 T fun4
00000837 T fun3
00000885 T fun2
000008c0 T fun1
00000900 t __do_global_ctors_aux
00000938 T _fini
000009b4 r __FRAME_END__
00001efc d __CTOR_LIST__
00001f00 d __CTOR_END__
00001f04 d __DTOR_LIST__
00001f08 d __DTOR_END__
00001f0c d __JCR_END__
00001f0c d __JCR_LIST__
00001f10 a _DYNAMIC
00001ff4 a _GLOBAL_OFFSET_TABLE_
00002030 d __dso_handle
00002034 A __bss_start
00002034 A _edata
00002034 b completed.5773
00002038 b dtor_idx.5775
0000203c B funptr
00002040 A _end
     U backtrace@@GLIBC_2.1
     U backtrace_symbols@@GLIBC_2.1
     U free@@GLIBC_2.0
     U __isoc99_scanf@@GLIBC_2.7
     U perror@@GLIBC_2.0
     U printf@@GLIBC_2.0
     U puts@@GLIBC_2.0
     w __cxa_finalize@@GLIBC_2.1.3
     w __gmon_start__
     w _Jv_RegisterClasses

pmap:-
START       SIZE     RSS     PSS   DIRTY    SWAP PERM MAPPING
08048000      4K      4K      4K      0K      0K r-xp /home/test/libtofun/a.out
08049000      4K      4K      4K      4K      0K r--p /home/test/libtofun/a.out
0804a000      4K      4K      4K      4K      0K rw-p /home/test/libtofun/a.out
...
b7767000      4K      4K      4K      0K      0K r-xp /home/test/libtofun/libtst.so
b7768000      4K      4K      4K      4K      0K r--p /home/test/libtofun/libtst.so
b7769000      4K      4K      4K      4K      0K rw-p /home/test/libtofun/libtst.so
....
Total:     1688K    376K     82K     72K      0K

128K для записи, приватный, 1560K только для чтения, 0K для общего доступа и 376K для ссылок

libtst.c:-

void myfunc5(void){
int j, nptrs;
#define SIZE 100
void *buffer[100];
char **strings;

nptrs = backtrace(buffer, SIZE);
printf("backtrace() returned %d addresses\n", nptrs);

strings = backtrace_symbols(buffer, nptrs);
if (strings == NULL) {
    perror("backtrace_symbols");
}

for (j = 0; j < nptrs; j++)
    printf("%s\n", strings[j]);

free(strings);
}

void fun4(){
char ip;
char *fun = "fun4\0";
printf("Fun name %s\n",fun);
scanf("%c",&ip);
myfunc5();
}


void fun3(){
char *fun = "fun3\0";
printf("Fun name %s\n",fun);
funptr = fun4;
funptr();
}


void fun2(){
char *fun = "fun2\0";
printf("Fun name %s\n",fun);
fun3();
}


void fun1(){
char *fun = "fun1\0";
printf("Fun name %s\n",fun);
fun2();
}

main.c:-

int main(){
char ip;
funptr = &fun1;
scanf("%c",&ip);
funptr();
return 0;
}

Дайте мне знать, если потребуется дополнительная информация ...

Ответы [ 4 ]

32 голосов
/ 26 сентября 2011

Попробуйте указать смещение для addr2line вместе с именем раздела.Например:

addr2line -j .text -e libtst.so 0x26887

Редактировать: Кстати, если неясно, 0x26887 исходит из того, что вы предоставили:

0xb77dc887(fun2 addr+offset)-0xb77b6000 (lib starting addr) = 0x26887 (result)

19 голосов
/ 28 мая 2014

Я просмотрел файлы backtrace.c и backtracesyms.c в исходном коде glibc (git: //sourceware.org/git/glibc.git, коммит 2482ae433a4249495859343ae1fba408300f2c2e).

Предполагая, что я не неправильно прочитал / неправильно понял: backtrace () сам по себе выглядит так, как будто он даст вам только адреса символов, как они есть во время выполнения, что, я думаю, означает, что вам нужен адрес загрузки библиотеки был из pmap или аналогичный. Однако backtrace_symbols () пересчитывает вещи так, что адреса относятся к разделяемой библиотеке ELF, а не к процессу во время выполнения, что действительно удобно. Это означает, что вам не нужна информация из pmap.

Итак, если вы скомпилировали с -g (или с -rdynamic), то вам повезло. Вы должны быть в состоянии сделать следующее:

$ # get the address in the ELF so using objdump or nm
$ nm libtst.so | grep myfunc
0000073c T myfunc5
$ # get the (hex) address after adding the offset 
$ # from the start of the symbol (as provided by backtrace_syms())
$ python -c 'print hex(0x0000073c+0x2b)'
0x767
$ # use addr2line to get the line information, assuming any is available            
addr2line -e libtst.so 0x767

Или, используя gdb:

$ gdb libtst.so
(gdb) info address myfunc
Symbol "myfunc" is at 0x073c in a file compiled without debugging. # (Faked output)
(gdb) info line *(0x073c+0x2b)
Line 27 of "foo.cpp" starts at address 0x767 <myfunc()+21> and ends at 0x769 <something>. # (Faked output)

Кроме того, если вы удалили библиотеку, но спрятали отладочные символы для последующего использования , то, скорее всего, вы получите только смещения ELF, распечатанные с помощью backtrace_syms (), и никаких имен символов (так что не вполне справедливо в исходном вопросе): в этом случае использование gdb возможно более удобно, чем использование других инструментов командной строки. Предполагая, что вы сделали это, вам нужно будет вызвать gdb следующим образом (например):

$ gdb -s debug/libtst.debug -e libtst.so

А затем выполните последовательность действий, аналогичную приведенной выше, используя «информационную строку» и «информационный адрес» в зависимости от того, есть ли у вас только смещения символов ELF или имена символов плюс смещения.

6 голосов
/ 26 сентября 2011
objdump -x --disassemble -l <objfile>

Это должно вывести, помимо прочего, каждую скомпилированную инструкцию машинного кода со строкой файла C, из которой она получена.

4 голосов
/ 19 октября 2016

Во время выполнения с eu-addr2line (автоматически находит библиотеки и рассчитывает смещения):

//-------------------------------------
#include <sys/types.h>
#include <unistd.h>

int i;
#define SIZE 100
void *buffer[100];

int nptrs = backtrace(buffer, SIZE);

for (i = 1; i < nptrs; ++i) {
    char syscom[1024];
    syscom[0] = '\0';
    snprintf(syscom, 1024, "eu-addr2line '%p' --pid=%d > /dev/stderr\n", buffer[i], getpid());
    if (system(syscom) != 0)
        fprintf(stderr, "eu-addr2line failed\n");
}

Выберите вариант --debuginfo-path=..., если ваши файлы отладки находятся где-то еще (в соответствии с идентификатором сборки и т. Д.).

eu-addr2line находится в пакете elfutils вашего дистрибутива.

...