Workshop: Debugging mit GDB
Auf der Pirsch
von Steven Goodwin
Erschienen im Linux-Magazin
2005/04
Wer Programme schreibt, baut ahnungslos oft auch gut versteckte Bugs ein. Die richtigen Tools und etwas Geduld vereinfachen das Debugging. Dieser Workshop erklärt die Grundlagen der Fehlersuche und vermittelt den Umgang mit dem prominentesten Vertreter der Gattung, dem GNU-Debugger GDB.
Die Existenz aller Bugs geht auf ein grundlegendes Missverständnis zurück: Etwas, was Sie für richtig gehalten haben, ist in Wirklichkeit falsch - egal ob sich der Fehler auf den Wert einer Variablen oder die Gültigkeit einer Speicheradresse oder eines Zeigers bezieht. Wie sich die Bugs auswirken, können Sie nicht vorhersagen. Vielleicht stürzt das Programm aufgrund eines Speicherzugriff-Fehlers ab, vielleicht bleibt es in einer Endlosschleife hängen oder es liefert falsche Ergebnisse. Aber eines steht fest: Alle Bugs sind wichtig und als Programmierer kommen Sie nicht darum herum, sie zu beseitigen.
Gründlich informieren
Als konventioneller Lösungsansatz dienen so genannte Trace-Meldungen. Sie geben aktuelle Zwischenergebnisse des Programms aus. In der Programmiersprache C fügt man üblicherweise Code hinzu, der auf dem Kanal zur Fehlerausgabe ausgiebig Bericht erstattet:
fprintf(stderr, "Entering CalcAverage now (num=%d, total=%d)",num,total);
....
fprintf(stderr, "Leaving CalcAverage now (return av=%d)", average);
Solche Befehle dokumentieren Funktionsaufrufe und Variablenwerte. Diese Informationen helfen bei der weiteren Suche nach der Fehlerursache.
Für Faultiere
Obwohl diese Methode für kleinere Programme angebracht sein mag, wird sie mit zunehmendem Code-Umfang sehr mühsam. Zusätzlich schleichen sich dabei schnell neue Fehler ein - schließlich kann auch der hinzugefügte Debugging-Code wieder Fehler enthalten.
Faulheit gilt bei Programmierern als eine Tugend, ebenso wie das Verschieben auf morgen. Bevor Sie sich also kopfüber ins Debugging stürzen, lehnen Sie sich zurück, um in Ruhe über prophylaktische Maßnahmen nachzudenken.
Erstens: Wird das Programm sauber kompiliert? Gibt der Compiler Warnungen aus und können diese Warnungen mit dem fehlerhaften Verhalten des Programms zusammenhängen? Kompilieren Sie mit den Optionen »-Wall« und »-O3«; Letztere führt zusätzliche Checks durch, die bei der nicht optimierten Kompilierung fehlen, »-Wall« gibt sämtliche Warnungen aus. Dann sehen Sie sich die Ausgabe erneut an.
Zweitens: Überprüfen Sie den Code mit anderen Tools wie Splint[2]; es meldet Fehler, die GCC ignoriert. Auf diese Art stoßen Sie auf Programmabschnitte, die unter bestimmten Umständen den Dienst verweigern. Typische Problemfälle sind zum Beispiel:
-
Eine Zahl des Typs »unsigned« nimmt einen negativen
Wert an.
-
Aus dem Gleichheitssymbol »==« wird durch einen
Tippfehler eine Zuweisung (»=«).
-
Beim Type-Casting (explizit oder implizit) gehen Informationen
verloren.
-
Schleifenanfänge oder -enden liegen um eins neben dem
gewünschten Wert (Off-by-One-Fehler).
Drittens: Melden andere Tools Probleme mit dem Programm? Zum Beispiel ein Memory-Debugger, der »malloc«-Probleme oder den Zugriff auf Daten außerhalb des gültigen Bereichs abfängt.
Dieses Problem tritt am häufigsten bei Zeichenketten auf, weil ein Test auf Grenzen (Bounds-Checking) hier typischerweise vernachlässigt wird. Allerdings kann das Problem jedes Array, jeden Zeiger sowie dynamisch allozierten Speicher betreffen.
|
|
|
Kürzel
|
Befehl
|
Beschreibung
|
|
r
|
run [ Args]
|
Programm starten
|
|
c
|
continue
|
Ablauf (vom aktuellen Breakpoint aus) fortsetzen
|
|
n
|
next
|
Nächste Anweisung, schrittweise Funktionsaufrufe abarbeiten
|
|
s
|
step
|
Zur nächsten Zeile oder Funktion gehen
|
|
p
|
print
|
Variable anzeigen
|
|
pt
|
ptype
|
Gibt den Typ einer Variablen sowie Details der Struktur zurück
|
|
bt
|
backtrace
|
Listet einen Stack aller Funktionen auf, die bis zu diesem Punkt aufgerufen wurden (auch unter dem Namen Where bekannt)
|
|
l
|
list
|
Listet einen Programmabschnitt auf
|
|
h
|
help
|
Spezifische Hilfe zum Beispiel mit »help delete«
|
|
q
|
quit
|
GDB beenden
|
Bekannte Memory-Debugger (siehe[3]) sind unter anderem Valgrind, CCMalloc, und Electric Fence von Bruce Perens, dem ehemaligen Leiter des Debian-Projekts. Nicht alle diese Tools funktionieren auf die gleiche Weise. So setzt Valgrind auf Just-in-Time-Debugging und interpretiert dazu den Quellcode selbst. Im Gegensatz dazu verlinkt der Entwickler bei CCMalloc die kompilierte Datei mit der CCMalloc-Bibliothek, um Speicherlecks aufzuspüren.
Verweigert Ihr Programm nach allen Bemühungen weiterhin den Dienst, müssen Sie den Code zeilenweise durchforsten, um festzustellen, wo und warum etwas schief läuft. Das Tool der Wahl für diesen Zweck heißt GDB, auf Wunsch mit Hilfe eines der grafischen Frontends wie DDD (siehe Artikel in diesem Heft) oder XXGDB.
Auch grafische Entwicklungsumgebungen wie KDevelop (siehe Abbildung 1), Anjuta und sogar Eclipse suchen Fehler mit Hilfe des GDB-Debuggers. Mit ihm steuern Sie den Programmablauf interaktiv, halten ein Programm an beliebiger Stelle an, untersuchen die Variablen und beeinflussen sogar die Ablaufreihenfolge des Code im laufenden Programm.
Der GNU Debugger ist einer der ältesten Bestandteile der GNU-Entwicklungsumgebung und in praktische jeder Linux-Distribution enthalten. Bereits 1988 rief Richard Stallman das Projekt ins Leben. Trotz oder gerade wegen dieser langen Geschichte ist GDB weiterhin eine reine Befehlszeilenanwendung, ausgestattet mit einer großen Vielfalt an mächtigen Befehlen.
Für den Linux-Kernel gibt es eine spezielle Version des Debuggers: KGDB. Sie unterstützt unter anderem das Remote-Kernel-Debugging über eine serielle Leitung. Mit Hilfe von GDB Server lässt sich GDB außerdem über eine TCP/IP-Verbindung steuern.
| Whitepaper |
|
The Role of Open Source in Data Integration
Obwohl in den letzten Jahren viele technische Fortschritte erzielt werden konnten, verfügen die meisten Datenintegrationsprozesse nach wie vor nur über eine sehr begrenzte Automatisierung. Das vorliegende White Paper von dem Industry Analyst Mark Madson wird zunächst ein grundlegendes Verständnis von Daten Integration vermitteln, die Vorzüge von Open Source Lösungen für Daten Integration erläutern und Ihnen professionelle Empfehlungen geben, damit Sie Ihre Integrationsjobs noch einfacher und produktiver gestalten können.
Download PDF (Registrierung erforderlich)
|
|
Open Source Datenintegration in der Praxis: Fallstudien und Anwendungsbeispiele (Folge 2)
Der zweite Teil des Open Source Datenintegration in der Praxis: Fallstudien und Anwendungsbeispiele White Papers beleuchtet anhand weiterer ausgewählter Case Studies die Implementierung von Open Source Datenintegration in der Praxis und benennt die daraus resultierenden Vorteile.
Download PDF (Registrierung erforderlich)
|
Dieser Online-Artikel kann Links enthalten, die auf nicht mehr vorhandene Seiten verweisen. Wir ändern solche "broken links"
nur in wenigen Ausnahmefällen. Der Online-Artikel soll möglichst unverändert der gedrucken Fassung entsprechen.
|