Remote-Debugging mit Eclipse

Im Rahmen des Masterstudiums habe ich ein How-To für das Remote-Debugging mit Eclipse erstellt. Das möchte ich nun hier zur Verfügung stellen.

1. Einleitung

In diesem Projekt wird Schritt für Schritt gezeigt, wie auf einem Raspberry Pi effizient und schnell entwickelt werden kann. Dazu wird ein Host-System die C/C++-Programme Cross-kompilieren und auf das Raspberry übertragen. Anschließend kann das Programm remote-debuggt werden, um Fehler schnell ausfindig machen zu können.

Um es komplett nachvollziehbar zu halten, wurden beide Systeme neu aufgesetzt. Auf dem Raspberry Pi kommt das bekannte Rasbian (Debian Wheezy) zum Einsatz und auf dem Host-System läuft ebenfalls ein Debian Wheezy (für amd64). Der Unterschied zu anderen Linux-Distributionen sollte sehr klein sein. Es können demnach auch andere Host-Betriebsysteme, wie OpenSuse, eingesetzt werden.

Ziel ist es, mit möglichst wenigen Installationsschritten zu einer Entwicklungsumgebung zu gelangen, die mit einer Schaltfläche

  1. die veränderten Dateien speichert,
  2. den Source kompiliert und linkt,
  3. die Binärdatei auf das Zielsystem überträgt und
  4. die Debugsession mit gdbserver startet.

Als Beispiel dafür wird ein einfaches C und C++ Projekt verwendet.

2. Raspberry Pi Setup

2.1. Erstellen der SD-Karte

Am schnellsten gelingt die Betriebssystem-Installation mit einem aktuellen und vollständigen Image von Rasbian. Diese gibt es zum Download auf der offiziellen Webseite:

http://www.raspberrypi.org/downloads/

Wer mehr Zeit hat, kann auch die schmalere Netzwerkinstallation auf die SD-Karte schreiben. Dann werden die Pakete vom Raspberry Pi selbst nachgeladen.

Das Image wurde mit Windows auf die SD-Karte geschrieben, da Debian in einer virtuellen Maschine läuft und der interne SD-Kartenleser nicht durchgereicht werden konnte.

Dazu wird einfach das kleine Tool win32diskimager geladen. Ein weiterer Vorteil der Software ist, dass auch Images von SD-Karte gesichert werden können. So kann man eine Sicherheitskopie auf dem Host-Rechner ablegen oder das Betriebssystem (mäßig) schnell wechseln, wenn zu wenig SD-Karten zur Hand sind.

Wie das Image mit Linux geschrieben werden kann, ist in vielen Anleitungen im Internet gut erklärt.

2.2 Erster Bootvorgang des Rasbian

Für diese Anleitung wird weder Monitor noch Tastatur benötigt, da diese Komponenten in anderen Embedded Systemen ebenfalls nicht vorhanden sein können. Eine SSH-Netzwerkverbindung wird jedoch vorausgesetzt.

Ist das Rasbian gebooted wird dem Raspberry Pi vom DHCP Server eine IP zugewiesen. Ein Blick in die heimische Routeroberfläche bleibt eventuell nicht aus.

Ist die IP bekannt, kann sich der Host mit dem SSH-Server des Raspberry Pi verbinden.

ssh Benutzername@Adresse
ssh pi@192.168.0.24

Das Password für den Raspberry Pi User ist per default “raspberry”. Dies sollte kurz nach dem Einloggen geändert werden, um ungewollten root Zugriff zu vermeiden. Der Rayperry Pi User ist zwar nicht direkt der root-User, er ist jedoch berechtigt, durch den sudo Befehl alles als root auszuführen und ist damit defakto ein root-User.

sudo passwd pi

Ist das Passwort neu vergeben, kann die grafische Oberfläche zur Grundeinstellung mit diesem Befehl geöffnet werden:

sudo raspi-config

