2011-09-26 6 views
27

función de traza inversa ¿cómo se asigna el nombre de la función/el nombre del archivo/número de línea?Cómo mapear la dirección de la función para que funcione en los archivos * .so

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] 

De la pila anterior ¿cómo puedo obtener el nombre del archivo y el número de línea? Hice cosas, pero no tuve suerte. corrígeme si estoy equivocado :)

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 

Entonces, ¿cómo puedo resolver, ya sea en tiempo de ejecución o después de tiempo de ejecución? Gracias de antemano ...

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 [email protected]@GLIBC_2.1 
    U [email protected]@GLIBC_2.1 
    U [email protected]@GLIBC_2.0 
    U [email protected]@GLIBC_2.7 
    U [email protected]@GLIBC_2.0 
    U [email protected]@GLIBC_2.0 
    U [email protected]@GLIBC_2.0 
    w [email protected]@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-grabable privada, 1560K-privada de sólo lectura, 0K compartida, y 376K referencia

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

Quiero saber si necesita más información ...

+1

¿Compiló con información de depuración ('-g')? – qrdl

+0

@qrdl sí compilado con (-g) gcc -shared -ldl -fPIC libtst.c -o libtst.so -g – Thangaraj

+0

Luego use 'backtrace_symbols()' para obtener los nombres de las funciones. Para obtener los nombres de las funciones y los números de línea de las direcciones, puede usar información enana: marque la utilidad 'dwarfdump' que viene con' libdwarf'. – qrdl

Respuesta

28

Pruebe a dar el desplazamiento a addr2line, junto con el nombre de la sección. De esta manera:

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

Editar: Por cierto, si no estaba claro, el 0x26887 proviene de lo que ya ha proporcionado:

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

+0

addr2line -j .text -e libtst.so 0x26887 ??: 0 lo siento, no tuvimos suerte. – Thangaraj

+0

¿Estás seguro de que tu dirección base es la correcta? Asegúrese de obtener la dirección base de la sección ejecutable de la biblioteca (marque/proc/pid/maps y encuentre la línea libtst.so con permisos 'r-xp'). –

+0

Gracias, lo obtuve.addr2line -e libtst.so 0x767 /home/test/libtofun/libtst.c:16 – Thangaraj

6
objdump -x --disassemble -l <objfile> 

Esto debería volcar, entre otras cosas, cada instrucción compilada de código de máquina con la línea del archivo C de donde vino.

+0

No lo hice, lo que esto significa. Cuando intento con objdump y nm, la dirección del símbolo es la misma. Más información sería útil. – Thangaraj

+0

Asegúrese de que está compilando su biblioteca con símbolos de depuración. – nmichaels

+0

Sí, he compilado con la opción -g ... – Thangaraj

16

que he tenido un vistazo a los archivos backtrace.c y backtracesyms.c en el código fuente de glibc (git: //sourceware.org/git/glibc.git, commit 2482ae433a4249495859343ae1fba408300f2c2e).

Asumiendo que no he leído mal/mal entendido cosas: backtrace() parece que solo le dará direcciones de símbolos, ya que están en tiempo de ejecución, lo que creo que significa que necesita la dirección de carga de la biblioteca como pmap o similar. Sin embargo, backtrace_symbols() recalcula las cosas para que las direcciones sean relativas a la biblioteca compartida ELF, y no al proceso en tiempo de ejecución, lo cual es realmente conveniente. Significa que no necesita información de pmap.

Por lo tanto, si ha compilado con -g (o con -dinámica), entonces está de suerte. Usted debe ser capaz de hacer lo siguiente:

$ # 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 

O, usando 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) 

Además, if you've stripped the library, but stashed off debug symbols for later use, entonces es probable que sólo tienen compensaciones ELF impresos por backtrace_syms() y ningún símbolo nombres (por lo que no es exactamente el caso en la pregunta original): en este caso, usar gdb es posiblemente más conveniente que usar otras herramientas de línea de comando. Suponiendo que haya hecho esto, tendrá que invocar el BGF como tal (por ejemplo):

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

y luego ir a través de una secuencia similar a la anterior, el uso de 'línea de información' y 'dirección de información' en función de si solo tiene compensaciones de símbolos ELF o nombres de símbolos más compensaciones.

+1

Dado que 'myfunc' es un símbolo válido ya en GDB, puede hacer' info line * (myfunc + 0x2b) '. –

3

En tiempo de ejecución con eu-addr2line (busca automáticamente las bibliotecas y calcula las compensaciones):

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

palillo de una opción --debuginfo-path=... si sus archivos de depuración están en otra parte (comparados por la acumulación de identificación, etc.).

eu-addr2line está en el paquete elfutils de su distribución.

+1

Observe también el icono de "regla horizontal" en la pestaña de edición anterior. Puede separar secciones de una pregunta con eso. Asegúrate de ver el? ayuda en la barra de menú de edición la próxima vez que edite una pregunta o respuesta. Pautas de edición muy útiles que van desde lo simple a lo avanzado. – clearlight

Cuestiones relacionadas