Friedrich-Alexander-Universität Erlangen-Nürnberg  /   Technische Fakultät  /   Department Informatik

GDB Remote Stub KlasseDiese Klasse ermöglicht ein entferntes Debuggen des Betriebssystems mit GDB auf echter Hardware (aber auch im Emulator), in dem sie einen Teil des GDB Remote Serial Protocols (RSP) implementiert, eigene Unterbrechungsbehandlungsroutinen für Traps installiert und über die serielle Schnittstelle kommuniziert. Mehr ...

#include <debug/gdb/stub.h>

Klassendiagramm für GDB_Stub:
Zusammengehörigkeiten von GDB_Stub:

Öffentliche Methoden

 GDB_Stub (bool wait=false, bool debugOutput=false, Serial::comPort port=COM1, Serial::baudRate baudrate=BAUD_9600)
 Konstruktor. Mehr ...
 
- Öffentliche Methoden geerbt von Serial
 Serial (Serial::comPort port=COM1, Serial::baudRate baudrate=BAUD_115200, Serial::dataBits databits=DATA_8BIT, Serial::stopBits stopbits=STOP_1BIT, Serial::parity parity=PARITY_NONE)
 Konstruktor. Mehr ...
 
int read (bool blocking=true)
 Lese ein Byte von serieller Schnittstelle. Mehr ...
 
int write (char out, bool blocking=true)
 Schreibe ein Byte auf die serieller Schnittstelle. Mehr ...
 

Geschützte Methoden

void handle (void)
 Behandlung eines Traps. Mehr ...
 
int writeString (const char *buf, size_t len)
 Sende eine Zeichenkette über die serielle Schnittstelle. Mehr ...
 
int readString (char *buf, size_t buf_len, size_t len)
 Empfange eine Zeichenkette über die serielle Schnittstelle. Mehr ...
 
int send_packet (const char *pkt, size_t pkt_len)
 Sende ein Datenpaket. Mehr ...
 
int recv_packet (char *pkt_buf, size_t pkt_buf_len, size_t *pkt_len)
 Empfange ein Datenpaket. Mehr ...
 
int checksum (const char *buf, size_t len)
 Berechne die Prüfsumme. Mehr ...
 
int recv_ack (void)
 Empfange ein Bestätigung für ein Paket. Mehr ...
 
int send_ok_packet ()
 Erstelle und sende ein OK Paket. Mehr ...
 
int send_signal_packet (char *buf, size_t buf_len, char signal)
 Erstelle und sende ein Signalpaket. Mehr ...
 
int send_error_packet (char *buf, size_t buf_len, char error)
 Erstelle und sende ein Fehlerpaket (E Errorcode) Mehr ...
 
int mem_read (char *buf, size_t buf_len, uintptr_t addr, size_t len, bool hex)
 Lese den Speicherinhalt einer Adresse in den Puffer. Mehr ...
 
int mem_write (const char *buf, size_t buf_len, uintptr_t addr, size_t len, bool hex)
 Schreibe den Pufferinhalt an eine Adresse. Mehr ...
 
void sys_continue (void)
 Setze das Programm am aktuellen Instruktionszeiger fort.
 
void sys_step (void)
 Springe zur nächsten Instruktion.
 

Freundbeziehungen

void debug_handler (struct debug_context *context)
 Erlaube der generischen Unterbrechungsbehandlung Zugriff auf die geschützten Methoden dieser Klasse. Mehr ...
 

Weitere Geerbte Elemente

- Öffentliche Typen geerbt von Serial
enum  comPort { COM1 = 0x3f8, COM2 = 0x2f8, COM3 = 0x3e8, COM4 = 0x238 }
 COM-Port. Mehr ...
 
enum  baudRate {
  BAUD_300 = 384, BAUD_600 = 192, BAUD_1200 = 96, BAUD_2400 = 48,
  BAUD_4800 = 24, BAUD_9600 = 12, BAUD_19200 = 6, BAUD_38400 = 3,
  BAUD_57600 = 2, BAUD_115200 = 1
}
 Übertragungsgeschwindigkeit. Mehr ...
 
enum  dataBits { DATA_5BIT = 0, DATA_6BIT = 1, DATA_7BIT = 2, DATA_8BIT = 3 }
 Anzahl der Datenbits pro Zeichen.
 
enum  stopBits { STOP_1BIT = 0, STOP_1_5BIT = 4, STOP_2BIT = 4 }
 Anzahl der Stopbits pro Zeichen.
 
enum  parity {
  PARITY_NONE = 0, PARITY_ODD = 8, PARITY_EVEN = 24, PARITY_MARK = 40,
  PARITY_SPACE = 56
}
 Paritätsbit.
 

