Fehlersuche mit dem grafischen Hilfsmittel Data Display
Debugger
Jagdstimmung
von Ralf Neubersch
Erschienen im Linux-Magazin
2005/04
Bei der Jagd nach Bugs im eigenen Programmcode holen sich Entwickler gern Hilfe. Etwa beim DDD: Er stöbert das virtuelle Ungeziefer auf und gibt den Blick frei auf alle Daten, die das Programm produziert.
Wenn ein selbst geschriebenes Programm nicht ordnungsgemäß funktioniert oder gar abstürzt, beginnt der ungeliebte Teil der Programmierarbeit: die Fehlersuche, auch Debuggen genannt. Wichtig sind dann Hilfsprogramme, die diese Arbeit erleichtern und beschleunigen. Ein weiterer Artikel in dieser Ausgabe stellt das Standardtool hierfür vor, den GNU-Debugger GDB[2].
Der GDB ist allerdings so umfangreich, dass die wenigsten Programmierer alle Optionen und Befehle kennen und daher nur einen geringen Teil seiner Funktionen nutzen. Zudem sind die Bedienung per Kommandozeile und die reine Textausgabe nicht sehr komfortabel. Das ändert der DDD (Data Display Debugger,[1]), der wie GDB ebenfalls zur GNU-Familie gehört. DDD ist nicht nur eine grafische Oberfläche für Konsolen-Debugger, er erweitert die Debugging-Möglichkeiten erheblich. Seine Stärke ist die Darstellung von Daten und komplexen Datenstrukturen.
Der DDD-Benutzer kann sogar weitere externe Programme einbinden und eigene Buttons einrichten, um seine eigene kleine IDE zusammenzubauen. Damit steuert er den kompletten Edit-Compile-Run-Zyklus aus dem DDD. Die Software unterstützt aber nicht nur den GDB, sie hilft auch beim Debuggen von Python-, PHP- oder Perl-Skripten (über Letztere berichtet der Perl-Snapshot in dieser Ausgabe).
Fehler verfolgen
Der Code in Listing 1 zeigt ein fehlerhaftes Programm. Es erhält eine Reihe von Zeichenketten als Eingabeparameter und sollte sie sortiert ausgeben, allerdings funktioniert das nicht wie gewünscht. Beim Aufspüren der Fehlerstellen hilft der Data Display Debugger.
01 #include <stdio.h>
02 #include <string.h>
03 #include <stdlib.h>
04
05 void slow_sort(char *arrIn[], int nrElements) {
06 int ready = 0,j;
07
08 while(!ready){
09 ready=1;
10 for (j=0; j< nrElements; j++) {
11 if (strcmp(arrIn[j], arrIn[j+1]) > 0) {
12 char *tmp;
13 ready = 0;
14 tmp = arrIn[j];
15 arrIn[j] = arrIn[j+1];
16 arrIn[j+1] = tmp;
17 }
18 }
19 }
20 }
21
22 int main(int argc, char *argv[]) {
23 int i, nrElems;
24 char **args;
25
26 nrElems = argc-1;
27 args = (char **) malloc(nrElems*sizeof (char *));
28 for (i=0; i< nrElems; i++)
29 args[i] = strdup(argv[i+1]);
30
31 slow_sort(args, nrElems);
32
33 for(i=0; i<nrElems; i++)
34 printf("%d: %sn", i, args[i]);
35
36 free(args);
37 return 0;
38 }
|
Damit der Debugger später nicht nur Maschinensprache anzeigt, sondern auch den Code, aus dem das Programm übersetzt wurde, muss der Compiler beim Übersetzen Debugging-Informationen einbinden. Beim GCC ist dafür die Option »-g« zuständig, das vollständige Kommando lautet »gcc -g slow_sort.c -o slow_sort«. Als erster Test dient folgender Aufruf:
./slow_sort Otto Willi Anna Xaver Zeppelin Gustav
Statt einer sortierten Liste spuckt der Rechner nur die Fehlermeldung »Speicherzugriffsfehler« aus (oder bei englischer Locale: »Segmentation fault«). Zur Ursachenforschung ist der Debugger mit dem Namen des Programms aufzurufen: »ddd ./slow_sort«. Abbildung 1 zeigt die drei Bereiche des DDD-Hauptfensters: Oben das Datenfenster (eingeschaltet per »View | Data Window«), in der Mitte das Fenster mit dem Quelltext und darunter die GDB-Konsole. Diese zeigt die Befehle, mit denen DDD den GDB steuert. Das Data-Window bleibt zunächst leer, hier zeigt DDD auf Wunsch die Werte von Variablen und Datenstrukturen an.
Um wie in Abbildung 1 die Werkzeug-Buttons ins Hauptfenster einzubetten statt sie als eigenständiges Fenster zu benutzen, wählt man im Menü »Edit | Preferences | Source« hinter »Tool Buttons Location« die Option »Source Window«. Hier versteckt sich auch die Option, die Zeilennummern im Quelltext einblendet: »Display Source Line Numbers«. Wer beim Start keinen Splash Screen und keinen Tip of the Day mag, schaltet beides unter »Startup« aus. Nach einem »Edit | Save Options« merkt sich DDD diese Einstellungen dauerhaft.

