gcc -g : was passieren wird

Lesezeit: 8 Minuten

Vijays Benutzeravatar
Vijay

Diese Frage wurde mir in einem Interview gestellt.

Sie haben mich gefragt, wie man eine Core-Dump-Datei generiert, mit der ich debuggen kann. dann sagte ich das mit -g Flagge ein gcc Wir können es schaffen.

dann haben sie mich gefragt was genau das macht -g flag do an den Compiler.

Ich sagte (wahrscheinlich eine falsche Antwort), dass es alle Symbole in der Kerndatei öffnen wird, die zum Debuggen verwendet werden können.

kann mir jemand sagen was das genau macht?

  • Es ist wahrscheinlich erwähnenswert, dass Sie, wenn Sie einen Core-Dump eines Prozesses generieren möchten, dessen PID an den gcore-Befehl übergeben können.

    – atx

    11. März 2011 um 11:23 Uhr

Benutzeravatar von Tony Delroy
Toni Delroy

Das ist irgendwie richtig, aber unvollständig. -g fordert an, dass der Compiler und der Linker Debugging-/Symbolinformationen auf Quellebene in der ausführbaren Datei selbst generieren und beibehalten.

Wenn

  • Das Programm stürzt später ab und erzeugt eine Kerndatei (was auf ein Problem im tatsächlichen Code hindeutet), oder
  • ein absichtlicher OS-Befehl zwang es zum Core (zB kill -SIGQUIT PID), oder
  • Das Programm ruft eine Funktion auf, die den Kern ausgibt (z abort)

…- von denen keiner tatsächlich durch die Verwendung von verursacht wird -g – dann weiß der Debugger, wie das zu lesen ist “-g” Symbolinformationen aus der ausführbaren Datei und verweisen sie mit dem Kern. Das bedeutet, dass Sie die richtigen Namen von Variablen und Funktionen in Ihren Stack-Frames sehen, Zeilennummern erhalten und die Quelle sehen können, während Sie in der ausführbaren Datei herumgehen.

Diese Debug-Informationen sind beim Debuggen nützlich – unabhängig davon, ob Sie mit einem Kern oder nur der ausführbaren Datei allein begonnen haben. Es hilft sogar, eine bessere Ausgabe von Befehlen wie zu erzeugen pstack.

Beachten Sie, dass Ihre Umgebung möglicherweise andere Einstellungen hat, um zu steuern, ob Kerne generiert werden (sie können groß sein, und es gibt keine allgemeine Möglichkeit zu wissen, ob/wann sie entfernt werden können, daher sind sie nicht immer erwünscht). Auf UNIX/LINUX-Shells ist dies beispielsweise häufig der Fall ulimit -c.

Vielleicht interessiert es Sie auch, darüber zu lesen ZWERG Wikipedia – ein häufig verwendetes Debugging-Informationsformat zum Codieren der eingebetteten Debug-/Symbolinformationen in ausführbaren/Bibliotheksobjekten (z. B. unter UNIX und Linux).

UPDATE auf Anfrage von Victor in den Kommentaren …

Symbolinformationen listet Bezeichner aus dem Quellcode auf (normalerweise erst nach any Namensverstümmelung benötigt), die (virtuellen) Speicheradressen/Offsets, an denen sie in den Prozessspeicher geladen werden, den Typ (z. B. Daten vs. Code). Zum Beispiel…

$ 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

Anmerkungen:

  • unsere Funktionen f() und main() Typ sind T (was für “TEXT” steht – wird für schreibgeschützten Speicherinhalt ungleich Null verwendet, unabhängig davon, ob es sich tatsächlich um Text oder andere Daten oder ausführbaren Code handelt),
  • g_my_num ist B ein globaler mit implizit auf Null gesetztem Speicher zu sein, während
  • NS::ns_my_num ist D da die ausführbare Datei den Wert explizit bereitstellen muss 2 diese Erinnerung zu besetzen.

Das Man/Info-Seite für nm dokumentiert diese Dinge weiter ….

  • Beachten Sie das strip Dienstprogramm führt die umgekehrte Operation durch, dh es nimmt eine Bibliothek mit Debugging-Symbolen und entfernt sie.

    – Matthias M.

    3. März 2011 um 10:34 Uhr

  • Was sind Symbolinformationen? Können Sie diese Antwort bitte etwas mehr ELIF für mich machen?

    – Viktor Lin

    2. März 2016 um 5:08 Uhr

  • @TonyD Tut mir leid. Es steht für Erklären, als wäre ich fünf. Ich habe noch keinen Compiler-Kurs besucht, also habe ich dieses Vokabular nicht.

    – Viktor Lin

    2. März 2016 um 21:02 Uhr

  • @VictorLin: Hier ist viel zu viel beteiligt, um es auf dieser Ebene zu erklären – es würde schnell in Erklärungen von Adressen vs. Offsets, “virtuellem” Speicher, Betriebssystemladern usw. explodieren, aber ich habe einige grundlegende Details und ein Beispiel gegeben – ich hoffe es hilft.

    – Toni Delroy

    3. März 2016 um 3:15 Uhr

