web-dev-qa-db-fra.com

Comment mapper l'adresse d'une fonction pour qu'elle fonctionne dans des fichiers * .so

la fonction backtrace donne un ensemble de backtrace comment le mapper avec le nom de la fonction/le nom du fichier/le numéro de ligne?

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]

À partir de la pile ci-dessus, comment puis-je obtenir le nom de fichier et le numéro de ligne? J'ai fait les choses suivantes, mais pas de chance. Corrigez-moi si je me trompe :)

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

Alors, comment puis-je résoudre le problème lors de l'exécution ou après l'exécution? Merci d'avance...

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

128 Ko en écriture privée, 1560 Ko en lecture seule, 0 Ko partagé et 376 Ko référencés

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

Faites-moi savoir si vous avez besoin de plus d'informations ...

35
Thangaraj

Essayez de donner le décalage à addr2line, ainsi que le nom de la section. Comme ça:

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

Edit: Au fait, si ce n'était pas clair, le 0x26887 Vient de ce que vous avez fourni:

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

33
tdenniston

J'ai jeté un œil aux fichiers backtrace.c et backtracesyms.c fichiers dans le code source de la glibc (git: //sourceware.org/git/glibc.git, commit 2482ae433a4249495859343ae1fba408300f2c2e).

En supposant que je n'ai pas mal lu/mal compris: backtrace () lui-même semble ne vous donner que des adresses de symboles telles qu'elles sont à l'exécution, ce qui signifie que vous avez besoin de l'adresse de chargement de la bibliothèque telle qu'elle était pmap ou similaire. Cependant, backtrace_symbols () recalcule les choses afin que les adresses soient relatives à la bibliothèque partagée ELF, et non au processus à l'exécution, ce qui est vraiment pratique. Cela signifie que vous n'avez pas besoin d'informations de pmap.

Donc, si vous avez compilé avec -g (ou avec -rdynamic), alors vous avez de la chance. Vous devriez pouvoir effectuer les opérations suivantes:

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

Ou, en utilisant 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)

En outre, si vous avez supprimé la bibliothèque, mais caché les symboles de débogage pour une utilisation ultérieure , vous n'aurez probablement que des décalages ELF imprimés par backtrace_symiques () et aucun nom de symbole (donc pas tout à fait le cas dans la question d'origine): Dans ce cas, l'utilisation de gdb est sans doute plus pratique que l'utilisation d'autres outils de ligne de commande. En supposant que vous ayez fait cela, vous devrez invoquer gdb comme ceci (par exemple):

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

Ensuite, suivez une séquence similaire à celle ci-dessus, en utilisant "ligne info" et "adresse info" selon que vous n'avez que des décalages de symboles ELF, ou des noms de symboles plus des décalages.

20
Rob
objdump -x --disassemble -l <objfile>

Cela devrait vider, entre autres, chaque instruction compilée du code machine avec la ligne du fichier C dont il est issu.

6
nmichaels

Au moment de l'exécution avec eu-addr2line (recherche automatiquement les bibliothèques et calcule les décalages):

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

Collez un --debuginfo-path=... option si vos fichiers de débogage sont ailleurs (correspondant à l'ID de build, etc.).

eu-addr2line est dans le package elfutils de votre distribution.

4
Velkan