Ausführliche Beschreibung

GDB Remote Stub Klasse

Diese Klasse ermöglicht ein entferntes Debuggen des Betriebssystems mit GDB auf echter Hardware (aber auch im Emulator), in dem sie einen Teil des GDB Remote Serial Protocols (RSP) implementiert, eigene Unterbrechungsbehandlungsroutinen für Traps installiert und über die serielle Schnittstelle kommuniziert.

Für den Einsatz muss GDB mit der selben Binärdatei wie das Betriebssystem auf der Hardware gestartet werden – idealerweise im Quelltextverzeichnis, denn dann kann der Quelltext in die Ausgabe eingebettet werden. Zudem müssen die Einstellungen für die seriellen Übertragung sowohl auf der Hardware als auch im GDB identisch sein.

Beispiel:

~> ssh faui04a
faui04a:~> cd mpstubs
faui04a:~/mpstubs> make netboot
faui04a:~/mpstubs> gdb .build/system64
GNU gdb (Debian 7.12-6) 7.12.0.20161007-git
[...]
Reading symbols from /proj/i4bs/student/uj66ojab/kernel...done.
(gdb) set arch i386:x86-64

(gdb) set serial baud 9600
(gdb) target remote /dev/ttyBS1
Remote debugging using /dev/ttyBS1
main () at main.cc:87
Zu beachten
GDB liegt bereits eine i386-stub.c bei, welche jedoch hässlich, schlecht gewartet und nicht sonderlich gut in unser objektorientiertes Betriebssystem integrierbar ist. Deshalb verwenden wir eine überarbeitete Version von Matt Borgersons gdbstub (veröffentlicht 2016 unter der GPL v2 Lizenz).

Beschreibung der Konstruktoren und Destruktoren

◆ GDB_Stub()

GDB_Stub::GDB_Stub ( bool  wait = false,
bool  debugOutput = false,
Serial::comPort  port = COM1,
Serial::baudRate  baudrate = BAUD_9600 
)

Konstruktor.

Konfiguriert die serielle Schnittstelle (als 8N1 ) sowie Unterbrechungsbehandlungen

Parameter
waitWarte nach der Konfiguration auf eine GDB-Verbindung
debugOutputDebugge den GDB-Stub durch Bildschirmausgaben der Kommunikation (hilfreich bei Erweiterung des RSP)
portCOM-Port für die serielle Verbindung
baudrateBaud Rate, Standard bei GDB ist 9600 (kann aber zu Engpässen führen)

Dokumentation der Elementfunktionen

◆ checksum()

int GDB_Stub::checksum ( const char *  buf,
size_t  len 
)
protected

Berechne die Prüfsumme.

Parameter
bufZeiger auf den Puffer
lenGröße des Puffers
Rückgabe
8-Bit Prüfsumme des Puffers

◆ handle()

void GDB_Stub::handle ( void  )
protected

Behandlung eines Traps.

Diese Funktion wird nach der Speicherung des aktuellen CPU Zustandes von der generischen Debug-Unterbrechungsbehandlungsroutine aufgerufen. Sie ist das Herzstück und übernimmt die Kommunikation mit dem GDB Host.

◆ mem_read()

int GDB_Stub::mem_read ( char *  buf,
size_t  buf_len,
uintptr_t  addr,
size_t  len,
bool  hex 
)
protected

Lese den Speicherinhalt einer Adresse in den Puffer.

Parameter
bufZeiger auf den Puffer
buf_lenGröße des puffers
addrStartadresse des zu lesenden Speichers
lenGröße des zu lesenden Speichers
hexSpeichere als Hexadezimal (true) oder binär (false) in den Puffer
Rückgabe
Anzahl der gelsenen Bytes oder -1 falls der Puffer zu klein

◆ mem_write()

int GDB_Stub::mem_write ( const char *  buf,
size_t  buf_len,
uintptr_t  addr,
size_t  len,
bool  hex 
)
protected

Schreibe den Pufferinhalt an eine Adresse.

Parameter
bufZeiger auf den Puffer
buf_lenGröße des puffers
addrStartadresse des zu schreibenden Speichers
lenGröße des zu schreibenden Speichers
hexInterpretiere den Pufferinhalt als Hexadezimal (true) oder binär (false)
Rückgabe
Anzahl der geschrieben Bytes oder -1 falls der Puffer zu gross

◆ readString()

int GDB_Stub::readString ( char *  buf,
size_t  buf_len,
size_t  len 
)
protected

Empfange eine Zeichenkette über die serielle Schnittstelle.

