web-dev-qa-db-fra.com

gcc -g: que va-t-il se passer

Cette question m'a été posée lors d'une interview.

ils m'ont demandé comment générer un fichier de vidage principal avec lequel je peux déboguer. alors j'ai dit qu'avec -g flag in gcc on peut le faire.

alors ils m'ont demandé ce que cela fait exactement -g flag faire pour le compilateur.

j'ai dit (probablement une mauvaise réponse) qu'il ouvrira tous les symboles du fichier principal qui peuvent être utilisés pour le débogage.

quelqu'un peut-il me dire ce que ça fait exactement?

41
Vijay

C'est un peu juste, mais incomplet. -g Demande que le compilateur et l'éditeur de liens génèrent et conservent les informations de débogage/symbole au niveau source dans l'exécutable lui-même.

Si ...

  • le programme se bloque plus tard et produit un fichier core (ce qui suggère un problème dans le code réel), ou
  • une commande délibérée du système d'exploitation l'a forcé à noyau (par exemple kill -SIGQUIT pid ), ou
  • le programme appelle une fonction qui vide le noyau (par exemple abort )

...- dont aucun n'est réellement provoqué par l'utilisation de -g - alors le débogueur saura lire les informations de symbole "-g" de l'exécutable et les renvoyer avec le coeur. Cela signifie que vous pouvez voir les noms propres des variables et des fonctions dans vos cadres de pile, obtenir des numéros de ligne et voir la source lorsque vous vous déplacez dans l'exécutable.

Ces informations de débogage sont utiles à chaque débogage - que vous commenciez avec un noyau ou simplement l'exécutable seul. Il aide même à produire une meilleure sortie à partir de commandes telles que pstack .

Notez que votre environnement peut avoir d'autres paramètres pour contrôler si les cœurs sont générés (ils peuvent être gros, et il n'y a aucun moyen général de savoir s'ils/quand ils peuvent être supprimés, ils ne sont donc pas toujours souhaités). Par exemple, sur les shells UNIX/LINUX, c'est souvent ulimit -c .

Vous pouvez également être intéressé par la lecture de NAIN Wikipedia - un format d'informations de débogage couramment utilisé pour coder les informations de débogage/symbole incorporées dans objets exécutables/bibliothèque (par exemple sous UNIX et Linux).

MISE À JOUR selon la demande de Victor dans les commentaires ...

Les informations sur les symboles répertorient les identifiants du code source (généralement seulement après que changement de nom nécessaire), les adresses de mémoire (virtuelles)/les décalages auxquels ils seront chargés dans la mémoire du processus, le type (par exemple, données vs code). Par exemple...

$ cat ok.cc
int g_my_num;
namespace NS { int ns_my_num = 2; }
int f() { return g_my_num + NS::ns_my_num; }
int main() { return f(); }

$ g++ -g ok.cc -o ok    # compile ok executable with symbol info

$ nm ok    # show mangled identifiers
00000000004017c8 d _DYNAMIC
0000000000401960 d _GLOBAL_OFFSET_TABLE_
0000000000400478 R _IO_stdin_used
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 w _Jv_RegisterClasses
000000000040037c T _Z1fv                     # this is f()
0000000000401798 D _ZN2NS9ns_my_numE         # this is NS::ns_my_num
00000000004017a8 d __CTOR_END__
00000000004017a0 d __CTOR_LIST__
00000000004017b8 d __DTOR_END__
00000000004017b0 d __DTOR_LIST__
0000000000400540 r __FRAME_END__
00000000004017c0 d __JCR_END__
00000000004017c0 d __JCR_LIST__
00000000004017c8 d __TMC_END__
00000000004017c8 d __TMC_LIST__
0000000000401980 A __bss_start
0000000000401788 D __data_start
0000000000400440 t __do_global_ctors_aux
00000000004002e0 t __do_global_dtors_aux
0000000000401790 d __dso_handle
0000000000000000 a __fini_array_end
0000000000000000 a __fini_array_start
                 w __gmon_start__
0000000000000000 a __init_array_end
0000000000000000 a __init_array_start
00000000004003a0 T __libc_csu_fini
00000000004003b0 T __libc_csu_init
                 U __libc_start_main
0000000000000000 a __preinit_array_end
0000000000000000 a __preinit_array_start
0000000000401980 A _edata
0000000000401994 A _end
0000000000400494 T _fini
000000000040047c T _init
0000000000400220 T _start
000000000040024c t call_gmon_start
0000000000401980 b completed.6118
0000000000401788 W data_start
0000000000400270 t deregister_tm_clones
0000000000401988 b dtor_idx.6120
0000000000401994 A end
0000000000400350 t frame_dummy
0000000000401990 B g_my_num                   # our global g_my_num
0000000000400390 T main                       # the int main() function
00000000004002a0 t register_tm_clones

