J'essaie d'utiliser la commande addr2line sous Unix mais à chaque fois, elle donne la même sortie que ??: 0. Je donne le commandement en tant que addr2line -e a.out 0x4005BDC
. J'ai obtenu cette adresse lors de l'exécution de cet exécutable a.out avec l'outil valgrind
pour trouver la fuite de mémoire. J'ai également compilé le code source avec -g
option.
Vous pouvez également utiliser gdb au lieu de addr2line pour examiner l'adresse mémoire. Chargez le fichier exécutable dans gdb et imprimez le nom d'un symbole qui est stocké à l'adresse. 16 Examen de la table des symboles .
(gdb) info symbol 0x4005BDC
Vérifiez s'il vous plaît:
-g
, addr2line
Seules les fonctions de support ont des informations de débogage, qui sont compilées avec -g
.text
. Dans la section .text
Signifie que l'adresse doit pointer vers une instruction dans le binaireVoici le message de man addr2line
.
addr2line - convertit les adresses en noms de fichiers et numéros de ligne.
addresses
doit être l'adresse dans un exécutable ou un décalage dans une section d'un objet déplaçable.
La sortie est quelque chose comme FILENAME:LINENO
, Le nom du fichier source et le numéro de ligne dans le fichier
Prenons l'exemple de helloworld
.
#include <stdio.h>
int main()
{
printf("hello\n");
return 0;
}
Après l'avoir compilé avec gcc -g hello.c
, Nous pourrions d'abord utiliser objdump
pour avoir une idée des informations de décalage dans le fichier a.out
Généré.
Ce qui suit fait partie du démontage sous-évalué:
Disassembly of section .text:
0000000000400440 <_start>:
400440: 31 ed xor %ebp,%ebp
400442: 49 89 d1 mov %rdx,%r9
400445: 5e pop %rsi
400446: 48 89 e2 mov %rsp,%rdx
400449: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
40044d: 50 Push %rax
40044e: 54 Push %rsp
40044f: 49 c7 c0 c0 05 40 00 mov $0x4005c0,%r8
400456: 48 c7 c1 50 05 40 00 mov $0x400550,%rcx
40045d: 48 c7 c7 36 05 40 00 mov $0x400536,%rdi
400464: e8 b7 ff ff ff callq 400420 <__libc_start_main@plt>
400469: f4 hlt
40046a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
...
0000000000400536 <main>:
#include <stdio.h>
int main()
{
400536: 55 Push %rbp
400537: 48 89 e5 mov %rsp,%rbp
printf("hello\n");
40053a: bf d4 05 40 00 mov $0x4005d4,%edi
40053f: e8 cc fe ff ff callq 400410 <puts@plt>
return 0;
400544: b8 00 00 00 00 mov $0x0,%eax
}
400549: 5d pop %rbp
40054a: c3 retq
40054b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
La colonne la plus à gauche du code est l'offset dans le fichier binaire. La fonction __start
Provient de la bibliothèque C standard et est précompilée sans informations de débogage. La fonction main
provient de notre code helloworld qui contient des informations de débogage puisque nous compilons le fichier avec -g
.
Voici la sortie de addr2line
:
$ addr2line -e a.out 0x400442 #offset in the `__start` function
??:?
$ addr2line -e a.out 0x400536 #offset in the `main` function
hello.c:21
$ addr2line -e a.out 0x40054b -f #The last instruction of the `main` function
main
??:?
Nous pourrions tirer quelques conclusions de la sortie ci-dessus:
-g
(Ce qui signifie que le segment contient des informations de débogage) peut générer avec succès des informations sur le nom de fichier et le numéro de ligne.-g
Ne sortiront pas correctement le nom de fichier et le numéro de lin. Le décalage 0x40054b
Est la dernière instruction après l'instruction ret
de la fonction main
, mais nous n'avons pas pu obtenir les informations.Vous devez spécifier un offset pour addr2line, pas une adresse virtuelle (VA). Vraisemblablement, si la randomisation de l'espace d'adressage était désactivée, vous pourriez utiliser un VA complet, mais dans la plupart des systèmes d'exploitation modernes, les espaces d'adressage sont randomisés pour un nouveau processus.
Étant donné le VA 0x4005BDC
par valgrind, trouvez l'adresse de base de votre processus ou bibliothèque en mémoire. Pour ce faire, examinez le /proc/<PID>/maps
fichier pendant l'exécution de votre programme. La ligne d'intérêt est le segment text
de votre processus, qui est identifiable par les autorisations r-xp
et le nom de votre programme ou bibliothèque.
Disons que la base VA est 0x0x4005000
. Ensuite, vous trouverez la différence entre le valgrind fourni VA et le VA de base: 0xbdc
. Ensuite, fournissez cela à add2line:
addr2line -e a.out -j .text 0xbdc
Et voyez si cela vous donne votre numéro de ligne.
C'est exactement comme ça que vous l'utilisez. Il est possible que l'adresse que vous avez ne corresponde pas à quelque chose directement dans votre code source.
Par exemple:
$ cat t.c
#include <stdio.h>
int main()
{
printf("hello\n");
return 0;
}
$ gcc -g t.c
$ addr2line -e a.out 0x400534
/tmp/t.c:3
$ addr2line -e a.out 0x400550
??:0
0x400534
est l'adresse de main
dans mon cas. 0x400408
est également une adresse de fonction valide dans a.out
, mais c'est un morceau de code généré/importé par GCC, qui n'a pas d'informations de débogage. (Dans ce cas, __libc_csu_init
. Vous pouvez voir la disposition de votre exécutable avec readelf -a your_exe
.)
Autres fois où addr2line
échouera si vous incluez une bibliothèque sans informations de débogage.
Essayez d'ajouter le -f
option pour afficher les noms des fonctions:
addr2line -f -e a.out 0x4005BDC