Parameter
bufZeiger auf den Puffer
buf_lenGröße des Puffers
lenAnzahl der zu empfangenden Bytes
Rückgabewerte
0falls erfolgreich,
-1falls kein/nicht alle Bytes empfangen werden konnten

◆ recv_ack()

int GDB_Stub::recv_ack ( void  )
protected

Empfange ein Bestätigung für ein Paket.

Rückgabewerte
0eine [positive] Bestätigung (ACK, + ) wurde empfangen
1eine negative Bestätigung (NACK, - ) wurde empfangen
-1andernfalls

◆ recv_packet()

int GDB_Stub::recv_packet ( char *  pkt_buf,
size_t  pkt_buf_len,
size_t *  pkt_len 
)
protected

Empfange ein Datenpaket.

Bedingt eine fehlerfreie Verbindung zur Übertragung von 7-Bit ANSI Zeichen

Parameter
pkt_bufZeiger auf den Paketpuffer
pkt_buf_lenGröße des Paketpuffers
pkt_lenGröße des zu empfangenden Pakets
Rückgabewerte
0falls Paket erfolgreich empfangen wurde,
-1andernfalls

◆ send_error_packet()

int GDB_Stub::send_error_packet ( char *  buf,
size_t  buf_len,
char  error 
)
protected

Erstelle und sende ein Fehlerpaket (E Errorcode)

Rückgabe
Statuscode von send_packet

◆ send_ok_packet()

int GDB_Stub::send_ok_packet ( )
protected

Erstelle und sende ein OK Paket.

Rückgabe
Statuscode von send_packet

◆ send_packet()

int GDB_Stub::send_packet ( const char *  pkt,
size_t  pkt_len 
)
protected

Sende ein Datenpaket.

Datenpakete haben die Form

$<Daten>#<Prüfsumme>
Parameter
pktZeiger auf den Paketpuffer
pkt_lenGröße des Paketpuffers
Rückgabewerte
0falls Paket erfolgreich gesendet und bestätigt wurde,
1falls Paket zwar gesendet aber nicht bestätigt wurde,
-1andernfalls

◆ send_signal_packet()

int GDB_Stub::send_signal_packet ( char *  buf,
size_t  buf_len,
char  signal 
)
protected

Erstelle und sende ein Signalpaket.

beinhaltet aktuellen Interruptvektor (S Vektor)

Rückgabe
Statuscode von send_packet

◆ writeString()

int GDB_Stub::writeString ( const char *  buf,
size_t  len 
)
protected

Sende eine Zeichenkette über die serielle Schnittstelle.

Parameter
bufZeiger auf den Puffer
lenGröße des Puffers
Rückgabewerte
0falls erfolgreich,
-1falls kein/nicht alle Bytes gesendet werden konnten

Freundbeziehungen und Funktionsdokumentation

◆ debug_handler

void debug_handler ( struct debug_context context)
friend

Erlaube der generischen Unterbrechungsbehandlung Zugriff auf die geschützten Methoden dieser Klasse.

Debug-Unterbrechungsbehandlungsroutine des Systems, analog zu guardian . Aufruf dieser Funktion durch den Assembler Teil der Debug- Unterbrechungsbehandlung (dbg_irq_entry_* in der debug/gbd/handler.asm) – diese Routinen müssen zuvor mittels GDB_Stub::install_handler installiert werden. Nach dem vorbereiten der Daten wird GDB_Stub::handle aufgerufen, welches mit dem Host über die serielle Schnittstelle kommuniziert.

Zu beachten
Für korrekte Funktionalität im Multiprozessorfall wird eine korrekte Implementierung der Klasse Ticketlock vorausgesetzt!
Parameter
contextbeinhaltet einen Pointer auf den eigenen Stack, über den auf den Debug-Unterbrechungskontext zugegriffen werden kann.

Da wir nur einen internen Zustandsspeicher haben, kann dies im Mehrkern- betrieb schnell böse enden, wenn mehrere Kerne gleichzeitig schreibend darauf zugreifen wollen. Deshalb exklusiver Ausschluss!

Selbstverständlich sollte man bei der Kombination 'aktives Warten' und 'Unterbrechungsbehandlung' sofort üble Bauchschmerzen bekommen. Als Ausrede dient hier, dass es für den Debugger ist, welcher zum einen so einfach wie möglich sein sollte, zum anderen auch nicht im produktiven Betrieb verwendet werden sollte.

Also bitte nur als 'simple Hack' und nicht als 'best practice' im Hinterkopf behalten.


Die Dokumentation für diese Klasse wurde erzeugt aufgrund der Dateien:
  • debug/gdb/stub.h
  • debug/gdb/handler.cc
  • debug/gdb/protocol.cc