$ nm ok | c++filt            # c++filt "unmangles" identifiers...
00000000004017c8 d _DYNAMIC
0000000000401960 d _GLOBAL_OFFSET_TABLE_
0000000000400478 R _IO_stdin_used
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 w _Jv_RegisterClasses
000000000040037c T f()
0000000000401798 D NS::ns_my_num
00000000004017a8 d __CTOR_END__
00000000004017a0 d __CTOR_LIST__
00000000004017b8 d __DTOR_END__
00000000004017b0 d __DTOR_LIST__
0000000000400540 r __FRAME_END__
00000000004017c0 d __JCR_END__
00000000004017c0 d __JCR_LIST__
00000000004017c8 d __TMC_END__
00000000004017c8 d __TMC_LIST__
0000000000401980 A __bss_start
0000000000401788 D __data_start
0000000000400440 t __do_global_ctors_aux
00000000004002e0 t __do_global_dtors_aux
0000000000401790 d __dso_handle
0000000000000000 a __fini_array_end
0000000000000000 a __fini_array_start
                 w __gmon_start__
0000000000000000 a __init_array_end
0000000000000000 a __init_array_start
00000000004003a0 T __libc_csu_fini
00000000004003b0 T __libc_csu_init
                 U __libc_start_main
0000000000000000 a __preinit_array_end
0000000000000000 a __preinit_array_start
0000000000401980 A _edata
0000000000401994 A _end
0000000000400494 T _fini
000000000040047c T _init
0000000000400220 T _start
000000000040024c t call_gmon_start
0000000000401980 b completed.6118
0000000000401788 W data_start
0000000000400270 t deregister_tm_clones
0000000000401988 b dtor_idx.6120
0000000000401994 A end
0000000000400350 t frame_dummy
0000000000401990 B g_my_num
0000000000400390 T main
00000000004002a0 t register_tm_clones

Remarques:

  • nos fonctions f() et main() sont de type T (qui signifie "TEXT" - utilisé pour le contenu mémoire non nul en lecture seule, qu'il s'agisse en fait de texte ou d'autres données ou code exécutable),
  • g_my_num Est B étant un global avec une mémoire implicitement mise à zéro, tandis que
  • NS::ns_my_num Est D car l'exécutable doit fournir explicitement la valeur 2 Pour occuper cette mémoire.

La man/info-page pour nm documente ces choses plus loin ....

50
Tony Delroy

L'indicateur -g indique au compilateur de générer des informations de débogage. Il n'a aucun impact sur la génération ou non d'un fichier core. Sur la plupart des systèmes de type Unix, cela peut être configuré à l'aide de la commande ulimit.

9
Axel

L'indicateur gcc -g indique à gcc de générer et d'incorporer des informations de débogage. ulimit -c est utilisé pour activer la génération du fichier principal. Vous pouvez avoir l'un ou l'autre sans l'autre.

5
Erik

-g ajoute des informations de débogage (noms de variables, numéros de ligne, etc.) au fichier exécutable. Cela fait partie de ce que vous devez faire pour pouvoir comprendre le fichier principal.

http://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html#Debugging-Options

3
JeremyP

Si vous ne mettez pas -g, ne pouvez pas appeler list dans gdb pour lister à quoi ressemble le code source. il affichera "Aucune table de symboles n'est chargée. Utilisez la commande" file "."

De plus, si vous tapez info func ou info frame, info localals dans gdb, sans -g, il ne montrera pas le type de données de retour et ses arguments, essentiellement aucune traduction de l'instruction en variable (mappage à partir de la table des symboles).

1
Steven Wong

le vidage de mémoire est l'une des actions par défaut d'un processus, lorsque ce processus reçoit les signaux, par ex. dans les signaux standard "SIGQUIT", "SIGILL", "SIGABRT", "SIGFPE", "SIGSEGV". Cependant, la plupart des shells suppriment la création du fichier core, simplement parce que les fichiers core ont tendance à être volumineux et cela peut prendre un certain temps ou beaucoup de temps.

afin d'activer la génération principale, "ulimit" est l'utilitaire que vous pouvez utiliser pour définir la limite de fichiers du shell ou de son processus enfant.

drapeaux du compilateur "-g" ou tout ce qui ne concerne que le compilateur. logiquement, cela n'a rien à voir avec le vidage de mémoire.

1
pepero

le fichier principal est généré lors d'une erreur de segmentation ou de telles exceptions. gdb source.cc core est une façon d'examiner le fichier principal. Retracer et étudier chaque image est un début pour explorer le cœur. -g ajoute des symboles de débogage dans le binaire.

1
vpit3833