如何将函数地址映射到* .so文件中

backtrace函数给出一组回溯如何用函数名/文件名/行号映射它?

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; } 

如果需要更多信息,请告诉我……

尝试为addr2line提供偏移量以及节名称。 像这样:

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

编辑:顺便说一句,如果不清楚, 0x26887来自你提供的:

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

我已经看过glibc源代码中的文件backtrace.cbacktracesyms.c文件(git://sourceware.org/git/glibc.git,commit 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  and ends at 0x769 . # (Faked output) 

此外, 如果你已经剥离了库,但是隐藏了调试符号以供以后使用 ,那么你可能只会通过backtrace_syms()打印掉ELF偏移量并且没有符号名称(原始问题中的情况并非如此):在这种情况下,使用gdb可以说比使用其他命令行工具更方便。 假设你已经完成了这个,你需要像这样调用gdb(例如):

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

然后使用’info line’和’info address’进行上述类似的序列,具体取决于您是否只有ELF符号偏移,或符号名称加偏移。

 objdump -x --disassemble -l  

除其他外,这应该转储机器代码的每个编译指令以及它来自的C文件行。

在运行时使用eu-addr2line (自动查找库并计算偏移量):

 //------------------------------------- #include  #include  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"); } 

如果您的调试文件位于其他位置(由build-id匹配,请粘贴--debuginfo-path=...选项)。

eu-addr2line位于您的发行版的elfutils包中。