Auf dieser Seite werden die Grundlagen der Fehlersuche mit dem Setup aus dem ersten Kapitel beschrieben. Dazu wird Schritt für Schritt erklärt, wie man den Debugger starten und verwenden kann.
Zum Starten der Applikation mit Debugger werden die beiden Run Konfigurationen Debug on CrowPi
und Attach to CrowPi Debugger
benötigt.
Diese sind nach dem Setup bereits korrekt eingestellt und können verwendet werden. Wichtig dabei ist die Reihenfolge, mit der die Konfigurationen gestartet werden. Dieses Vorgehen ist:
Debug on CrowPi
mit dem Run-Knopf (nicht mit dem Debug-Knopf)Listening for transport dt_socket at address: 5005 (Attach debugger)
Attach to CrowPi Debugger
Nachfolgend wird der Ablauf mit entsprechenden Abbildungen ergänzt. Als Erstes wird die Applikation im Debugmodus gestartet. Dazu muss die Konfiguration Debug on CrowPi
angewählt werden. Gestartet wird die Konfiguration mit dem Play Button.
Als Zweites wird nun gewartet, bis die korrekte Ausgabe im Konsolenfenster erscheint:
Zum Starten des Remote Debugger die entsprechende Run Konfiguration Attach to CrowPi Debugger
auswählen und mit einem Klick auf das Käfer-Icon (Debug) starten. Das Debugfenster meldet nun, ob eine Verbindung hergestellt wurde.
Nun kann zwischen den beiden Tabs Run
und Debug
hin und her gewechselt werden.
Run
wird die Ausgabe der Applikation angezeigt.Debug
finden sich Knöpfe und Informationen zu Breakpoints und Variablen.Wenn nun ein Beispiel ausgeführt wird, startet dies ganz normal und läuft, bis das Programm beendet wird. Solange keine Breakpoints oder ähnliches im Programmablauf vorkommen, hat der Debugger keinen weiteren Einfluss auf die Applikation.
Wenn nun ein Problem auftritt, wird oft an der entsprechenden Codestelle ein Breakpoint gesetzt. Dieser Breakpoint weist den Debugger an, die laufende Applikation zu unterbrechen und den aktuellen Programmstatus auf dieser Zeile im Code auszugeben. An der
Beispielapplikation 7-Segment Anzeige wird demonstriert, wie ein Breakpoint verwendet werden kann. Untersucht soll die Anzeige der - - - -
werden. Wie im Beispielcode ersichtlich passiert dies mit einem for-loop
.
Ein Breakpoint kann in IntelliJ sehr einfach durch Klicken neben die Zeilennummer in einem Programm eingefügt werden. Platziert wird der Breakpoint hier bewusst vor den zu untersuchenden for-loop
. So kann sichergestellt werden, dass nichts verpasst wird. Wenn nicht genau bekannt ist, wo ein Problem verursacht wird, lohnt es sich fast immer den Breakpoint ein paar Zeilen über der kritischen Stelle zu
platzieren. So kann die Ausgangslage gut analysiert werden.
Wie vorgängig erklärt, wird zuerst der Breakpoint platziert, die Applikation im Debugmodus gestartet und der Debugger angehängt. Es werden also diese 3 Schritte durchgeführt:
Debug on CrowPi
ohne Verwendung vom Debug-KnopfListening for transport dt_socket at address: 5005 (Attach debugger)
Attach to CrowPi Debugger
Da ein Fehler im 7-Segment Beispiel gesucht werden soll, wird das entsprechende Beispielprogramm nach Programmstart angewählt. Die Applikation wird ausgeführt, bis der Debugger am Breakpoint die Ausführung der Anwendung unterbricht.
Nachfolgend die Ansicht in IntelliJ, wenn der Debugger das Programm unterbrochen hat. IntelliJ markiert die entsprechende aktuelle Zeile im Programm. Im Debug-Tab werden zudem die aktuellen Variablen mit Werten der Applikation ausgegeben.
Um nun die Programmausführung schrittweise fortzusetzen, verfügt die Entwicklungsumgebung über verschiedene Funktionen. Diese beinhalten Grundfunktionen wie das Fortsetzen der Applikation oder das komplette Stoppen der Applikation. Die wichtigsten kurz erklärt:
Resume Program
setzt das Programm fort bis zum nächsten Breakpoint oder ApplikationsendeStop Remote Debug
stoppt den Debugger. Da in diesem Setup jedoch die Applikation und der Debugger getrennt laufen, hat die Option
keinen sinnvollen Effekt. Zum Stoppen des Programms sollte immer Stop All
verwendet werden. Dies wird auf dem zweiten Bild gezeigt.Mute Breakpoints / Disable all Breakpoints
der Debugger deaktiviert alle Breakpoints. So wird das Programm bei weiterer Ausführung nicht
mehr unterbrochen.
Für die schrittweise Ausführung des Programms stellt der Debugger noch weitere Tasten zur Verfügung:
Step Over
die nächste Anweisung im Code wird ausgeführt. Bei einem Methodenaufruf wird der Rückgabewert ermittelt, ohne die Methode zu
betreten.Step Into
die nächste Anweisung im Code wird ausgeführt. Bei einem Methodenaufruf wird der Code der Methode geöffnet und das Debugging
geht in der Methode weiter.Force Step Into
die nächste Anweisung im Code wird ausgeführt. Bei einem Methodenaufruf, welcher normalerweise bei Step Into ignoriert, wird
das Eintauchen in die Methode erzwungen.Step Out
die aktuelle Methode wird ausgeführt, bis der Code wieder am aufrufenden Ort angekommen ist. Wird zum vorzeitigen Rückkehren
aus Step Into
verwendet.
Noch genauere Erklärungen zu den einzelnen Funktionen können auch direkt der IntelliJ Anleitung entnommen werden.
Inzwischen wurden einige Steps an der Codestelle des for-loops
ausgeführt. Nun nochmals ein Blick auf die Variablenliste des Debuggers.
Auf dem Bild kann erkannt werden, wie der Debugger dem Benutzer anzeigt welche Variablen nun welche Werte haben. Aktuell ist es also: i=2
und state="- "
Da der for-loop
erst bei i > 5
stoppt, könnte nun mit dem Debugger jede weitere Iteration nachvollzogen werden.
Auf diese Weise lassen sich auch Entscheidungen bei if (this) {then that} else {other things}
nachvollziehen. Jede Variable kann auf ihren Zustand geprüft und somit bei Fehlentscheiden die Logik angepasst werden.