Einzustellen ist:

  • Expandieren der root-Partition, um den gesamten Speicher der SD-Karte zu nutzen,
  • Zeitzone und Keyboard-Layout sowie
  • Upgraden des Debian Systems (wichtige Updates laden).

Alle Einstellungen können auch in der CLI (command-line) selbst vorgenommen werden. Für ein Upgrade z.B. muss nicht jedes mal die Oberfläche benutzt werden. Dies geht einfach über:

sudo apt-get update
sudo apt-get upgrade

Damit wäre unser Rasbian schon einsatzbereit um remote zu debuggen.

Sollte ein kleineres System auf dem Raspberry Pi zum Einsatz kommen, ist es wichtig, dass der gdbserver installiert ist. Getestet werden kann dies mit dem Aufruf:

gdbserver

Sollte keine Programm gefunden werden, kann dieser evtl. mit dem Paketmanager nachinstalliert werden.

sudo apt-get install gdbserver

3. Debian Host Setup

3.1 Systemeinstellungen

Die Anleitung ist darauf ausgelegt, möglichst wenig Systemeinstellungen anpassen zu müssen. Besser ist es, die Einstellungen in der Entwicklungsumgebung vorzunehmen.

Das Systemsetup beschränkt sich bei den Softwarepaketen auf die neuste git-Version. Die Java Laufzeitumgebung wird von Eclipse benötigt und sollte bereits auf dem neusten Stand sein. Anders als beim Raspberry Pi arbeitet das neu aufgesetzte Debian mit einem festen root-Account mit eigenem Passwort. Rootzugriffe sind über den Login-Befehl su mit anschließender Passworteingabe möglich.

Als root sollten der git-Client installiert werden:

apt-get install git

Nun kann der root-user mit exit verlassen werden.

Für den Cross-Compiler wird ein neuer Ordner im Home-Verzeichnis angelegt:

mkdir rpi
cd rpi

In dieses Verzeichnis wird der neuste Cross-Compiler aus dem git-Repository geladen. Dafür haben wir zuvor das git-Paket installiert.

git clone https://github.com/raspberrypi/tools.git --depth=1

Das “–depth=1” bewirkt ein kleineres Projekt, da wir nur die letzte Version verwenden und kein Interesse an der vorangegangenen Versionsverwaltung haben.

Ist das Dateisystem vom git-Server geklont, sollte folgende Ordnerstruktur mit anschließenden Binärdateien vorhanden sein:

$HOME/rpi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin

Ebenso sollte der gleiche Pfad für das 32 Bit Hostsystem ohne “-x64” vorhanden sein. Je nach Betriebsystem sollte in weiteren Instruktionen dabei unterschieden werden. Informationen über sein Host-System erhält man mit uname -a.

3.2 Eclipse-Einstellungen

3.2.1 Installation und Pakete

Wer Eclipse bereits installiert hat, sollte sich die “Eclipse IDE for C/C++ Developers” Umgebung über den Marketplace nachinstallieren. Weiterhin ist das Plugin “Remote System Explorer” (RSE) für diese Anleitung relevant.

Ist noch kein Eclipse installiert, kann direkt eine Eclipse-Version mit allen relevanten Tools mit diesem Link geladen werden:

http://www.eclipse.org/downloads/packages/eclipse-ide-cc-developers/lunar

3.2.2 Cross-Compiler Projekt erstellen

Über File->New->C Projekt… kann ein neues Projekt angelegt werden.

Als Projekt Type wird Executable -> Hello World ANSI C Projekt gewählt. Bei Toolchain wird der Cross GCC angewählt und oben in das Textfeld kommt der Projektname z.B. “HelloWorld”. Mit dem Button Next gelangt man auf die Maske der Konfigurationsmöglichkeiten. Mit ausgewählter Debug und Release Konfiguration geht es zum nächsten Schritt. Hier wird der Cross-Compiler eingestellt, der die ausführbare Datei für den Raspberry Pi erstellen kann. Da dieser bereits mit git geladen wurde, muss hier nur noch der Pfad bei path eingetragen werden (z.B.):

/home/benutzername/rpi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin

Bei Präfix wird die Anfangskennung eingetragen. Eclipse wählt die Endungen der ausführbaren Dateien anschließend so, dass das entsprechende Werkzeug geladen wird (z.B. Compiler oder Linker). Der Präfix kann über den soeben angegebene Pfad leicht erkannt werden. In diesem Fall ist er:

arm-linux-gnueabihf-

Mit dem Finish-Button sollten nun ein neues Projekt im Projekt Explorer zu sehen sein. Dieses sollte man mit rechter Maustaste und Build Project erfolgreich kompilieren können.

Die Datei in dem Ordner Debug sollte auf dem Hostsystem nicht ausführbar sein. Zum Ausführen muss diese zuvor auf das Raspberry Pi übertragen werden.

3.2.3 RSE einrichten

Um die Remote System Umgebung benutzten zu können, muss diese erst in die C/C++ Perspektive eingebunden werden. Über das Menü mit Window -> Show View -> Other… kann die “Remote System Details” Ansicht aus dem Ordner “System Details” ausgewählt werden.

Anschließen kann mit rechts Klick, in die soeben eingeblendete Ansicht, ein neues Remote System angelegt werden.

image06

In diesem Beispielbild sind schon zwei Verbindungen zum Remote System eingetragen, einmal für einen Zugriff über das lokale Netzwerk und ein anderes um das Raspberry Pi über das Internet zu steuern.

Im ersten Dialog von “New Connection…” wird die Verbindungsart SSH Only ausgewählt. Bei dem Hostname kann nun die passenden IP zum Raspberry Pi eingeben. Der Connection Name kann selbst vergeben werden und stellt sicher, dass die Systeme unterschieden werden können. Zum Beispiel ist remote_pi_home ein ausreichend aussagekräftiger Name. Die darauffolgenden Dialoge können mit finish übersprungen werden.

Für die eben erstellte Verbindung muss noch der SSH-Benutzernamen eingestellt werden. Dazu mit recht Klick auf die Verbindung gehen und Properties wählen. Anschließend bei Default User ID den Benutzer “pi” eingeben.

image04

Nachdem alle Einstellungen vorgenommen wurden, kann mit recht Klick auf die neue Verbindung und dem Eintrag Connect die Verbindung zum Raspberry Pi aufgebaut werden.

Wenn die Passwortabfrage für den Raspberry Pi-User erscheint und anschließend ein grüner Pfeil über der Verbindung erscheint, ist die Konfiguration erfolgreich abgeschlossen.

3.2.4 Hello World Programm überspielen

Die RSE Umgebung bietet nun die Möglichkeit ein SSH-Terminal in die Eclipse-Umgebung einzubinden. Was sehr praktisch ist, da alle Fenster die zum Entwickeln gebraucht werden, in einer Umgebung angeordnet werden können.

Sind alle vorherigen Schritte ausgeführt, kann die Remote Verbindung mit einem Doppelklick geöffnet werden. Nun kann auch ein Terminal mit rechter Maustaste auf Ssh Terminals geöffnet werden.

image05

Das Teminal kann nun frei in der Umgebung angeordnet werden.

Das Ziel die Cross-kompilierte Binärdatei auf das Raspberry Pi zu übertragen, erreicht man durch die Sftp Files Option. Hier kann auf das Dateisystem des Remote Systems zugegriffen werden.

Per Drag&Drop kann nun die Binärdatei in das Home-Verzeichnis kopiert werden. Dazu wird diese vom Projekt Explorer in den Remote System Details Ansicht kopiert und dabei im Hintergrund über die Netzwerkinfrastruktur kopiert. Vorher sollte natürlich im RSE bis zum Home-Ordner navigiert werden.

