Gdb

Aus VDR Wiki
Version vom 29. Juli 2013, 17:40 Uhr von Hulk (Diskussion | Beiträge)

(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Wechseln zu: Navigation, Suche

Der GNU Debugger, normalerweise GDB abgekürzt, ist der Standard-Debugger des GNU-Projekts. Als debuggen wird das auffinden, diagnostizieren und eliminieren von Fehlern bezeichnet.

Ein Werkzeug zur Fehlerbereinigung von Software nennt sich Debugger. Der Debugger ermöglicht in der Regel eine Ablaufverfolgung des zu untersuchenden Programmes in einzelnen Schritten oder zwischen definierten Haltepunkten.

Inhaltsverzeichnis

Einführung

Dieses ist eine sehr kurze Einleitung in die Anwendung von GDB. Gerichtet ist sie an Anwender, die ein ernstes Problem mit dem VDR, einen Plugin oder einer anderen Anwendung hat, und mithelfen möchte indem er Debugger-Ausgaben dem Entwickler oder Betreuer dieses Programmes, als ausführliche Informationen des Problemes übergibt.

Debugger Ausgaben

Programme können zusätzlich eingebaute Debugger Informationen enthalten. GDB kann die Debugger Informationen verwenden, um ausführlichere Informationen zur Verfügung zu stellen (wie Funktion Prototypen, Quellcode-Dateinamen und Zeilenzahlen,...). Falls ein Programm Debugger Informationen enthält ist es sinnvolle diese jetzt zu aktivieren.

Der Kompiler gcc hat eine Kommandozeilenschalter (-g), welcher den gcc anweist Debugger Informationen in die Objekt- und Ausführbaren Programmdateien zuschreiben.

Analysieren einer Schutzverletzung

Eine Schutzverletzung (segmentation fault oder segmentation violation, bzw. abgekürzt segfault) tritt auf, wenn ein Programm i.A. versucht auf Speicherbereiche zuzugreifen, die vor einem solchen Zugriff geschützt sind. Ursachen sind meist nicht initialisierte Pointer oder überschriebene Speichervariablen.

Der Linux Kernel ist in der Lage, einen sogenannten Kernelspeicherabzug zu schreiben, wenn irgendeine Anwendung abstürzt. Dieser Kernelspeicherabzug notiert den Zustand des Prozesses zu der Zeit des Abbruchs. GDB kann solch einen Kernelspeicherabzug lesen und Informationen aus ihm heraus erhalten.

Die meisten Distributionen haben diese Kernelspeicherabzug, die durch eine Einstellung gesperrt, so mußt sie zuerst reaktiviert werden. "ulimit -c unlimited" macht dies für die gegenwärtige Shell und alle Prozesse, die von ihm begonnen werden. Überprüfe die Bash-Man-Seite, wenn du mehr über den ulimit Befehl wissen möchtest.

# ulimit -c unlimited

Nächstes Mal wenn die Anwendung mit einem segfault abstürzt, siehst du, daß die Anzeige "Segmentation fault", in "Segmentation fault (core dumped)" geändert wurde. Und eine eine Datei "core" oder "core.pid" im aktuellen Verzeichnis gestellt wurde. Anmerkung: Du benötigst auch Schreibberechtigung für das aktuelle Verzeichnis, andernfalls wird keine Datei erstellt.

Jetzt ist es Zeit, gdb zu starten, um zu sehen, was genau geschah. Das erste Argument für gdb sollte die abgestürzte Anwendung, das zweite der Kernelspeicherabzug sein, der wegen des Abbruchs geschrieben wurde.

# gdb vdr /tmp/core.2841

gdb listet viele Informationen auf und begrüßt dich mit einer "(gdb)" Aufforderung, wenn es abgeschlossen ist. Die nützlichste Information für einen Entwickler ist ein sogenanntes Stacktrace.

Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
...
Core was generated by `/opt/vdr-1.4/bin/vdr -l 1 6 -v /video/vdr -L /opt/vdr-1.4/lib -s /opt/vdr-1.4/b'.
Program terminated with signal 11, Segmentation fault.
...
Reading symbols from /usr/lib/libstdc++.so.5...done.
Loaded symbols for /usr/lib/libstdc++.so.5
Reading symbols from /lib/tls/libm.so.6...Reading symbols from /usr/lib/debug/lib/tls/libm-2.3.2.so...done.
..
#0  0xb7e06090 in malloc_consolidate () from /lib/tls/libc.so.6
(gdb)

Schreibe "bt" in der Aufforderung um gdb aufzufordern, um einen Stacktrace (Engl. Backtrace) auszugeben, welches du dann zum Entwickler verschicken kannst. Mit "quit" verlässt man gdb.

(gdb) bt
#0  0xb7e06090 in malloc_consolidate () from /lib/tls/libc.so.6
#1  0xb7e05f6e in _int_free () from /lib/tls/libc.so.6
#2  0xb7e04dcb in free () from /lib/tls/libc.so.6
#3  0x081066b6 in ~cFrame (this=0x8f17110) at ringbuffer.c:352
#4  0x08106bc2 in cRingBufferFrame::Delete (this=0x8f1b988, Frame=0x8f17110) at ringbuffer.c:411
#5  0x08106c4b in cRingBufferFrame::Drop (this=0x8f1b988, Frame=0x8f17110) at ringbuffer.c:421
#6  0x08106a15 in cRingBufferFrame::Clear (this=0x8f1b988) at ringbuffer.c:374
#7  0x08106958 in ~cRingBufferFrame (this=0x8f1b988) at ringbuffer.c:366
#8  0x080b1f0c in ~cDvbPlayer (this=0x8f179a0) at dvbplayer.c:276
#9  0x080b3e01 in cDvbPlayerControl::Stop (this=0x8f163a0) at dvbplayer.c:775
#10 0x080e0fc8 in cReplayControl::ProcessKey (this=0x8f163a0, Key=kBlue) at menu.c:4154
#11 0x081372a3 in main (argc=30, argv=0xbffffac4) at vdr.c:1022
(gdb) quit

Folgendes Kommando erstellt eine kompletten Stacktrace von allen Threads der Anwendung.

(gdb) thread apply all bt

Andere Arten, gdb zu benutzen

Du kannst eine Anwendung unter vollständig Steuerung des gdb starten. Um das zu tun genügt gdb Anwendung. In der gdb Eingabeaufforderung verwende run Parameter, um die Anwendung zu starten. Wenn die Anwendung ein Signal empfängt, wird gdb die Eingabeauforderung zeigen um Befehle dazu einzugeben. Du kannst jederzeit Strg-C drücken, um eine gdb Eingabeauforderung zu erhalten.

Die nützlichsten gdb Befehle sind

  • bt - Ausgabe eines stacktrace (siehe obrige Ausführung).
  • up/down - Navigation innerhalb des strackframe
  • thread [Nummer] - Anzeige des aktuellen Thread / Wechsel zu einem anderem Thread mit der angegebenen Nummer.
  • c - Fortsetzen der gestarteten Anwendung.
  • print Ausdruck - den Wert des spezifizierten Ausdruckes ausgeben. Kann verwendet werden, den Wert bestimmter Variablen zum Beispiel zu kontrollieren, spezifizieren einfach den variablen Namen als Ausdruck
(gdb) up
#1  0xb7e05f6e in _int_free () from /lib/tls/libc.so.6
(gdb) up
#2  0xb7e04dcb in free () from /lib/tls/libc.so.6
(gdb) up
#3  0x081066b6 in ~cFrame (this=0x8f17110) at ringbuffer.c:352
352       free(data);
(gdb) print data
$1 = (uchar *) 0x8f3a920 ""
  • quit - beendet gdb.

Laufende Prozesse debuggen

Es ist auch möglich, gdb an einem bereits laufenden Prozeß anzudocken. Dieses kann mit gdb --pid=`pidof Anwendung` getan werden. gdb dockt am Prozeß an, der durch die Prozeßkennzeichnung spezifiziert wird, die könnte nützlich sein, wenn die Anwendung, in einer Endlos-Schleife verweilt und du feststellen möchtest, wo sie genau hängt.