GDB

Hauptfunktionen des GDB

Der GNU Debugger erlaubt es, zu sehen, was in einem Programm während der Ausführung passiert oder was ein Programm zuletzt gemacht vor einem Absturz.

Die vier Hauptfunktionen von GDB sind:

  • Programm mit Optionen starten
  • Programm bei bestimmten Bedingungen anhalten
  • Untersuchen was geschehen ist, wenn das Programm angehalten wurde
  • Inhalt des Speichers ändern

Handhabung

GDB ist in vielen IDEs (wie z.B. Eclipse) integriert und wird über das GUI bedient. Alternativ kann GDB auch über die Kommandozeile gestartet werden. Das ist besonders nütztlich, um einen Segfault zu überprüfen.

Mehr dazu unter im Crashcourse gdb

Coredumps

Mit Coredumps können Segfaults analysiert werden, ohne dass die Applikation im gdb gestartet wird. Ein Backtrace kann im Nachhinen untersucht werden. Es ist ebenfalls möglich, lokale Variablen nach dem Absturz zu untersuchen.

Mehr dazu unter unter software:gdb:coredump.

STABS

STABS (symbol tables) ist das Format in welchem das Program für den Debugger beschrieben wird. Der GCC Compiler kompiliert C-Programme (.c) in Assembler-Programme (.s), welche vom Assembler in Objekt-Dateien (.o) kompiliert werden, die dann vom Linker und anderen Objekt-Dateien zu einem ausführbarem Programm verlinkt werden.

Mit der Option '-g' des GCC Compilers wird in die .s-Dateien zusätzliche Information eingefügt. Diese Information beschreibt Eigenschaften der Source-Datei, wie z.B. Zeilennummern, Typen, Scope der Variable, Funktionsnamen, usw.

Beispiel: C Source, ASM Source mit STAB

Remote Debugging

GDB Remote Debugging

GDB kann auch Programme debuggen, die nicht lokal ausgeführt werden. Auf dem Target muss aber ein RSP-Server lauften, der mit dem GDB kommunizieren kann. Die Kommunikation läuft über das Remote Serial Protokoll.

Beispiel mit MPC5200

Grundsätzlicher Aufbau

In der Zukunft sollte der Deep-Compiler zwei Files generieren. Das Image-File, welches direkt auf den MPC5200 geladen und ausgeführt wird, und ein ELF-File, welches zusammen mit den Java-Sourcen vom GDB Debugger benutzt werden können, um den MPC5200 zu debuggen.

Im ELF-File stehen die Debug-Information (STABS), die es GDB erlauben das Java-Program zu debuggen. In einer ersten Version werden die STABS manuell in ein Assembler-Programm eingefügt und mit dem GCC-Assembler übersetzt.

Java Code

Um das Beispiel noch zu vereinfachen wird eine Endlos-Schleife ans Ende der reset()-Methode eingefügt:

static void reset() {
	int stackOffset = US.GET4(sysTabBaseAddr + stStackOffset);
	int stackBase = US.GET4(sysTabBaseAddr + stackOffset + 4);
	int stackSize = US.GET4(sysTabBaseAddr + stackOffset + 8);
	US.PUTGPR(1, stackBase + stackSize - 4);	// set stack pointer
	int kernelClinitAddr = US.GET4(sysTabBaseAddr + stKernelClinitAddr);
	US.PUTSPR(SRR0, kernelClinitAddr);
	US.PUTSPR(SRR1, SRR1init);
	//US.ASM("rfi");
	
	int x = 4;
	x ^= 0x55; 
	
	US.PUTGPR(R27, x);
	while (true);
}

Assembler Code

Der Assembler-Code (test.S) sieht wie folgt aus:

.org 0x400100
reset:
	li		r2, 16388
	lwz		r4, 0(r2)
	addi	r2, r4, 16384
	addi	r3, r2, 4
	lwz		r5, 0(r3)
	addi	r2, r4, 16384
	addi	r3, r2, 8
	lwz		r4, 0(r3)
	add		r2, r5, r4
	addi	r3, r2, -4
	mr		r1, r3
	li		r2, 16396
	lwz		r4, 0(r2)
	mr		r0, r4
	mtspr	SRR0, r0
	li		r2, 14338
	mr		r0, r2
	mtspr	SRR1, r0
	li		r2, 4
	xori	r3, r2, 0x55
	xoris	r3, r3, 0x0
	mr		r27, r2
	b		0

Kompiliert wird mit folgendem Befehl:

$ powerpc-linux-gnu-as -mppc32 -mregnames -be test.S

Das ELF-File a.out wird erstellt. Dieses File kann durch folgenden Befehl disassembliert werden:

$ powerpc-linux-gnu-objdump -d -EB -G -mpowerpc a.out

Assembler Code mit STABS

Der Assembler-Code (test.S) mit den Debug-Informationen sieht wie folgt aus:

.include "stabs.include"

.stabs "void:t1=1",N_LSYM,0,0,0
.stabs "int:t2=r2;-2147483648;2147483647;",N_LSYM,0,0,0

.data
.org 0x100000
.stabs "targetCommand:G2",N_GSYM,0,0,0
.global targetCommand
targetCommand:
.int 0

.org 0x400100
.stabs "/home/abajric/ntb/deep/ws/runtime-library/",N_SO,0,0,Ltext0
.stabs "src/ch/ntb/inf/deep/runtime/mpc555/Reset.java",N_SO,0,0,Ltext0
.text
Ltext0:

reset:
.stabn N_SLINE, 0, 38, LM1
LM1:
	li		r2, 16388
	lwz		r4, 0(r2)
	addi	r2, r4, 16384
	addi	r3, r2, 4
	lwz		r5, 0(r3)
	addi	r2, r4, 16384
	addi	r3, r2, 8
	lwz		r4, 0(r3)
	add		r2, r5, r4
	addi	r3, r2, -4
.stabn N_SLINE, 0, 41, LM5
LM6:
	mr		r1, r3
	li		r2, 16396
	lwz		r4, 0(r2)
	mr		r0, r4
	mtspr	SRR0, r0
	li		r2, 14338
	mr		r0, r2
	mtspr	SRR1, r0
.stabn N_SLINE, 0, 47, LM4
LM4:
	li		r2, 4
.stabs "x:r2;-2147483648;2147483647;",N_RSYM,0,4,2
.stabn N_SLINE, 0, 48, LM5
LM5:
	xori	r3, r2, 0x55
.stabs "x:r2;-2147483648;2147483647;",N_RSYM,0,4,3
	xoris	r3, r3, 0x0
.stabn N_SLINE, 0, 50, LM2
LM2:
	mr		r27, r2
.stabs "x:r2;-2147483648;2147483647;",N_RSYM,0,4,27
.stabn N_SLINE, 0, 51, LM3
LM3:
	b		0

.stabs "ch::ntb::inf::deep::runtime::mpc555::Reset::reset:F1",N_FUN,0,0,reset
.stabn N_SLINE, 0, 37, reset
.stabn N_LBRAC, 0, 0, LM1
.stabn N_RBRAC, 0, 0, LM3

Im File stabs.include stehen Definitionen der STABS Symboltypen:

# non-stab symbol types
.set N_UNDF,		0x0
.set N_EXT,			0x1
.set N_ABS,			0x2
.set N_TEXT,		0x4
.set N_DATA,		0x6
.set N_BSS,			0x8
.set N_FN_SEQ,		0x0c
.set N_INDR,		0x0a
.set N_COMM,		0x12
.set N_SETA,		0x14
.set N_SETT,		0x16
.set N_SETD,		0x18
.set N_SETB,		0x1a
.set N_SETV,		0x1c
.set N_WARNING,		0x1e
.set N_FN,			0x1f

# stab symbol types
.set N_GSYM,		0x20
.set N_FNAME,		0x22
.set N_FUN,			0x24
.set N_STSYM,		0x26
.set N_LCSYM,		0x28
.set N_MAIN,		0x2a
.set N_ROSYM,		0x2c
.set N_PC,			0x30
.set N_NSYMS,		0x32
.set N_NOMAP,		0x34
.set N_MAC_DEFINE,	0x36
.set N_OBJ,			0x38
.set N_MAC_UNDEF,	0x3a
.set N_OPT,			0x3c
.set N_RSYM,		0x40
.set N_M2C,			0x42
.set N_SLINE,		0x44
.set N_DSLINE,		0x46
.set N_BSLINE,		0x48
.set N_BROWS,		0x48
.set N_DEFD,		0x4a
.set N_FLINE,		0x4c
.set N_EHDECL,		0x50
.set N_MOD2,		0x50
.set N_CATCH,		0x54
.set N_SSYM,		0x60
.set N_ENDM,		0x62
.set N_SO,			0x64
.set N_LSYM,		0x80
.set N_BINCL,		0x82
.set N_SOL,			0x84
.set N_PSYM,		0xa0
.set N_EINCL,		0xa2
.set N_ENTRY,		0xa4
.set N_LBRAC,		0xc0
.set N_EXCL,		0xc2
.set N_SCOPE,		0xc4
.set N_RBRAC,		0xe0
.set N_BCOMM,		0xe2
.set N_ECOMM,		0xe4
.set N_ECOML,		0xe8
.set N_WITH,		0xea
.set N_NBTEXT,		0xf0
.set N_NBDATA,		0xf2
.set N_NBBSS,		0xf4
.set N_NBSTS,		0xf6
.set N_NBLCS,		0xf8