Das Flag -g weist den Compiler an, Debugging-Informationen zu generieren. Es hat keinen Einfluss darauf, ob eine Kerndatei generiert wird oder nicht. Auf den meisten Unix-ähnlichen Systemen kann dies mit dem Befehl ulimit eingerichtet werden.

  • Aber ich möchte wissen, was genau diese Debugging-Informationen sind. Ich weiß, was Sie bereits wissen. Ich brauchte etwas, das darüber hinausgeht.

    – Vijay

    3. März 2011 um 10:09 Uhr

  • @wvwvwv Darüber hinaus ist es kompliziert – eine gründliche Beschreibung dauert ein paar Dutzend Seiten. Sie könnten damit beginnen, sich den DWARF (dwarfstd.org/Download.php)-Standard, der die Spezifikation für die Debugging-Symbole darstellt, die in die ausführbare Datei eingebettet sind (auf den meisten *nixes). -g weist den Compiler/Linker an, diese Strukturen zu generieren und in die ausführbare Datei einzubetten. Der nächste Schritt besteht wahrscheinlich darin, zu verstehen, wie ein Debugger diese Debugging-Informationen verwendet.

    – Nr

    3. März 2011 um 10:15 Uhr


  • Kurz gesagt, es fügt Informationen über Symbolnamen (Funktionen, lokale und globale Variablen usw.) sowie Informationen über Typen, Quelldateinamen und Zeilennummern hinzu. Es könnte auch über ein automatisch definiertes Makro verschiedene Header-Dateien (z. B. für STL und die Definition des Assert-Makros) abrufen, die das Debuggen erleichtern. Es wird wahrscheinlich auch eine spezielle Ausgabe für eingebettete Funktionen erzeugen, so dass das Einsteigen in eingebettete Funktionen/Methoden möglich ist.

    – Axel

    3. März 2011 um 10:23 Uhr

Das Flag gcc -g weist gcc an, Debug-Informationen zu generieren und einzubetten. ulimit -c wird verwendet, um die Kerndateigenerierung zu aktivieren. Sie können eines davon ohne das andere haben.

-g fügt Debugging-Informationen (Variablennamen, Zeilennummern usw.) zur ausführbaren Datei hinzu. Es ist Teil dessen, was Sie tun müssen, um die Kerndatei zu verstehen.

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

Benutzeravatar von Steven Wong
Steven Wong

Wenn Sie das Flag -g nicht setzen, kann list in gdb nicht aufgerufen werden, um aufzulisten, wie der Quellcode aussieht. Es wird angezeigt “Keine Symboltabelle geladen. Verwenden Sie den Befehl “Datei”.

Auch wenn Sie info func oder info frame, info locals in gdb, ohne -g eingeben, werden der Rückgabedatentyp und seine Argumente nicht angezeigt, im Grunde keine Übersetzung der Anweisung in eine Variable (Zuordnung aus der Symboltabelle).

Benutzeravatar von vpit3833
vpit3833

Kerndatei wird bei Segmentierungsfehlern oder solchen Ausnahmen generiert. gdb source.cc core ist eine Möglichkeit, in die Kerndatei zu schauen. Das Zurückverfolgen und Untersuchen jedes Frames ist ein Anfang, um in den Kern zu schauen. -g fügt Debugging-Symbole in die Binärdatei ein.

Benutzeravatar von pepero
Pepero

Core Dump ist eine der Standardaktionen eines Prozesses, wenn dieser die Signale empfängt, zB in den Standardsignalen “SIGQUIT”, “SIGILL”, “SIGABRT”, “SIGFPE”, “SIGSEGV”. Die meisten Shells unterdrücken jedoch die Erstellung von Core-Dateien, einfach weil die Core-Dateien in der Regel groß sind und dies einige Zeit oder viel Zeit in Anspruch nehmen kann.

Um die Core-Generierung zu aktivieren, ist “ulimit” das Dienstprogramm, mit dem Sie die Dateigrenze der Shell oder ihrer untergeordneten Prozesse festlegen können.

Compiler-Flags “-g” oder was auch immer betreffen nur den Compiler. Mit Core Dump hat das logischerweise nichts zu tun.

1412860cookie-checkgcc -g : was passieren wird

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy