Open Source im professionellen Einsatz

Newsletter abonnieren
Seite durchsuchen

HEFTARCHIV | NEWS | E-BIBLIOTHEK | VIDEO | BLOGS | WHITEPAPER | EVENTS | ACADEMY | ABO | SHOP

user friendly

  Home  »  Heft & Abo  »  Heftarchiv  »  2005  »  04  »  Auf der Pirsch  

RSS-Feed der aktuellen News von Linux-Magazin Online Folgen Sie Linux-Magazin Online auf Twitter
Diesen Artikel druckenDiesen Artikel weiterempfehlen Diesen Artikel kommentieren Newsletter abonnieren
Share/Bookmark

Immer unterwegs

Sobald Sie das Programm angehalten haben, gibt es drei wichtige Befehle, um es wieder in Gang zu setzen. Das Kürzel »n« (Next) führt die nächste Anweisung aus und kehrt zum GDB-Prompt zurück. »s« (Step) schreitet zur nächsten Anweisung, im Gegensatz zu »n« auch dann, wenn sie sich innerhalb einer Funktion befindet. Das Kommando »c« (Continue) setzt die Programmausführung bis zum Erreichen des nächsten Breakpoints oder bis zum Programmende fort.

Die von den Distributionen installierten Standardbibliotheken wurden üblicherweise ohne Debugging-Informationen kompiliert, deshalb lassen sie sich nicht mit dem Befehl »s« schrittweise abarbeiten. Allerdings gibt es dafür zum Teil separate Pakete, zum Beispiel bei Fedora »glibc-debuginfo- Version.rpm«.

Wenn Sie das Programm mit dem Parameter »23« starten, berechnet es die Stückelung für 23 Cent. Die Funktion »CalcChangeFor()« in Listing 1 berechnet dazu zuerst die nötige Anzahl an 2-Euro-Münzen (200 Cent). Bei einem Betrag von 23 Cent sollte die Funktion merken, dass sie dafür keine 2-Euro-Münzen braucht. Sie bleibt aber in der Prüfschleife hängen.

Um den Grund herauszufinden, sehen Sie sich die Variablen an. Die Symbol-Informationen enthalten alle Details der Variablen, einschließlich des Typs und des Gültigkeitsbereichs (lokal oder global). Der Befehl »p« oder »print« gibt den Wert einer Variablen im aktuellen Gültigkeitsbereich aus. Haben Sie sich schrittweise mit »s« zu Zeile 17vorgearbeitet, geben Sie Folgendes ein:

(gdb) print val
$1 = 200
(gdb) p i
$2 = 23

Der Wert hinter dem »$«-Symbol erhöht sich mit jedem »print«-Befehl. Eine Variable dauerhaft beobachten ist Aufgabe des Kommandos »display« (Tabelle 3):

(gdb) display val
1: val = 200
(gdb) disp i
2: i = 23

Während Sie sich anschließend mit »s« weiter durch den Code bewegen, beobachten Sie die Werte, um zu verstehen, warum die Schleife nicht endet.

Tabelle 2:
Breakpoint-Befehle

 

Befehl

Beschreibung

b [ Dateiname:] Zeilennummer

Setzt Breakpoint in Zeile

b [ Dateiname:] Funktion

Setzt Breakpoint am Anfang einer Funktion

b [ Dateiname:] Zeilennummer if expr

Setzt bedingten Breakpoint

watch Ausdruck

Fügt Watchpoint für Variable/Ausdruck hinzu
(Abkürzung: »wa«)

info break

Listet Breakpoints und Watchpoints auf

delete

Löscht alle Breakpoints

delete [N]

Breakpoint-Nummer #N (gem. Ausgabe von »info
break«)

disable [N]

Deaktivert Breakpoint [N] (oder alle, falls [N] nicht
spezifiziert)

Tabelle 3:
Display-Befehle

 

Befehl

Beschreibung

print [/F] [ Ausdruck]

Gibt Ausdruck sofort aus, z. B.: /x = hex, /d = dez, /u
= ohne Vorzeichen, /o = okt, /t = bin, /c = char, /f = float; /F
ist ein optionales Format

display [/F] [ Ausdruck]

Gibt Ausdruck vor jedem Befehlsprompt aus

display

Listet Werte für alle Ausdrücke

undisplay

Entfernt alle Ausdrücke aus der Displayliste

undisplay [N]

Entfernt bestimmten Ausdruck aus der Liste (wie mit dem
Display- Befehl angegeben)

Der Fehler im Beispielprogramm kommt an Hand der Variablen »i« zum Vorschein: Sie sollte kleiner werden, wird aber hochgezählt, denn im Zählerabschnitt der »for«-Schleife in Zeile 16 steht »i++« statt »i--«.

Breakpoint-Nummern

Breakpoints werden auch dann fortlaufend nummeriert, wenn Sie einen wieder gelöscht haben. Wenn Sie zum Beispiel mit zwei Breakpoints (1 und 2) beginnen und dann »delete 2« eingeben, erhält der nächste Breakpoint trotzdem die Nummer 3. So bleiben Ihnen bei Änderungen Verwechslungen zwischen alt und neu erspart. Das Gleiche gilt für Display-Variablen und Watchpoints.

Erbarmungslos - Teil II

Nach der Korrektur des Fehlers kompilieren Sie das Programm neu. Dazu müssen Sie zwar den Debugger nicht beenden, aber den laufenden Prozess, denn sonst erhalten Sie beim Linken die Fehlermeldung, dass die Datei noch in Benutzung ist:

(gdb) kill
Kill the program being debugged? (y or n) y

Nach dem Kompilieren des Programms, nutzen Sie den Befehl »file«, um es wieder in den Speicher zu laden. Da Sie den Debugger in diesem Fall zuvor nicht beendet haben, bleiben alle Breakpoints erhalten - das spart vor allem bei größeren Projekten viel Zeit:

(gdb) file change
Load new symbol table from "change"? 
(y or n) y
Reading symbols from "change"...done.
(gdb) r

Beachten Sie, dass der »r«-Befehl das letzte Argument beibehält, sodass Sie auf die Eingabe des Parameters wie bei »r 23« verzichten können. Wenn Sie sich nun schrittweise durch die Schleife tasten, stellen Sie fest, dass die Zählervariable »i« korrekt heruntergezählt wird. Sie können jetzt alle Breakpoints mit »delete« entfernen (Tabelle 2) und das Programm weiterlaufen lassen.

Nach ungewöhnlich langer Verzögerung gibt der Debugger einen Speicherzugriffsfehler aus und kehrt zurück zur Eingabeaufforderung (siehe Listing 4). Es gibt also einen weiteren Bug. Als Erstes müssen Sie feststellen, wo genau das Programm momentan steht. Dazu sehen Sie sich den Call Stack (oder Backtrace) an, der die aufgerufenen Funktionen sowie deren Parameter anzeigt.

Diese Ausgabe aus Listing 5 zeigt, dass der Algorithmus in einer rekursiven Schleife steckt. Das Programm ruft dieselbe Funktion immer wieder mit dem gleichen Parameter auf. Daher wird die Abbruchbedingung (»cent==0«) niemals ausgelöst.

Listing 4:
Speicherzugriffsfehler

Program received signal SIGSEGV, Segmentation fault.
   0x080485a7 in CalcChangeFor (cent=23) at change.c:19
   19  CalcChangeFor(cent - i*val);

Listing 5: Stack
durchsuchen

(gdb) backtrace
   #1  0x08048505 in CalcChangeFor (cent=23) at change.c:19
   #2  0x08048505 in CalcChangeFor (cent=23) at change.c:19
   #3  0x08048505 in CalcChangeFor (cent=23) at change.c:19
   #4  0x08048505 in CalcChangeFor (cent=23) at change.c:19
   .....

Listing 6:
Breakpoints

(gdb) b 15
   Breakpoint 2 at 0x8048554: file change.c, line 15.
   (gdb) r
   Starting program: /home/steev/code/change 23
   
   Breakpoint 2, CalcChangeFor (cent=23) at change.c:15
   15  val = coins[i];

Wenn Sie den Debugger neu starten - da Sie die Datei nicht verändert haben, reichen dazu die Befehle »kill« und »run« - und Breakpoints für jeden rekursiven Aufruf für »CalcChangeFor()« setzen, erkennen Sie, dass der Wert von »cent« unverändert bleibt, denn »i*val = 0«.

Diesen Artikel druckenDiesen Artikel weiterempfehlen Diesen Artikel kommentieren Newsletter abonnieren
Share/Bookmark
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)
Kommentare (0)