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