Ich debugge mit Core-Dumps und stelle fest, dass gdb Sie benötigt, um sowohl die ausführbare Datei als auch den Core-Dump bereitzustellen. Warum ist das? Wenn der Core-Dump den gesamten vom Prozess verwendeten Speicher enthält, ist die ausführbare Datei dann nicht im Core-Dump enthalten? Vielleicht gibt es keine Garantie dafür, dass die gesamte Exe in den Speicher geladen wird (einzelne ausführbare Dateien sind normalerweise nicht so groß), oder vielleicht enthält der Core-Dump doch nicht den gesamten relevanten Speicher? Ist es für die Symbole (vielleicht werden sie normalerweise nicht in den Speicher geladen)?
11
Antworten:
Der Core-Dump ist nur der Dump des Speicherbedarfs Ihres Programms. Wenn Sie wissen, wo sich alles befindet, können Sie ihn einfach verwenden.
Sie verwenden die ausführbare Datei, weil sie erklärt, wo sich (in Bezug auf logische Adressen) Dinge im Speicher befinden, dh in der Kerndatei.
Wenn Sie einen Befehl verwenden
objdump
, werden die Metadaten des ausführbaren Objekts, das Sie untersuchen, ausgegeben. Verwenden Sie als Beispiel ein ausführbares Objekt mit dem Namen a.out.objdump -h a.out
Gibt nur die Header-Informationen aus. Es werden Abschnitte mit dem Namen z. .data oder .bss oder .text (es gibt noch viel mehr). Diese informieren den Kernel-Loader darüber, wo im Objekt verschiedene Abschnitte zu finden sind und wo im Prozessadressraum der Abschnitt geladen werden soll und für einige Abschnitte (z. B. .data .text), was geladen werden soll. (Der Abschnitt .bss enthält keine Daten in der Datei, bezieht sich jedoch auf die Speichermenge, die im Prozess für nicht initialisierte Daten reserviert werden muss. Er ist mit Nullen gefüllt.)Das Layout der ausführbaren Objektdatei entspricht einem Standard-ELF.
objdump -x a.out
- wirft alles wegWenn das ausführbare Objekt noch seine Symboltabellen enthält (es wurde nicht entfernt -
man strip
und Sie haben-g
die Debug-Generierung generiert, um diegcc
Kompilierung der Wechselstromquelle anzunehmen), können Sie den Kerninhalt anhand von Symbolnamen untersuchen, z. B. wenn Sie eine Variable / einen Puffer hatten Mit dem Namen inputLine in Ihrem Quellcode können Sie diesen Namen verwendengdb
, um den Inhalt anzuzeigen . Das heißtgdb
, Sie kennen den Versatz vom Beginn Ihres vom Programm initialisierten Datensegments, in dem inputLine beginnt, und die Länge dieser Variablen.Lesen Sie weiter Artikel 1 , Artikel 2 und die ELF-Spezifikation (Executable and Linking Format) .
Update nach @mirabilos Kommentar unten.
Aber wenn Sie die Symboltabelle wie in verwenden
Produziert
und dann nicht die Symboltabelle verwenden und die Adresse direkt in untersuchen,
Produziert
Ich habe den Speicher direkt untersucht, ohne die Symboltabelle im 2. Befehl zu verwenden.
Ich sehe auch, dass die Antwort von @ user580082 die Erklärung weiter erweitert und die Abstimmung verbessern wird.
quelle
Die Kerndatei ist eine Momentaufnahme des Stapelabbilds, der Speicherzuordnungen und der Register zum Zeitpunkt der Prozessbeendigung. Der Inhalt kann wie in der Kernmanpage angegeben bearbeitet werden . Standardmäßig werden private Zuordnungen, freigegebene Zuordnungen und ELF-Headerinformationen in die Kerndatei kopiert.
Wenn Sie zu Ihrer Frage kommen , ist der Grund, warum gdb eine ausführbare Datei benötigt, der, dass die Ausführung nicht simuliert wird, indem die binären Anweisungen wie valgrind gelesen und interpretiert werden. Stattdessen wird sie zum übergeordneten Element des Prozesses, um das Verhalten des Prozesses während der Ausführung zu steuern Zeit. Es verwendet die Kerndatei, um die Speicherzuordnungen und den Prozessorstatus während des Absturzes zu bestimmen.
Unter Linux können übergeordnete Prozesse zusätzliche Informationen über ihre untergeordneten Prozesse erhalten, insbesondere die Möglichkeit, sie zu verfolgen, sodass der Debugger auf Informationen auf niedriger Ebene des Prozesses zugreifen kann, z. B. auf seinen Speicher lesen / schreiben, sich registrieren, Signalzuordnungen ändern, seine Ausführung stoppen usw.
Sie werden die Anforderung einer ausführbaren Datei verstehen, obwohl die Kerndatei mehr vorhanden ist, sobald Sie die Funktionsweise eines Debuggers gelesen haben.
quelle
(zusätzlich zu anderen guten Antworten)
Auf modernen Linux-Systemen (und vielen Unix-ähnlichen Systemen) liegen die Debugging-Informationen (einschließlich Metadaten zu Symboltypen , Quellcode-Speicherort, Variablentyp usw. usw.) im DWARF- Format vor und befinden sich in der ausführbaren ELF- Datei ( oder gemeinsam genutzte ELF-Bibliotheken), wenn es mit einer
-g
Option kompiliert wird . Ich empfehle das Kompilieren von Programmen zum Debuggen-g3 -O0
und möglicherweise-fno-inline
bei Verwendung eines aktuellen GCC . Mit GCC können Sie jedoch sogar sowohl Optimierungs- als auch Debugging-Informationen kompilieren, z. B. mit-O2 -g1
, obwohl die Debug-Informationen in diesem Fall möglicherweise etwas "unscharf" sind (dies kann leicht dazu beitragen, einige ungezogene Heisenbugs zu erkennen ).Es ist durchaus sinnvoll, zu vermeiden, dass diese Informationen in Kerndateien abgelegt werden, da Sie möglicherweise viele verschiedene Kerndateien (stellen Sie sich eine weit verbreitete Software vor, bei der viele Benutzer Fehlerberichte erstellen, die meisten davon mit einem
core
Speicherauszug) für dieselbe ausführbare Datei erstellen . Außerdem werden Core (5) -Dateien vom Kernel ausgegeben, was sich nicht um das Vorhandensein von DWARF-Abschnitten in ausführbaren Dateien von elf (5) kümmern sollte (da diese Abschnitte nicht dem virtuellen Adressraum des fehlerhaften Prozesses zugeordnet sind, der den Core auf ein Signal ausgegeben hat ( 7) ). Es besteht sogar die Möglichkeit, dass die Debug-Informationen in separaten Dateien (außerhalb der ausführbaren Datei) abgelegt werden.Übrigens kann GDB schmerzhaft zum Debuggen von Core-Dumps für ausführbare Dateien ohne Debug-Informationen verwendet werden. Aber dann debuggen Sie praktisch auf der Ebene des Maschinencodes (nicht auf der symbolischen Ebene, die von Programmiersprachen und ihren Compilern bereitgestellt wird).
quelle