Ist die Datei kopiert, verliert diese das Attribute für die Ausführbarkeit. Um das HelloWorld Programm auf dem Raspberry zu starten, muss erst der chmod Befehl benutzt werden.

chmod +x HelloWorld

Wenn alles funktioniert hat, sollte es ungefähr so im Eclipse aussehen:

image03

3.2.5 Remote-Debugging konfigurieren

Wie man im vorherigen Abschnitt gesehen hat, ist das Ausführen der kompilierten Datei nicht weiter schwierig, braucht dennoch einige Schritte die bei längeren Projekten schnell zu Fehlern führen könnten.

Glücklicherweise bietet Eclipse mit dem Remote System Explorer einer noch einfachere Möglichkeit. Dazu wird wie in Abschnitt 3.2.1 ein neues Projekt angelegt. Diesmal jedoch als C++ Projekt. Das Vorgehen bleibt hierbei jedoch gleich.

Damit mit dem Debugger vernümpftig gearbeitet werden kann, muss ein etwas umfangreicheres Programm eingefügt werden. Ohne weitere Erklärungen über den Inhalt zu verlieren, könnte man dieses Beispiel verwenden:

#include <iostream>
#include <cstddef> // size_t is a typedef on an unsigned int

int main() {
const char* MyStringDigits[] = { "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten" } ;
    std::cout << "Number: " ;
    std::size_t Number ;
    std::cin >> Number ;
    if ( Number > 10 )
         std::cerr << "Hey!! Out of Range!" << std::endl ;
    else
         std::cout << "It's: \"" << MyStringDigits[Number-1] << "\"" << std::endl ;
    return 0 ;
}

Über das Menü Run->Debug Configurations… wird ein neues Remote Debugging Profil angelegt. Dabei sollte die Felder ähnlich wie im folgenden Bild gefüllt sein:

image00

  1. C/C++ Application: die kompilierte Binärdatei muss ausgewählt sein
  2. Project: das aktuelle Projekt auf dem gearbeitet wird
  3. Connection: die Remote-Verbindung die mit Hilfe des RSE erstellt wurde
  4. Remote Absolute File Path…: der Ordner und die Zieldatei auf dem Remote System, hier befindet sich anschließend die kopierte Binärdatei.
  5. Using GDB (DSF) Automatic Remote Debugging Launcher muss ausgewählt werden

Im Tab Debugger muss nun der Cross-Debugger eingestellt werden. Dieser befindet sich in dem selben Ordner, der auch den Cross-Compiler enthält.

image01Im Unter-Tab “Gdbserver Settings” sind nur zwei Einstellfelder. In dem ersten wird der Befehl zum Starten des Debugservers eingetragen. Das das Raspberry den “gdbserver” starten kann, wurde schon bei den Raspberry Pi Einstellungen getestet. Das Feld wird nun mit “gdbserver” gefüllt.

Weiterhin muss der Port auf dem der Debugger wartet gewählt werden. Der Client wird von Eclipse automatisch auf diesen Port festgelegt. Wir wählen z.B. 2345 als Port und können die Eingaben mit Apply speichern.

Mit Close verlassen wir den Dialog und testen die Einstellungen mit der Schaltfläche die ab jetzt immer zum kompilieren, kopieren und starten der Debug-Session benutzt werden kann. Dazu wählt man den kleinen Pfeil neben dem “Bug” und das soeben konfigurierte Projekt.

image02

Eclipse sollte nun in die Debug-Ansicht wechseln. In der Konsole kann man das Programm verfolgen. Wir drücken nun die Taste F6 und führen “single steps” aus, um durch das Programm Zeile für Zeile zu gehen. In der Ansicht Variables kann der Werte der verwendeten Variablen abgelesen werden.

Das Programm wechselt automatisch in den Run-Modus sobald wir die Eingabeaufforderung mit std::cin >> Number; erreichen.