|
Abbildung 1: Das DDD-Hauptfenster teilt sich in Datenbereich (oben, noch leer), Quellcode (Mitte) und GDB-Konsole (unten). Beim Aufruf mit einer Namensliste bricht das Programm mit einem Segmentation Fault ab. Der Backtrace zeigt, wo im Quelltext der Fehler aufgetreten ist.
|
Programmstart
DDD hat das Programm noch nicht gestartet. Das erledigt entweder ein »run Parameter« in der GDB-Konsole oder der Menüpunkt »Program | Run...«. Bei Letzterem öffnet DDD ein Fenster, das die Aufrufparameter entgegennimmt (unter »Run with Arguments«). Beim Start mit einer Namensliste stürzt die Sortiersoftware dank eines Segmentation Fault prompt ab. Der GDB (siehe GDB-Konsole in Abbildung 1) informiert zusätzlich darüber, in welcher Funktion an welcher Adresse der Fehler aufgetreten ist.
Der Programmablauf ist innerhalb der Systemroutine »strcmp()« gescheitert. Diese Funktion ist Teil der Libc und vermutlich fehlerfrei - wahrscheinlich hat das Programm die Funktion falsch benutzt. Um das näher einzugrenzen, hilft die Aufrufreihenfolge, der so genannte Backtrace. Er ist über »Status | Backtrace« zu erreichen (Abbildung 1).
Das Ergebnis: Die »strcmp()«-Funktion wurde laut Eintrag »#1« im Backtrace vom Code in Zeile 11 (Listing 1) in der Sortierfunktion »slow_sort()« aufgerufen. Nach einem Klick auf den Eintrag wechselt die Darstellung im Quellcode-Fenster an die entsprechende Stelle.
Der grüne Pfeil vor dem »strcmp()«-Aufruf bestätigt, dass das Programm gerade an dieser Zeile war, bevor es abstürzte - der Pfeil markiert die gerade ausgeführte Funktion. Die beiden Tool-Buttons »Up« und »Down« bewegen den Cursor zur aufrufenden oder aufgerufenen Funktion, also nach oben oder unten im Call Stack.
Den nächsten Hinweis bei der Spurensuche geben die Parameter der »strcmp()«-Funktion selbst: Den ersten Parameter »arrIn[j]« im Quelltext-Fenster markieren und auf den Toolbar-Button »Print« klicken, dann wertet GDB den Ausdruck aus und präsentiert das Ergebnis in seiner Konsole. Es erscheint der unverdächtige Wert »$1 = 0x8049878 "Zeppelin"«. Beim zweiten »strcmp()«-Parameter »arrIn[j+1]« gibt GDB allerdings »$2 = 0x0« aus, der Inhalt dieses Array-Elements ist ein Null-Zeiger.
| Whitepaper |
|
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)
|
|
Usage Landscape Enterprise Open Source Data Integration
Die Nachfrage nach Datenintegrationslösungen für Unternehmen ist zunehmend gestiegen und vor allem das Interesse an Open Source Technologien wird immer größer. Doch wie und von wem werden Open Source Datenintegrationslösungen genutzt und welches Nutzungsverhalten lässt sich daraus ableiten? Das vorliegende White Paper präsentiert die Erfahrungswerte von über 1000 Open Source Nutzern und liefert fundierte Antworten auf diese Fragen.
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.
|