Seite wählen

Historisches Debuggen mit GDB

von | Aug 4, 2011 | Development

Beim Debuggen von Speicherzugriffen ist es manchmal recht schwierig, die verursachende Stelle im Quelltext zu finden, wenn das Programm an einer scheinbar zufälligen Stelle crasht oder es durch Logikfehler unerwartete Ergebnisse liefert.
Hilfsmittel wie Valgrind oder Watchpoints („help watch“ und „help rwatch“ in GDB) erleichtern hierbei die Fehlersuche, können aber nicht immer den Fehler finden. Gerade bei komplexeren Bugs wünscht man sich oft, in der Programmausführung zurückgehen zu können, um Variablen vor einem bestimmten Funktionsaufruf untersuchen zu können, oder um weitere Breakpoints zu setzen.
Seit Version 7.0 ist genau das mit GDB möglich. Mit Hilfe des „record“-Targets kann die Programmausführung aufgenommen werden und schrittweise zurück- und auch wieder vorgespult werden.
Um dieses Feature zu demonstrieren, kompilieren wir folgendes Beispiel-Programm mit „gcc -ggdb -o test test.c“:

int main(int argc, char **argv) {
    int a, b;
    a = 7;
    b = a;
    return 0;
}

Danach können wir wie gewohnt gdb aufrufen:

$ gdb ./test

Zunächst müssen wir einen Breakpoint setzen, an dem wir mit der Aufnahme der Programmausführung starten wollen. Im einfachsten Falle wäre das die „main“-Funktion. Bei komplexeren Programmen kann hier eine andere Stelle im Programm verwendet werden, wo der zu untersuchende Bug noch nicht aufgetreten ist:

(gdb) break main
Breakpoint 1 at 0x4004bf: file test.c, line 4.

Danach können wir noch einen zweiten Breakpoint setzen, wenn wir wissen, an welcher Stelle der Bug schon aufgetreten ist (z.B. beim Speichern einer Datei, wenn die zu speichernden Daten zu diesem Zeitpunkt bereits fehlerhaft sind) – dies ist jedoch optional:

(gdb) break test.c:8
Breakpoint 2 at 0x4004cc: file test.c, line 8.

Nachdem wir die Breakpoints gesetzt haben, können wir das Programm starten:

(gdb) run
Starting program: /home/gunnar/test
Breakpoint 1, main (argc=1, argv=0x7fffffffe288) at test.c:4
4		a = 7;

GDB stoppt unseren Prozess an dem ersten Breakpoint. Mit dem „record“-Befehl können wir nun GDB anweisen, die weitere Programmausführung aufzuzeichnen:

(gdb) record

Wenn wir den Prozess nun weiterlaufen lassen, sollte er den zweiten Breakpoint erreichen. (Falls wir keinen gesetzt haben, fragt GDB uns nach Ausführung des Programms, ob wir den Prozess anhalten möchten – dies sollte mit „y“ beantwortet werden, da GDB sonst den Prozess beendet):

(gdb) continue
Continuing.
Breakpoint 2, main (argc=1, argv=0x7fffffffe288) at test.c:8
8		return 0;

Um nun in der Aufnahme zurückspringen zu können, bietet GDB zusätzlich zu den normalen Ausführungsbefehlen (continue, step, next, usw.) entsprechende Befehle, die in umgekehrter Richtung funktionieren:

  • reverse-continue
  • reverse-finish
  • reverse-next
  • reverse-nexti
  • reverse-step
  • reverse-stepi

Mit reverse-continue können wir z.B. zum Anfang der Aufnahme zurückspringen:

(gdb) reverse-continue
Continuing.
No more reverse-execution history.
main (argc=1, argv=0x7fffffffe288) at test.c:4
4		a = 7;

An dieser Stelle können wir z.B. weitere Breakpoints und Watchpoints setzen, oder mit „step“ das Programm zeilenweise durchlaufen lassen und mit „print“ Variablen untersuchen.
Abschließend wäre noch zu beachten, dass „record“ das auszuführende Programm deutlich verlangsamt. Idealerweise sollten dabei die Breakpoints so gewählt werden, dass ein möglichst kleiner Teil des Prozesses aufgezeichnet werden muss.

0 Kommentare

Trackbacks/Pingbacks

  1. Weekly Snap: GDB for Debugging, ispCP for Web Server Admin, 1 New Job & 3 New Hardware › NETWAYS Blog - […] the development team, Gunnar showed how to use GDB for debugging. As of v.7.0, GDB can “record” and replay…

Einen Kommentar abschicken

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Mehr Beiträge zum Thema Development

Mein PHP-Trainingsprojekt

PHP Schulung Vor kurzem haben wir begonnen, eine neue Programmiersprache zu lernen – PHP. In der ersten Woche haben wir mit den Grundlagen wie Variablen, Arrays, Schleifen begonnen und uns schrittweise zu komplizierterer Syntax wie Funktionen, Objekten und Klassen...

check_prometheus ist jetzt öffentlich verfügbar!

Monitoring ist komplex, das wissen wir hier bei NETWAYS leider zu gut. Deswegen laufen in der Infrastruktur auch mal gerne mehrere Tools für die Überwachung. Zwei gern gesehene Kandidaten sind dabei Icinga und Prometheus. Icinga und Prometheus erfüllen...