Pourquoi GDB a-t-il besoin de l'exécutable ainsi que du vidage de mémoire?


11

Je débogue en utilisant des vidages mémoire, et notez que gdb a besoin de vous pour fournir l'exécutable ainsi que le vidage mémoire. Pourquoi est-ce? Si le vidage de mémoire contient toute la mémoire utilisée par le processus, l'exécutable n'est-il pas contenu dans le vidage de mémoire? Peut-être n'y a-t-il aucune garantie que l'intégralité de l'exe est chargée en mémoire (les exécutables individuels ne sont généralement pas si gros cependant) ou peut-être que le vidage de mémoire ne contient pas toute la mémoire pertinente après tout? Est-ce pour les symboles (peut-être qu'ils ne sont pas chargés normalement en mémoire)?


1
L'exécutable contient les informations sur les symboles, comme indiqué dans la documentation gdb ...
Thomas Dickey

1
Étonnamment, aucune réponse (sauf celle que je viens d'ajouter) ne mentionne le format DWARF
Basile Starynkevitch

Réponses:


15

Le vidage de mémoire n'est que le vidage de l'empreinte mémoire de vos programmes, si vous savez où tout était, vous pouvez simplement l'utiliser.

Vous utilisez l'exécutable car il explique où (en termes d'adresses logiques) les choses se trouvent dans la mémoire, c'est-à-dire le fichier principal.

Si vous utilisez une commande, objdumpelle videra les métadonnées sur l'objet exécutable que vous étudiez. Utilisation d'un objet exécutable nommé a.out comme exemple.

objdump -h a.outvide les informations d'en-tête uniquement, vous verrez des sections nommées par exemple. .data ou .bss ou .text (il y en a beaucoup plus). Ceux-ci informent le chargeur du noyau où dans l'objet diverses sections peuvent être trouvées et où dans l'espace d'adressage du processus la section doit être chargée, et pour certaines sections (par exemple .data .text) ce qui doit être chargé. (La section .bss ne contient aucune donnée dans le fichier mais elle fait référence à la quantité de mémoire à réserver dans le processus pour les données non initialisées, elle est remplie de zéros).

La disposition du fichier objet exécutable est conforme à un ELF standard.

objdump -x a.out - décharge tout

Si l'objet exécutable contient toujours ses tables de symboles (il n'a pas été supprimé - man stripet vous avez utilisé -gpour générer une génération de débogage en gcc supposant une compilation de source CA), alors vous pouvez examiner le contenu principal par des noms de symboles, par exemple si vous aviez une variable / tampon nommé inputLine dans votre code source, vous pouvez utiliser ce nom gdbpour consulter son contenu. c.-à gdb-d. connaîtrait l'offset depuis le début du segment de données initialisé de votre programme où commence InputLine et la longueur de cette variable.

Pour en savoir plus sur l' article 1 , l' article 2 , et pour la spécification Nitty Gritty Executable and Linking Format (ELF) .


Mettre à jour après le commentaire @mirabilos ci-dessous.

Mais si vous utilisez la table des symboles comme dans

$ gdb --batch -s a.out -c core -q -ex "x buf1"

Produit

 0x601060 <buf1>:    0x72617453

puis ne pas utiliser la table des symboles et examiner l'adresse directement dans,

$ gdb --batch -c core -q -ex "x 0x601060"

Produit

0x601060:   0x72617453

J'ai examiné la mémoire directement sans utiliser la table des symboles dans la 2e commande.


Je vois également que la réponse de @ user580082 ajoute des explications et fera un vote positif.


6
Jamais entendu parler de "section de pile de base". .bss est (historiquement) "bloc démarré par symbole" et pratiquement "données unitarisées", tandis que .data est "données initialisées" et du texte (pas .code) est utilisé pour stocker le code machine. Il n'y a pas de section de pile dans un binaire, car les piles sont créées au moment de l'exécution.
jlliagre

«Si vous savez où tout était, alors vous pouvez simplement l'utiliser» n'est pas vrai non plus parce que tout dans le programme n'est pas nécessairement inclus dans l'empreinte.
mirabilos

1
@jlliagre vous avez raison, j'ai appelé par erreur .text .code (parce que je pensais à une explication lors de la composition de la réponse) - mis à jour. J'ai pensé à tort à bss de manière incorrecte par son nom et j'ai mis à jour ma réponse, mais j'ai évité * Bloquer démarré par symbole car je ne pense pas que cela ajoute vraiment à l'équation, et j'ai expliqué qu'il est utilisé comme des données non initialisées, ce qui était notre compréhension commune. Merci - j'ai apprécié votre commentaire pour corriger cette annonce.
X Tian

4

Le fichier principal est un instantané de l'image de la pile, des mappages de la mémoire et des registres au moment de l'arrêt du processus. Dont le contenu peut être manipulé comme indiqué dans la page de manuel principale . Par défaut, les mappages privés, les mappages partagés et les informations d'en-tête ELF sont vidés dans le fichier principal.

En venant à votre question , la raison pour laquelle gdb nécessite un exécutable est parce qu'il ne simule pas l'exécution, en lisant et en interprétant les instructions binaires comme valgrind le fait à la place, il devient le parent du processus afin de contrôler le comportement du processus pendant l'exécution temps. Il utilise le fichier principal pour déterminer les mappages de mémoire et l'état du processeur du processus lors d'un crash.

Sous Linux, les processus parents peuvent obtenir des informations supplémentaires sur leurs enfants, en particulier la possibilité de les retracer, ce qui permet au débogueur d'accéder aux informations de bas niveau du processus comme lire / écrire sa mémoire, les registres, modifier les mappages de signaux, arrêter son exécution, etc.

Vous comprendrez l'exigence d'un exécutable malgré le fait d'avoir un fichier core plus une fois que vous aurez lu comment fonctionne un débogueur.


1

(en plus d'autres bonnes réponses)

Sur les systèmes Linux modernes (et de nombreux systèmes similaires à Unix), les informations de débogage (y compris les métadonnées sur les types de symboles, l'emplacement du code source, le type de variables, etc., etc.) sont au format DWARF et se trouvent à l'intérieur de l' exécutable ELF ( ou bibliothèques partagées ELF) lorsqu'il est compilé avec une -goption. Je recommande de compiler les programmes à déboguer avec -g3 -O0et peut -fno-inline- être si vous utilisez un GCC récent ; cependant, avec GCC, vous pouvez même compiler avec à la fois des informations d'optimisation et de débogage, par exemple avec -O2 -g1, bien que les informations de débogage puissent dans ce cas être un peu "floues" (cela pourrait légèrement aider à attraper quelques coquins Heisenbugs ).

Il est assez judicieux d'éviter de mettre ces informations dans les fichiers core , car vous pourriez avoir de nombreux fichiers core différents (imaginez un logiciel largement utilisé avec de nombreux utilisateurs faisant des rapports de bogues, la plupart avec un corevidage) pour le même exécutable. Les fichiers core (5) sont également vidés par le noyau, qui ne devrait pas se soucier de l'existence de sections DWARF dans les exécutables elf (5) (car ces sections ne sont pas mappées dans l' espace d'adressage virtuel du processus défaillant qui a vidé le noyau sur un signal ( 7) ). Il est même possible de placer les informations de débogage dans des fichiers séparés (en dehors de l'exécutable).

BTW, GDB peut être douloureusement utilisé pour déboguer les vidages de mémoire pour les exécutables sans aucune information de débogage. Mais ensuite, vous déboguez pratiquement au niveau du code machine (pas au niveau symbolique fourni par les langages de programmation et leurs compilateurs).

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.