In der Konsole kann nun eine Zahl eingetragen werden und bis zum Ende des Programmes gesprungen werden. Ist das Programm beendet, sollte dennoch der rote Stopp-Button gedrückt werden, um später den Debugger neustarten zu können. Die Ausgabe in der Konsole sollte nun ungefähr so ausgesehen haben:

gdbserver :2345 /home/pi/cpp_example;exit
pi@rasp:~$ echo $PWD'>'
/home/pi>
pi@rasp:~$ gdbserver :2345 /home/pi/cpp_example;exit
Process /home/pi/cpp_example created; pid = 3530
Listening on port 2345
Remote debugging from host 146.52.131.225
Number:
5
5
It's: "Five"

Somit wäre Eclipse fertig konfiguriert und die Oberfläche für umfangreiche Projekte bereit.

4. Remote-Debugging Problembehandlung

Ab und zu kann es vorkommen, dass der gdbserver auf dem Raspberry nicht sauber über die Debug-Oberfläche von Eclipse beendet wird. Für diesen Fall wurde bereits eine SSH Konsolenverbindung geöffnet. Bereithalten sollte man dafür die Befehle ps -A, um sich alle laufenden Prozesse anzeigen zu lassen. Anschließend kann man den hängengebliebenen gdbserver etwas unsanft mit kill -9 und im ps Befehl abgelesener PID beenden.

kill -9 3527

Damit wird auch der Child-Prozess, also das eigentliche Programm, mit beendet.

Werden Programme geschrieben, die root-Rechte beim Ausführen benötigen, sollte man es vermeiden im RSE einen Account mit root einzutragen. So viel vertrauen sollte dem Eclipse-Plugin nicht eingeräumt werden, da der RSE selbstständig Kopier- und Löschfunktionen durchführt. Beim Raspberry Pi ist durch das sudo Schlüsselwort das Debuggen mit root sehr einfach. Dazu wird in der Debug-Konfiguration im Tab “Debugger” und im Unter-Tab “gdbserver Settings” statt auf den gdbserver auf ein kurzes Shellscript verlinkt. Der Eintrag könnte z.B. so aussehen:

/home/pi/gdbscript

Anschließend muss das Script auf dem Raspberry Pi erstellt werden. Dazu im Home-Verzeichnis mit nano gdbscript die Datei öffnen und folgenden Inhalt einfügen:

#!/bin/bash
#
sudo gdbserver $*

Anschließend wird die Datei mit chmod +x gdbscript wieder ausführbar gemacht.

Das der gdbserver nun als root gestartet ist, lässt sich auch daran erkennen, dass der kill-Befehl nun ebenfalls mit sudo ausgeführt werden muss.

Sollte in den Konfigurationsschritten etwas schief gegangen sein, kommentiert Eclipse dies oft mit nichtsagenden Fehlermeldungen. In den meisten Fällen sind es aber falsche Pfadangaben, die für Probleme sorgen. Pfadangaben sollte daher bei Fehlern sorgfältig kontrolliert werden. Am Besten versucht man, den Pfad in der Konsole aufzurufen, um die Angabe zu verifizieren.

Advertisements
Dieser Beitrag wurde unter Allgemein veröffentlicht. Setze ein Lesezeichen auf den Permalink.

4 Antworten zu Remote-Debugging mit Eclipse

  1. JojoS schreibt:

    Danke für die gute Anleitung!
    Habe das unter Windows installiert, geht im Prinzip genauso. Dazu habe ich die fertige Toolchain von http://gnutoolchains.com/raspberry/ genommen.
    Remote Debuggen klappt, nur das Terminal Fenster will nicht öffnen. Ist vielleicht ein Problem in der aktuellen Eclipse Neon Version?

  2. JojoS schreibt:

    ok, Terminal geht jetzt auch. Beim neueren Eclipse müssen zwei *TM Terminal‘ Extensions installiert werden, siehe: http://aninternetpresence.net/2015/08/eclipse-mars-rse-terminal/

  3. Roman schreibt:

    Wow, super Anleitung! Hat auf Anhieb geklappt!

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s