Beschreibung der STABS

Definition von Typen

(String-Field) Type 1 = void und Type 2 = int.

.stabs "void:t1=1",N_LSYM,0,0,0
.stabs "int:t2=r2;-2147483648;2147483647;",N_LSYM,0,0,0

Definition von globalen Variablen

(Global Variables) Variable targetCommand an Adresse 0x100000 vom Type 2 = int.

.data
.org 0x100000
.stabs "targetCommand:G2",N_GSYM,0,0,0
.global targetCommand
targetCommand:
.int 0

Definition vom Java-Sourcecode

(Source Files) Der erste STABS mit N_SO ist der Build-Ordner. Der Zweite ist der relative Pfad zum Source-File.

.org 0x400100
.stabs "/home/abajric/ntb/deep/ws/runtime-library/",N_SO,0,0,Ltext0
.stabs "src/ch/ntb/inf/deep/runtime/mpc555/Reset.java",N_SO,0,0,Ltext0
.text
Ltext0:

Definition von Zeilennummern

(Line Numbers)

reset:
.stabn N_SLINE, 0, 38, LM1
LM1:

...

.stabn N_SLINE, 0, 41, LM5
LM6:

...

.stabn N_SLINE, 0, 47, LM4
LM4:

Definition von Registervariablen

(Register Variables) Registervariablen müssen immer im gleichen Register bleiben. („r2“ ⇒ Registervariable vom Type 2 und nicht Register R2, Registernummer ist der letzte Parameter!)

.stabs "x:r2;-2147483648;2147483647;",N_RSYM,0,4,2

Definition von Funktionen

(Procedures) N_LBRAC und N_RBRAC ist die Position der öffnenden/schliessenden geschweiften Klammern der Funktion.

.stabs "ch::ntb::inf::deep::runtime::mpc555::Reset::reset:F1",N_FUN,0,0,reset
.stabn N_SLINE, 0, 37, reset
.stabn N_LBRAC, 0, 0, LM1
.stabn N_RBRAC, 0, 0, LM3

Debuggen mit GDB

Damit ein PowerPC Target debugged werden kann muss GDB mit PowerPC Support installiert werden:

$ sudo apt-get install gdb-multiarch

Bevor GDB gestarted wird, muss das Image-File auf den MPC5200 geladen werden:

$ telnet bdi3000inf01
pcm5200io> load 0x400000 pub/abajric/test.bin bin
pcm5200io> rm pc 0x400100

GDB starten:

$ gdb-multiarch

PowerPC Architektur auswählen:

(gdb) set arch powerpc:common

ELF-File mit Debug-Informationen auswählen:

(gdb) file ./a.out

GDB mit Abatron BDI3000 verbinden:

(gdb) target remote bdi3000inf01:2001

GDB TUI aktivieren und Layout umstellen:

(gdb) layout split
(gdb) focus cmd

Alternativ kann ein File (gdb.cmd) mit diesen GDB-Kommandos erstellt werden:

set arch powerpc:common
file ./a.out
target remote bdi3000inf01:2001
layout split
focus cmd

Beim Ausführen von GDB muss dieses File angegeben werden, damit alle Kommandos im File ausgeführt werden:

$ gdb-multiarch -x ./gdb.cmd

Mit dem folgenden Befehl kann der Java-Sourcecode angezeigt werden:

(gdb) list

Mit dem folgenden Befehl wird eine Assembler-Instruktion ausgeführt:

(gdb) stepi

Mit dem folgenden Befehl wird Code ausgeführt, bis eine neue Source-Zeile erreicht wurde:

(gdb) next

Mit dem folgenden Befehl wird eine definierte Variable ausgegeben:

(gdb) print x

Mit dem folgenden Befehl wird eine definierte Variable geändert:

(gdb) set var x = 12345

Mit dem folgenden Befehl kann im Memory geschrieben werden:

(gdb) set var *0x100000 = 12345