II-INF3-HOME

  1. Einführung

  2. Die Sicht des Programmierers

  3. Der GNU Debugger gdb

    1. gdb run und list

    2. Breakpoints und Print, Display

    3. Der Stack

    4. Die Register

  4. Testfragen und Übungen


II-INFORMATIK3 WS04
VL4: Von C zu Assembler zu Binaerkode

    Achtung : Skript gibt den mündlichen Vortrag nur teilweise wieder !!!
                        

AUTHOR: Gerd Döben-Henisch
DATE OF FIRST GENERATION: Oct-8, 2004
DATE OF LAST CHANGE: Oct-31, 2004, 22:01h
EMAIL: doeben_at_fb2.fh-frankfurt.de



1. Einführung

Bei der Arbeit mit dem exzellenten Buch von [BRYANT 2003] stellte sich leider erst jetzt heraus, dass der Y86-Simulator in seiner aktuellen Version unter den neueren SuSe-Versionen nicht so funktioniert, wie es für die Vorlesung notwendig wäre. Dies bedeutet, dass die Durcharbeitung der Y86-Prozessorarchitektur nicht so vorgenommen werden kann, wie geplant. Es besteht zwar zur Zeit eine lebhafte email-Korrespondenz mit dem Autor Randy Bryant über das Problem; aber bislang konnte bzgl. des SW-Einsatzes noch keine brauchbaren Ergebnisse erzielt werden. Es ist allerdings zu erwarten, dass das Problem in den naechsten Wochen geloest wird.

Für die aktuell laufende Vorlesung heisst dies aber, dass der ursprüngliche Plan so nicht fortgeführt werden kann. In einem längeren Gespräch der Studenten mit dem Dozenten kristallisierte sich heraus, dass die überwältigende Mehrheit nicht den Javabasierten Ansatz mit dem Tanenbaum Simulator wählen will, sondern lieber mit dem C-basierten Ansatz des Buches [BRYANT 2003] weiterarbeiten will. Dies passt auch besser zu den übrigen systemnahen LVs. Es wurde daher ein neues Programm vereinbart, das den Zugang zur Hardware über einen C-Assembler-basierten Ansatz beibehält und in diesem Kontext Fragen der Hardwarearchitektur behandelt. Wir folgen hier dem Kap.3 von [BRYANT 2003]. Siehe dazu auch [BREY 2003] sowie die offiziellen Dokumente der Firma Intel.


START



2.Die Sicht des Programmierers

Nachdem der erste Plan gescheitert ist, die Funktionesweise der Hardware durch das Y86-Programmiermodell zu untersuchen, soll nun der Ansatz gewählt werden, dass die IA32-Architektur aus Sicht des IA32-Befehlssatzes untersucht wird. Dabei soll --analog dem Vorgehen von [BRYANT 2003]-- der IA32-Befehlssaatz immer auch von der Ebene eines C-Programms aus betrachtet werden.



c-ass-bin

C-Assembler-Binaer-ISA



Dies sei hier an einem Beispiel verdeutlicht. Als Ausgangspunkt nehmen wir zwei einfache C-Dateien. Eine main-Datei, die eine Funktion sum() aufruft und eine Datei mit dieser Funktion sum(). Beim Aufruf übergibt die main-Funktion der Funktion sum() zwei Argumente, die addiert werden. Das Ergebnis wird zurück geliefert.


/****************************
 *
 * bsp1_main.c
 *
 * idea: simple demo for calling a function
 *
 **********************************/


int main(){

  int accum = 0;

  accum = sum(1,3);

  return 0;

}


/****************************
 *
 * bsp1_sum.c
 *
 * idea: simple illustration
 *
 **********************************/



int sum(int x, int y){

  int t;

  t = x + y;

  return t;

}

Als nächstes kann man diesen c-Kode in IA32-Assemblerkode übersetzen. Dies lässt sich unter Linux mit dem gcc-Compiler bewerkstelligen, wenn man ihn mit der Option -S aufruft, also

gerd@kant:~/public_html/fh/II-INF3/II-INF3-TH/VL4> gcc -v -S bsp1_main.c bsp1_sum.c

Das Ergebnis sieht dann wie folgt aus:


	.file	"bsp1_main.c"
	.text
.globl main
	.type	main, @function
main:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$8, %esp
	andl	$-16, %esp
	movl	$0, %eax
	subl	%eax, %esp
	movl	$0, -4(%ebp)
	subl	$8, %esp
	pushl	$3
	pushl	$1
	call	sum
	addl	$16, %esp
	movl	%eax, -4(%ebp)
	movl	$0, %eax
	leave
	ret
	.size	main, .-main
	.section	.note.GNU-stack,"",@progbits
	.ident	"GCC: (GNU) 3.3.3 (SuSE Linux)"


	.file	"bsp1_sum.c"
	.text
.globl sum
	.type	sum, @function
sum:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$4, %esp
	movl	12(%ebp), %eax
	addl	8(%ebp), %eax
	movl	%eax, -4(%ebp)
	movl	-4(%ebp), %eax
	leave
	ret
	.size	sum, .-sum
	.section	.note.GNU-stack,"",@progbits
	.ident	"GCC: (GNU) 3.3.3 (SuSE Linux)"

Man kann zwar erkennen, dass es sich irgendwie um Assemblerkode handelt, da die IA32-Befehle aber noch nicht explizit behandelt wurden, ist dieser Kode an dieser Stelle noch unverständlich. Untersuchen wir es weiter.

Assemblerkode ist ja, wie bekannt, noch nicht jenes Format, was dann tatsaechlich von einem Mikroprozessor verstanden werden kann. Die Welt des Mikroprozessors besteht nur aus 1en und 0en, dem Binärkode. Es muss also der Assemblerkode noch weiter übersetzt werden, bis er als eine Folge von 1en und 0en vorliegt. Dies kann man mit dem Compiler gcc erreichen, wenn man garkeine Option angibt. Dann werden die Dateien, die man als Argumente übergibt, in Binärkode übersetzt und zugleich noch mittels des Linkers automatich zu einem einzigen ausführbaren Kode zusammengebunden, also:

gerd@kant:~/public_html/fh/II-INF3/II-INF3-TH/VL4> gcc -o bsp1 bsp1_main.s bsp1_sum.s

Als Ergebnis liegt die ausführbare Datei "bsp1" vor (der Name wurde mit der Option -o erzwungen). Dieser Kode besteht jetzt nur noch aus einer Folge von 1en und 0en, die ein IA32-Prozessor nun direkt lesen könnte. Um das Format dieses Kodes einigermassen lesbar zu machen, gibt es unter Linux den Befehl objdump:

gerd@kant:~/public_html/fh/II-INF3/II-INF3-TH/VL4> objdump -d bsp1


bsp1:     file format elf32-i386

Disassembly of section .init:

08048264 <_init>:
 8048264:	55                   	push   %ebp
 8048265:	89 e5                	mov    %esp,%ebp
 8048267:	83 ec 08             	sub    $0x8,%esp
 804826a:	e8 55 00 00 00       	call   80482c4 <call_gmon_start>
 804826f:	e8 bc 00 00 00       	call   8048330 <frame_dummy>
 8048274:	e8 f7 01 00 00       	call   8048470 <__do_global_ctors_aux>
 8048279:	c9                   	leave  
 804827a:	c3                   	ret    
Disassembly of section .plt:

0804827c <.plt>:
 804827c:	ff 35 a8 95 04 08    	pushl  0x80495a8
 8048282:	ff 25 ac 95 04 08    	jmp    *0x80495ac
 8048288:	00 00                	add    %al,(%eax)
 804828a:	00 00                	add    %al,(%eax)
 804828c:	ff 25 b0 95 04 08    	jmp    *0x80495b0
 8048292:	68 00 00 00 00       	push   $0x0
 8048297:	e9 e0 ff ff ff       	jmp    804827c <_init+0x18>
Disassembly of section .text:

080482a0 <_start>:
 80482a0:	31 ed                	xor    %ebp,%ebp
 80482a2:	5e                   	pop    %esi
 80482a3:	89 e1                	mov    %esp,%ecx
 80482a5:	83 e4 f0             	and    $0xfffffff0,%esp
 80482a8:	50                   	push   %eax
 80482a9:	54                   	push   %esp
 80482aa:	52                   	push   %edx
 80482ab:	68 a0 83 04 08       	push   $0x80483a0
 80482b0:	68 10 84 04 08       	push   $0x8048410
 80482b5:	51                   	push   %ecx
 80482b6:	56                   	push   %esi
 80482b7:	68 5c 83 04 08       	push   $0x804835c
 80482bc:	e8 cb ff ff ff       	call   804828c <_init+0x28>
 80482c1:	f4                   	hlt    
 80482c2:	90                   	nop    
 80482c3:	90                   	nop    

080482c4 <call_gmon_start>:
 80482c4:	55                   	push   %ebp
 80482c5:	89 e5                	mov    %esp,%ebp
 80482c7:	53                   	push   %ebx
 80482c8:	e8 00 00 00 00       	call   80482cd <call_gmon_start+0x9>
 80482cd:	5b                   	pop    %ebx
 80482ce:	81 c3 d7 12 00 00    	add    $0x12d7,%ebx
 80482d4:	52                   	push   %edx
 80482d5:	8b 83 10 00 00 00    	mov    0x10(%ebx),%eax
 80482db:	85 c0                	test   %eax,%eax
 80482dd:	74 02                	je     80482e1 <call_gmon_start+0x1d>
 80482df:	ff d0                	call   *%eax
 80482e1:	58                   	pop    %eax
 80482e2:	5b                   	pop    %ebx
 80482e3:	c9                   	leave  
 80482e4:	c3                   	ret    
 80482e5:	90                   	nop    
 80482e6:	90                   	nop    
 80482e7:	90                   	nop    
 80482e8:	90                   	nop    
 80482e9:	90                   	nop    
 80482ea:	90                   	nop    
 80482eb:	90                   	nop    
 80482ec:	90                   	nop    
 80482ed:	90                   	nop    
 80482ee:	90                   	nop    
 80482ef:	90                   	nop    

080482f0 <__do_global_dtors_aux>:
 80482f0:	55                   	push   %ebp
 80482f1:	89 e5                	mov    %esp,%ebp
 80482f3:	50                   	push   %eax
 80482f4:	50                   	push   %eax
 80482f5:	80 3d b8 95 04 08 00 	cmpb   $0x0,0x80495b8
 80482fc:	75 2e                	jne    804832c <__do_global_dtors_aux+0x3c>
 80482fe:	a1 c0 94 04 08       	mov    0x80494c0,%eax
 8048303:	8b 10                	mov    (%eax),%edx
 8048305:	85 d2                	test   %edx,%edx
 8048307:	74 1c                	je     8048325 <__do_global_dtors_aux+0x35>
 8048309:	8d b4 26 00 00 00 00 	lea    0x0(%esi),%esi
 8048310:	83 c0 04             	add    $0x4,%eax
 8048313:	a3 c0 94 04 08       	mov    %eax,0x80494c0
 8048318:	ff d2                	call   *%edx
 804831a:	a1 c0 94 04 08       	mov    0x80494c0,%eax
 804831f:	8b 10                	mov    (%eax),%edx
 8048321:	85 d2                	test   %edx,%edx
 8048323:	75 eb                	jne    8048310 <__do_global_dtors_aux+0x20>
 8048325:	c6 05 b8 95 04 08 01 	movb   $0x1,0x80495b8
 804832c:	c9                   	leave  
 804832d:	c3                   	ret    
 804832e:	89 f6                	mov    %esi,%esi

08048330 <frame_dummy>:
 8048330:	55                   	push   %ebp
 8048331:	89 e5                	mov    %esp,%ebp
 8048333:	51                   	push   %ecx
 8048334:	51                   	push   %ecx
 8048335:	8b 15 a0 95 04 08    	mov    0x80495a0,%edx
 804833b:	85 d2                	test   %edx,%edx
 804833d:	74 19                	je     8048358 <frame_dummy+0x28>
 804833f:	b8 00 00 00 00       	mov    $0x0,%eax
 8048344:	85 c0                	test   %eax,%eax
 8048346:	74 10                	je     8048358 <frame_dummy+0x28>
 8048348:	83 ec 0c             	sub    $0xc,%esp
 804834b:	68 a0 95 04 08       	push   $0x80495a0
 8048350:	e8 ab 7c fb f7       	call   0 <_init-0x8048264>
 8048355:	83 c4 10             	add    $0x10,%esp
 8048358:	c9                   	leave  
 8048359:	c3                   	ret    
 804835a:	90                   	nop    
 804835b:	90                   	nop    

0804835c <main>:
 804835c:	55                   	push   %ebp
 804835d:	89 e5                	mov    %esp,%ebp
 804835f:	83 ec 08             	sub    $0x8,%esp
 8048362:	83 e4 f0             	and    $0xfffffff0,%esp
 8048365:	b8 00 00 00 00       	mov    $0x0,%eax
 804836a:	29 c4                	sub    %eax,%esp
 804836c:	c7 45 fc 00 00 00 00 	movl   $0x0,0xfffffffc(%ebp)
 8048373:	83 ec 08             	sub    $0x8,%esp
 8048376:	6a 03                	push   $0x3
 8048378:	6a 01                	push   $0x1
 804837a:	e8 0d 00 00 00       	call   804838c <sum>
 804837f:	83 c4 10             	add    $0x10,%esp
 8048382:	89 45 fc             	mov    %eax,0xfffffffc(%ebp)
 8048385:	b8 00 00 00 00       	mov    $0x0,%eax
 804838a:	c9                   	leave  
 804838b:	c3                   	ret    

0804838c <sum>:
 804838c:	55                   	push   %ebp
 804838d:	89 e5                	mov    %esp,%ebp
 804838f:	83 ec 04             	sub    $0x4,%esp
 8048392:	8b 45 0c             	mov    0xc(%ebp),%eax
 8048395:	03 45 08             	add    0x8(%ebp),%eax
 8048398:	89 45 fc             	mov    %eax,0xfffffffc(%ebp)
 804839b:	8b 45 fc             	mov    0xfffffffc(%ebp),%eax
 804839e:	c9                   	leave  
 804839f:	c3                   	ret    

080483a0 <__libc_csu_fini>:
 80483a0:	55                   	push   %ebp
 80483a1:	89 e5                	mov    %esp,%ebp
 80483a3:	83 ec 18             	sub    $0x18,%esp
 80483a6:	89 5d f4             	mov    %ebx,0xfffffff4(%ebp)
 80483a9:	e8 ba 00 00 00       	call   8048468 <__i686.get_pc_thunk.bx>
 80483ae:	81 c3 f6 11 00 00    	add    $0x11f6,%ebx
 80483b4:	89 7d fc             	mov    %edi,0xfffffffc(%ebp)
 80483b7:	8d 83 14 ff ff ff    	lea    0xffffff14(%ebx),%eax
 80483bd:	8d bb 14 ff ff ff    	lea    0xffffff14(%ebx),%edi
 80483c3:	89 75 f8             	mov    %esi,0xfffffff8(%ebp)
 80483c6:	29 f8                	sub    %edi,%eax
 80483c8:	c1 f8 02             	sar    $0x2,%eax
 80483cb:	85 c0                	test   %eax,%eax
 80483cd:	8d 70 ff             	lea    0xffffffff(%eax),%esi
 80483d0:	75 12                	jne    80483e4 <__libc_csu_fini+0x44>
 80483d2:	e8 bd 00 00 00       	call   8048494 <_fini>
 80483d7:	8b 5d f4             	mov    0xfffffff4(%ebp),%ebx
 80483da:	8b 75 f8             	mov    0xfffffff8(%ebp),%esi
 80483dd:	8b 7d fc             	mov    0xfffffffc(%ebp),%edi
 80483e0:	89 ec                	mov    %ebp,%esp
 80483e2:	5d                   	pop    %ebp
 80483e3:	c3                   	ret    
 80483e4:	ff 14 b7             	call   *(%edi,%esi,4)
 80483e7:	89 f0                	mov    %esi,%eax
 80483e9:	4e                   	dec    %esi
 80483ea:	85 c0                	test   %eax,%eax
 80483ec:	75 f6                	jne    80483e4 <__libc_csu_fini+0x44>
 80483ee:	89 f6                	mov    %esi,%esi
 80483f0:	e8 9f 00 00 00       	call   8048494 <_fini>
 80483f5:	8b 5d f4             	mov    0xfffffff4(%ebp),%ebx
 80483f8:	8b 75 f8             	mov    0xfffffff8(%ebp),%esi
 80483fb:	8b 7d fc             	mov    0xfffffffc(%ebp),%edi
 80483fe:	89 ec                	mov    %ebp,%esp
 8048400:	5d                   	pop    %ebp
 8048401:	c3                   	ret    
 8048402:	8d b4 26 00 00 00 00 	lea    0x0(%esi),%esi
 8048409:	8d bc 27 00 00 00 00 	lea    0x0(%edi),%edi

08048410 <__libc_csu_init>:
 8048410:	55                   	push   %ebp
 8048411:	89 e5                	mov    %esp,%ebp
 8048413:	83 ec 18             	sub    $0x18,%esp
 8048416:	89 5d f4             	mov    %ebx,0xfffffff4(%ebp)
 8048419:	89 75 f8             	mov    %esi,0xfffffff8(%ebp)
 804841c:	31 f6                	xor    %esi,%esi
 804841e:	e8 45 00 00 00       	call   8048468 <__i686.get_pc_thunk.bx>
 8048423:	81 c3 81 11 00 00    	add    $0x1181,%ebx
 8048429:	89 7d fc             	mov    %edi,0xfffffffc(%ebp)
 804842c:	e8 33 fe ff ff       	call   8048264 <_init>
 8048431:	8d 93 14 ff ff ff    	lea    0xffffff14(%ebx),%edx
 8048437:	8d 83 14 ff ff ff    	lea    0xffffff14(%ebx),%eax
 804843d:	29 c2                	sub    %eax,%edx
 804843f:	c1 fa 02             	sar    $0x2,%edx
 8048442:	39 d6                	cmp    %edx,%esi
 8048444:	73 15                	jae    804845b <__libc_csu_init+0x4b>
 8048446:	89 45 f0             	mov    %eax,0xfffffff0(%ebp)
 8048449:	89 d7                	mov    %edx,%edi
 804844b:	90                   	nop    
 804844c:	8d 74 26 00          	lea    0x0(%esi),%esi
 8048450:	ff 14 b0             	call   *(%eax,%esi,4)
 8048453:	46                   	inc    %esi
 8048454:	8b 45 f0             	mov    0xfffffff0(%ebp),%eax
 8048457:	39 fe                	cmp    %edi,%esi
 8048459:	72 f5                	jb     8048450 <__libc_csu_init+0x40>
 804845b:	8b 5d f4             	mov    0xfffffff4(%ebp),%ebx
 804845e:	8b 75 f8             	mov    0xfffffff8(%ebp),%esi
 8048461:	8b 7d fc             	mov    0xfffffffc(%ebp),%edi
 8048464:	89 ec                	mov    %ebp,%esp
 8048466:	5d                   	pop    %ebp
 8048467:	c3                   	ret    

08048468 <__i686.get_pc_thunk.bx>:
 8048468:	8b 1c 24             	mov    (%esp),%ebx
 804846b:	c3                   	ret    
 804846c:	90                   	nop    
 804846d:	90                   	nop    
 804846e:	90                   	nop    
 804846f:	90                   	nop    

08048470 <__do_global_ctors_aux>:
 8048470:	55                   	push   %ebp
 8048471:	89 e5                	mov    %esp,%ebp
 8048473:	53                   	push   %ebx
 8048474:	52                   	push   %edx
 8048475:	bb 90 95 04 08       	mov    $0x8049590,%ebx
 804847a:	a1 90 95 04 08       	mov    0x8049590,%eax
 804847f:	83 f8 ff             	cmp    $0xffffffff,%eax
 8048482:	74 0c                	je     8048490 <__do_global_ctors_aux+0x20>
 8048484:	83 eb 04             	sub    $0x4,%ebx
 8048487:	ff d0                	call   *%eax
 8048489:	8b 03                	mov    (%ebx),%eax
 804848b:	83 f8 ff             	cmp    $0xffffffff,%eax
 804848e:	75 f4                	jne    8048484 <__do_global_ctors_aux+0x14>
 8048490:	58                   	pop    %eax
 8048491:	5b                   	pop    %ebx
 8048492:	5d                   	pop    %ebp
 8048493:	c3                   	ret    
Disassembly of section .fini:

08048494 <_fini>:
 8048494:	55                   	push   %ebp
 8048495:	89 e5                	mov    %esp,%ebp
 8048497:	53                   	push   %ebx
 8048498:	e8 00 00 00 00       	call   804849d <_fini+0x9>
 804849d:	5b                   	pop    %ebx
 804849e:	81 c3 07 11 00 00    	add    $0x1107,%ebx
 80484a4:	50                   	push   %eax
 80484a5:	e8 46 fe ff ff       	call   80482f0 <__do_global_dtors_aux>
 80484aa:	59                   	pop    %ecx
 80484ab:	5b                   	pop    %ebx
 80484ac:	c9                   	leave  
 80484ad:	c3                   	ret    

In dieser Darstellung kann man in der linken Spalte absolute Adressen von Speicherzellen erkennen. In der zweiten Sektion findet man Bytefolgen im Hex-Format, die den eigentlichen Objektkodecrepräsentieren. Rechts davon finden sich nochmals die Assemblerbefehle, die diese Bytefolgen kodieren.

In den nächsten Schritten soll erläutert werden, wie man solchen Kode interpretieren kann. Dieses Verständnis soll dabei über den eigentlichen Kode hinausgehen und mittels des Kodes einen Einblick in die zugrundeliegende Hardware vermitteln. Um dies tun zu können benötigt man die Möglichkeit, den jeweiligen Kode in Verbindung mit der Hardware anschauen zu können, d.h. die Register der CPU sowie der Stack-Speicher, der benutzt wird. Diess Werkzeug ist der GNU Debugger gdb.

Der GNU Debuger gdb wird hier kurz eingeführt; anschliessend wird die IA32-Architektur beschrieben.


START



3. Der GNU Debugger gdb

Eine sehr ausführliche Information zum GNU Debugger --z.T. mit Beispielen-- findet sich unter Linux mit dem Befehl

 info gdb
 

Im folgenden stellen wir nur die Befehle und Optionen vor, die wir für die nächsten Schritte benötigen.

Der GNU Debugger gdb ist ein exzellentes Stück opensource Software verbunden mit einer entsprechenden opensource Dokumentation. Im vollen Umfang unterstützt er die Sprachen C und C++; andere Sprachen nur zum Teil. Der Debugger erlaubt es einem Softwareentwickler, die Abarbeitung eines Programms auf der Hardware in --nahezu-- allen Aspekten zu kontrollieren, um auf diese Weise Fehler aufzuspüren.

Will man ein Programm mit dem Debugger gdb debuggen, dann muss man es zuvor mit der Option -g kompiliert haben. Das soll jetzt mit den beiden kleinen Beispielprogrammen nachgeholt werden:

 
gerd@kant:~/public_html/fh/II-INF3/II-INF3-TH/VL4> gcc -g -o bsp1 bsp1_main.c bsp1_sum.c

 

gdb run und list

Will man sich die Arbeitsweise eines normalen Programms anschauen, dann reicht es, wenn man beim Aufruf von gdb einfach dieses Namen angibt. Ist das Programm wegen eines Fehlers abgestürzt und es wurde ein sogenannter core dump erzeut, dann kann man diesen mit angeben und es wird gleich die Stelle angezeigt, an der das Programm abgestürzt ist. Wir betrachten hier erst den einfachen Fall ohne core dump:

 
gerd@kant:~/public_html/fh/II-INF3/II-INF3-TH/VL4> gdb bsp1
GNU gdb 6.1
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i586-suse-linux"...Using host libthread_db library "/lib/tls/libthread_db.so.1".
(gdb)
 

Den Programmkode kann man mit dem Befehl list [l] anzeigen lassen, dazu einige weitere Optionen:

 (gdb) l
3        * bsp1_main.c
4        *
5        * idea: simple demo for calling a function
6        *
7        **********************************/
8
9
10      int main(){
11
12        int accum = 0;
(gdb) l
13
14        accum = sum(1,3);
15
16        return 0;
17
18      }
(gdb) l -16
1       /****************************
2        *
3        * bsp1_main.c
4        *
5        * idea: simple demo for calling a function
6        *
7        **********************************/
8
9
10      int main(){
(gdb) l
11
12        int accum = 0;
13
14        accum = sum(1,3);
15
16        return 0;
17
18      }
(gdb) l sum
6        *
7        **********************************/
8
9
10
11      int sum(int x, int y){
12
13        int t;
14
15        t = x + y;
(gdb) l
16
17        return t;
18
19      }
(gdb)
 

Man kann hier sehen, wie man mit l zunächst 10 Zeilen des Quelltextes von main() angezeigt bekommt; mit einem weiteren l die nächsten Zeilen. Ist man bei Zeile 16 angekommen und man gibt l -16 ein, dann dann werden die letzten 16 Zeilen vor dem aktuellen Punkt angezeigt, allerdings momentan nur 10 auf einmal. Gibt man l Funktionsname ein, dann wird die Funktion aufgelistet. Hier die wichtigsten Befehle aus der GNU-info-Datei:


`list LINENUM'
     Print lines centered around line number LINENUM in the current
     source file.

`list FUNCTION'
     Print lines centered around the beginning of function FUNCTION.

`list'
     Print more lines.  If the last lines printed were printed with a
     `list' command, this prints lines following the last lines
     printed; however, if the last line printed was a solitary line
     printed as part of displaying a stack frame (*note Examining the
     Stack: Stack.), this prints lines centered around that line.

`list -'
     Print lines just before the lines last printed.

   By default, GDB prints ten source lines with any of these forms of
the `list' command.  You can change this using `set listsize':

`set listsize COUNT'
     Make the `list' command display COUNT source lines (unless the
     `list' argument explicitly specifies some other number).

`show listsize'
     Display the number of lines that `list' prints.
 Repeating a `list' command with <RET> discards the argument, so it
is equivalent to typing just `list'.  This is more useful than listing
the same lines again.  An exception is made for an argument of `-';
that argument is preserved in repetition so that each repetition moves
up in the source file.

 

Es soll jetzt das Programm zunächst einmal ganz nomal mit dem Befehl run [r] gestarttet werden:



(gdb) r
Starting program: /home/gerd/public_html/fh/II-INF3/II-INF3-TH/VL4/bsp1

Program exited normally.
(gdb)
  

START



Breakpoints und Print, Display

Das Programm startet und wird beendet, ohne dass weitere Informationen ausgegeben werden. Will man mehr wissen, dann muss man in das Programm hineinschauen. Zu diesem Zweck kann man sogenannte breakpoints [b] (Unterbrechungspunkte, Haltepunkte) festlegen, an denen das Programm anhalten soll.

Im folgenden Beispiel wird nach Aufruf des Debuggers mit dem Programm bsp1 als Argument zuerst die Anzahl der zu zeigenden Zeilen auf 25 gesetzt:

gerd@kant:~/public_html/fh/II-INF3/II-INF3-TH/VL4> gdb bsp1
GNU gdb 6.1
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i586-suse-linux"...Using host libthread_db library "/lib/tls/libthread_db.so.1".

(gdb) set listsize 25
(gdb) l
1       /****************************
2        *
3        * bsp1_main.c
4        *
5        * idea: simple demo for calling a function
6        *
7        **********************************/
8
9
10      int main(){
11
12        int accum = 0;
13
14        accum = sum(1,3);
15
16        return 0;
17
18      }

Dann wird ein erster Breakpoint in Zeile 14 gesetzt:

 
(gdb) b 14
Breakpoint 1 at 0x8048373: file bsp1_main.c, line 14.

Dann wird der Quelltext der funktion sum ausgelistet:

(gdb) l sum
1       /****************************
2        *
3        * bsp1_sum.c
4        *
5        * idea: simple illustration
6        *
7        **********************************/
8
9
10
11      int sum(int x, int y){
12
13        int t;
14
15        t = x + y;
16
17        return t;
18
19      }

Auch in diesem Quelltext wird ein Breakpoint gesetzt:

(gdb) b 13
Breakpoint 2 at 0x8048392: file bsp1_sum.c, line 13.

Schliesslich wird der Quelltext der Funktion main() nochmals gelistet und darin ein Breakpoint in Zeile 16 gesetzt:

(gdb) l main
1       /****************************
2        *
3        * bsp1_main.c
4        *
5        * idea: simple demo for calling a function
6        *
7        **********************************/
8
9
10      int main(){
11
12        int accum = 0;
13
14        accum = sum(1,3);
15
16        return 0;
17
18      }
(gdb) b 16
Breakpoint 3 at 0x8048385: file bsp1_main.c, line 16.
(gdb)
 

Lässt man das programm nun mit run [r] ablaufen, dann hält der Programmlauf jeweils in der Zeile des Haltepunktes an:

(gdb) r
Starting program: /home/gerd/public_html/fh/II-INF3/II-INF3-TH/VL4/bsp1

Breakpoint 1, main () at bsp1_main.c:14
14        accum = sum(1,3);

Will man wissen, welchen Wert die jeweiligen Variablen haben, kann man sich den Wert z.B. mit dem Befehl print [p] anzeigen lassen:

(gdb) p accum
$1 = 0

Wie man sehen kann, hat die Variable accum an dieser Stelle noch ihren startwert, da die Funktion sum zur Berechnung eines neuen Wertes noch nichtausgeführt worden ist. Den Programmlauf cann man mit dem Befehl continue [c] fortsetzen.

(gdb) c
Continuing.

Breakpoint 2, sum (x=1, y=3) at bsp1_sum.c:15
15        t = x + y;

Wieder kann man sich die Werte der Variablen anzeigen lassen:

(gdb) p x
$2 = 1
(gdb) p y
$3 = 3
(gdb) p t
$4 = -1073746076

Während die Variablen x und y schon einen Wert aufgrund des Funktionsaufrufs haben, hat die Variable t noch keinen definierten Wert, da die Addition noch nicht durchgeführt worden ist. Fortsetzung mit 'c':

(gdb) c
Continuing.

Breakpoint 3, main () at bsp1_main.c:16
16        return 0;
(gdb) p accum
$5 = 4
(gdb) c
Continuing.

Program exited normally.
 

Wie man erkennen kann, hat die Variable accum schliesslich den Wert, den man erwartet.

Um Breakpoints zu verwalten, stehen einige Befehle zur Verfügung. Hier die wichtigsten.

Hat man mehrere breakpoints gesetzt, dann kann es hilfreich sein, sich alle breakpoints anzeigen zu lassen, um den Übergblick zu wahren. Dazu gibnt es den Befehl info:

(gdb) info breakpoints
Num Type           Disp Enb Address    What
1   breakpoint     keep y   0x08048373 in main at bsp1_main.c:14
        breakpoint already hit 1 time
2   breakpoint     keep y   0x08048392 in sum at bsp1_sum.c:13
        breakpoint already hit 1 time
3   breakpoint     keep y   0x08048385 in main at bsp1_main.c:16
        breakpoint already hit 1 time

Will man aus dieser Liste einen Breakpoint löschen, kann man den Befehl delete benutzen gefolgt von der Nr. des zu löschen Breakpoints:

(gdb) delete 1
(gdb) info breakpoints
Num Type           Disp Enb Address    What
2   breakpoint     keep y   0x08048392 in sum at bsp1_sum.c:13
        breakpoint already hit 1 time
3   breakpoint     keep y   0x08048385 in main at bsp1_main.c:16
        breakpoint already hit 1 time

Man kann aber auch einen Breakpoint auch nur vorübergehend, zeitweise neutralisieren, indem man ihn mit dem Befehl disable abschaltet:

(gdb) disable 2
(gdb) info breakpoints
Num Type           Disp Enb Address    What
2   breakpoint     keep n   0x08048392 in sum at bsp1_sum.c:13
        breakpoint already hit 1 time
3   breakpoint     keep y   0x08048385 in main at bsp1_main.c:16
        breakpoint already hit 1 time
(gdb) r
Starting program: /home/gerd/public_html/fh/II-INF3/II-INF3-TH/VL4/bsp1

Breakpoint 3, main () at bsp1_main.c:16
16        return 0;
(gdb) info breakpoints
Num Type           Disp Enb Address    What
2   breakpoint     keep n   0x08048392 in sum at bsp1_sum.c:13
3   breakpoint     keep y   0x08048385 in main at bsp1_main.c:16
        breakpoint already hit 1 time

Die Reaktivierung eines vorübergehend ausgeschalteten Haltepunkts gelingt wieder mit dem Befehl enable:

(gdb) enable 2
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/gerd/public_html/fh/II-INF3/II-INF3-TH/VL4/bsp1

Breakpoint 2, sum (x=1, y=3) at bsp1_sum.c:15
15        t = x + y;
(gdb) c
Continuing.

Breakpoint 3, main () at bsp1_main.c:16
16        return 0;
(gdb) info breakpoints
Num Type           Disp Enb Address    What
2   breakpoint     keep y   0x08048392 in sum at bsp1_sum.c:13
        breakpoint already hit 1 time
3   breakpoint     keep y   0x08048385 in main at bsp1_main.c:16
        breakpoint already hit 1 time
(gdb) delete 2
(gdb) delete 3
(gdb) info breakpoints
No breakpoints or watchpoints.
(gdb) c
Continuing.

Program exited normally.
(gdb)
 

Will man sich den Inhalt einer Variablen automatisch anzeigen lassen, dann kann man den Befehl display benutzen. Zuerst setzt man einen Breakpoint auf die Stelle, bei der man eine bestimmte Variable abfragen kann, dann gibt man den Befehl display mit dieser Variablen an, und dann kann man das Programm laufen lassen:

 
(gdb) l
4        *
5        * idea: simple demo for calling a function
6        *
7        **********************************/
8
9
10      int main(){
11
12        int accum = 0;
13
14        accum = sum(1,3);
15
16        return 0;
17
18      }
(gdb) b 16
Breakpoint 4 at 0x8048385: file bsp1_main.c, line 16.
(gdb) r
Starting program: /home/gerd/public_html/fh/II-INF3/II-INF3-TH/VL4/bsp1

Breakpoint 4, main () at bsp1_main.c:16
16        return 0;
(gdb) display accum
1: accum = 4
(gdb) c
Continuing.

Program exited normally.
(gdb) r
Starting program: /home/gerd/public_html/fh/II-INF3/II-INF3-TH/VL4/bsp1

Breakpoint 4, main () at bsp1_main.c:16
16        return 0;
1: accum = 4
(gdb) c
Continuing.

Program exited normally.
(gdb) r
Starting program: /home/gerd/public_html/fh/II-INF3/II-INF3-TH/VL4/bsp1

Breakpoint 4, main () at bsp1_main.c:16
16        return 0;
1: accum = 4

 

START



Der Stack

Der Debugger gdb bietet auch die Möglichkeit, sich den aktuellen Stack mit dem Befehl backtrace [bt] anzuschauen. Im info-text heisst es dazu: Each line in the backtrace shows the frame number and the function name. The program counter value is also shown--unless you use `set print address off'. The backtrace also shows the source file name and line number, as well as the arguments to the function. The program counter value is omitted if it is at the beginning of the code for that line number. Dazu ein Beispiel. Wir setzen in der funktion sum einen Breakpoint und rufen von dort den Stapel ab:


(gdb) r
Starting program: /home/gerd/public_html/fh/II-INF3/II-INF3-TH/VL4/bsp1

Breakpoint 3, sum (x=1, y=3) at bsp1_sum.c:17
17        return t;
(gdb) bt
#0  sum (x=1, y=3) at bsp1_sum.c:17
#1  0x0804837f in main () at bsp1_main.c:14
(gdb) c
Continuing.

Program exited normally.

Man kann sehen, dass auf dem stack zu diesem Zeitpunkt zwei Funktionen liegen: die main()-Funktion als die Startfunktion eines C-Programms sowie die sum()-Funktion, die noch nicht beendet ist.

Innerhalb des Stacks kann man sich auch mit den Befehlen up und down hoch- oder runterbewegen:

(gdb) up
#1  0x0804837f in main () at bsp1_main.c:14
14        accum = sum(1,3);
(gdb) up
Initial frame selected; you cannot go up.
(gdb) down
#0  sum (x=1, y=3) at bsp1_sum.c:17
17        return t;
(gdb) down
Bottom (i.e., innermost) frame selected; you cannot go down.
 

Im info-File kann man zusaetzlich u.a. nachlesen:

`frame N'
`f N'
     Select frame number N.  Recall that frame zero is the innermost
     (currently executing) frame, frame one is the frame that called the
     innermost one, and so on.  The highest-numbered frame is the one
     for `main'.

`frame ADDR'
`f ADDR'
     Select the frame at address ADDR.  This is useful mainly if the
     chaining of stack frames has been damaged by a bug, making it
     impossible for GDB to assign numbers properly to all frames.  In
     addition, this can be useful when your program has multiple stacks
     and switches between them.

     On the SPARC architecture, `frame' needs two addresses to select
     an arbitrary frame: a frame pointer and a stack pointer.

     On the MIPS and Alpha architecture, it needs two addresses: a stack
     pointer and a program counter.

     On the 29k architecture, it needs three addresses: a register stack
     pointer, a program counter, and a memory stack pointer.

`up N'
     Move N frames up the stack.  For positive numbers N, this advances
     toward the outermost frame, to higher frame numbers, to frames
     that have existed longer.  N defaults to one.

`down N'
     Move N frames down the stack.  For positive numbers N, this
     advances toward the innermost frame, to lower frame numbers, to
     frames that were created more recently.  N defaults to one.  You
     may abbreviate `down' as `do'.

   All of these commands end by printing two lines of output describing
the frame.  The first line shows the frame number, the function name,
the arguments, and the source file and line number of execution in that
frame.  The second line shows the text of that source line.

...

There are several other commands to print information about the selected
stack frame.

`frame'
`f'
     When used without any argument, this command does not change which
     frame is selected, but prints a brief description of the currently
     selected stack frame.  It can be abbreviated `f'.  With an
     argument, this command is used to select a stack frame.  *Note
     Selecting a frame: Selection.

`info frame'
`info f'
     This command prints a verbose description of the selected stack
     frame, including:

        * the address of the frame

        * the address of the next frame down (called by this frame)

        * the address of the next frame up (caller of this frame)

        * the language in which the source code corresponding to this
          frame is written

        * the address of the frame's arguments

        * the address of the frame's local variables

        * the program counter saved in it (the address of execution in
          the caller frame)

        * which registers were saved in the frame
   The verbose description is useful when something has gone wrong
     that has made the stack format fail to fit the usual conventions.

`info frame ADDR'
`info f ADDR'
     Print a verbose description of the frame at address ADDR, without
     selecting that frame.  The selected frame remains unchanged by this
     command.  This requires the same kind of address (more than one
     for some architectures) that you specify in the `frame' command.
     *Note Selecting a frame: Selection.

`info args'
     Print the arguments of the selected frame, each on a separate line.

`info locals'
     Print the local variables of the selected frame, each on a separate
     line.  These are all variables (declared either static or
     automatic) accessible at the point of execution of the selected
     frame.

`info catch'
     Print a list of all the exception handlers that are active in the
     current stack frame at the current point of execution.  To see
     other exception handlers, visit the associated frame (using the
     `up', `down', or `frame' commands); then type `info catch'.  *Note
     Setting catchpoints: Set Catchpoints.

 

Wendet man diese zusätzlichen Befehle auf das beispiel an, dann erhält man zusätzliche Informationen:

(gdb) f 0
#0  sum (x=1, y=3) at bsp1_sum.c:17
17        return t;
(gdb) info frame
Stack level 0, frame at 0xbfffef60:
 eip = 0x804839b in sum (bsp1_sum.c:17); saved eip 0x804837f
 called by frame at 0xbfffef80
 source language c.
 Arglist at 0xbfffef58, args: x=1, y=3
 Locals at 0xbfffef58, Previous frame's sp is 0xbfffef60
 Saved registers:
  ebp at 0xbfffef58, eip at 0xbfffef5c
(gdb) down
Bottom (i.e., innermost) frame selected; you cannot go down.
(gdb) up
#1  0x0804837f in main () at bsp1_main.c:14
14        accum = sum(1,3);
(gdb) info frame
Stack level 1, frame at 0xbfffef80:
 eip = 0x804837f in main (bsp1_main.c:14); saved eip 0x40047500
 caller of frame at 0xbfffef60
 source language c.
 Arglist at 0xbfffef78, args:
 Locals at 0xbfffef78, Previous frame's sp is 0xbfffef80
 Saved registers:
  ebp at 0xbfffef78, eip at 0xbfffef7c

 

START



Die Register

Eine weitere interessante Möglichkeit ist die, sich die Inhalte der Register der CPU anzeigen zu lassen. Im info-File kann man lesen:

You can refer to machine register contents, in expressions, as variables
with names starting with `$'.  The names of registers are different for
each machine; use `info registers' to see the names used on your
machine.

`info registers'
     Print the names and values of all registers except floating-point
     and vector registers (in the selected stack frame).

`info all-registers'
     Print the names and values of all registers, including
     floating-point and vector registers (in the selected stack frame).

Wendet man diese Befehle an, erhält man im vorliegenden Kontext folgende Ausgaben:


(gdb) info registers
eax            0x4      4
ecx            0x400474c5       1074033861
edx            0x1      1
ebx            0x40143bd0       1075067856
esp            0xbfffef60       0xbfffef60
ebp            0xbfffef78       0xbfffef78
esi            0x400168c0       1073834176
edi            0x80483a0        134513568
eip            0x804837f        0x804837f
eflags         0x200202 2097666
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) info all-registers
eax            0x4      4
ecx            0x400474c5       1074033861
edx            0x1      1
ebx            0x40143bd0       1075067856
esp            0xbfffef60       0xbfffef60
ebp            0xbfffef78       0xbfffef78
esi            0x400168c0       1073834176
edi            0x80483a0        134513568
eip            0x804837f        0x804837f
eflags         0x200202 2097666
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
st0            0        (raw 0x00000000000000000000)
st1            0        (raw 0x00000000000000000000)
st2            0        (raw 0x00000000000000000000)
st3            0        (raw 0x00000000000000000000)
st4            0        (raw 0x00000000000000000000)
st5            0        (raw 0x00000000000000000000)
st6            0        (raw 0x00000000000000000000)
st7            0        (raw 0x00000000000000000000)
fctrl          0x37f    895
fstat          0x0      0
ftag           0xffff   65535
fiseg          0x0      0
fioff          0x0      0
foseg          0x0      0
fooff          0x0      0
fop            0x0      0
xmm0           {v4_float = {0x0, 0x0, 0x0, 0x0}, v2_double = {0x0, 0x0}, v16_int8 = {0x0 <repeats 16 times>}, v8_int16 = {0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0, 0x0}, v4_int32 = {0x0, 0x0, 0x0, 0x0}, v2_int64 = {0x0, 0x0}, uint128 = 0x00000000000000000000000000000000}
xmm1           {v4_float = {0x0, 0x0, 0x0, 0x0}, v2_double = {0x0, 0x0}, v16_int8 = {0x0 <repeats 16 times>}, v8_int16 = {0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0, 0x0}, v4_int32 = {0x0, 0x0, 0x0, 0x0}, v2_int64 = {0x0, 0x0}, uint128 = 0x00000000000000000000000000000000}
xmm2           {v4_float = {0x0, 0x0, 0x0, 0x0}, v2_double = {0x0, 0x0}, v16_int8 = {0x0 <repeats 16 times>}, v8_int16 = {0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0, 0x0}, v4_int32 = {0x0, 0x0, 0x0, 0x0}, v2_int64 = {0x0, 0x0}, uint128 = 0x00000000000000000000000000000000}
xmm3           {v4_float = {0x0, 0x0, 0x0, 0x0}, v2_double = {0x0, 0x0}, v16_int8 = {0x0 <repeats 16 times>}, v8_int16 = {0x0, 0x0, 0x0,
 
    0x0, 0x0, 0x0, 0x0, 0x0}, v4_int32 = {0x0, 0x0, 0x0, 0x0}, v2_int64 = {0x0, 0x0}, uint128 = 0x00000000000000000000000000000000}
xmm4           {v4_float = {0x0, 0x0, 0x0, 0x0}, v2_double = {0x0, 0x0}, v16_int8 = {0x0 <repeats 16 times>}, v8_int16 = {0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0, 0x0}, v4_int32 = {0x0, 0x0, 0x0, 0x0}, v2_int64 = {0x0, 0x0}, uint128 = 0x00000000000000000000000000000000}
xmm5           {v4_float = {0x0, 0x0, 0x0, 0x0}, v2_double = {0x0, 0x0}, v16_int8 = {0x0 <repeats 16 times>}, v8_int16 = {0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0, 0x0}, v4_int32 = {0x0, 0x0, 0x0, 0x0}, v2_int64 = {0x0, 0x0}, uint128 = 0x00000000000000000000000000000000}
xmm6           {v4_float = {0x0, 0x0, 0x0, 0x0}, v2_double = {0x0, 0x0}, v16_int8 = {0x0 <repeats 16 times>}, v8_int16 = {0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0, 0x0}, v4_int32 = {0x0, 0x0, 0x0, 0x0}, v2_int64 = {0x0, 0x0}, uint128 = 0x00000000000000000000000000000000}
xmm7           {v4_float = {0x0, 0x0, 0x0, 0x0}, v2_double = {0x0, 0x0}, v16_int8 = {0x0 <repeats 16 times>}, v8_int16 = {0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0, 0x0}, v4_int32 = {0x0, 0x0, 0x0, 0x0}, v2_int64 = {0x0, 0x0}, uint128 = 0x00000000000000000000000000000000}
mxcsr          0x1f80   8064
mm0            {uint64 = 0x0, v2_int32 = {0x0, 0x0}, v4_int16 = {0x0, 0x0, 0x0, 0x0}, v8_int8 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
mm1            {uint64 = 0x0, v2_int32 = {0x0, 0x0}, v4_int16 = {0x0, 0x0, 0x0, 0x0}, v8_int8 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
mm2            {uint64 = 0x0, v2_int32 = {0x0, 0x0}, v4_int16 = {0x0, 0x0, 0x0, 0x0}, v8_int8 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
mm3            {uint64 = 0x0, v2_int32 = {0x0, 0x0}, v4_int16 = {0x0, 0x0, 0x0, 0x0}, v8_int8 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
mm4            {uint64 = 0x0, v2_int32 = {0x0, 0x0}, v4_int16 = {0x0, 0x0, 0x0, 0x0}, v8_int8 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
mm5            {uint64 = 0x0, v2_int32 = {0x0, 0x0}, v4_int16 = {0x0, 0x0, 0x0, 0x0}, v8_int8 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
mm6            {uint64 = 0x0, v2_int32 = {0x0, 0x0}, v4_int16 = {0x0, 0x0, 0x0, 0x0}, v8_int8 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
mm7            {uint64 = 0x0, v2_int32 = {0x0, 0x0}, v4_int16 = {0x0, 0x0, 0x0, 0x0}, v8_int8 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
(gdb)

In der info-Datei kann man weiterhin lesen:

.....

   GDB has four "standard" register names that are available (in
expressions) on most machines--whenever they do not conflict with an
architecture's canonical mnemonics for registers.  The register names
`$pc' and `$sp' are used for the program counter register and the stack
pointer.  `$fp' is used for a register that contains a pointer to the
current stack frame, and `$ps' is used for a register that contains the
processor status.  For example, you could print the program counter in
hex with

     p/x $pc

or print the instruction to be executed next with


     x/i $pc

or add four to the stack pointer(1) with

     set $sp += 4

   Whenever possible, these four standard register names are available
on your machine even though the machine has different canonical
mnemonics, so long as there is no conflict.  The `info registers'
command shows the canonical names.  For example, on the SPARC, `info
registers' displays the processor status register as `$psr' but you can
also refer to it as `$ps'; and on x86-based machines `$ps' is an alias
for the EFLAGS register.

   GDB always considers the contents of an ordinary register as an
integer when the register is examined in this way.  Some machines have
special registers which can hold nothing but floating point; these
registers are considered to have floating point values.  There is no way
to refer to the contents of an ordinary register as floating point value
(although you can _print_ it as a floating point value with `print/f
$REGNAME').

   Some registers have distinct "raw" and "virtual" data formats.  This
means that the data format in which the register contents are saved by
the operating system is not the same one that your program normally
sees.  For example, the registers of the 68881 floating point
coprocessor are always saved in "extended" (raw) format, but all C
programs expect to work with "double" (virtual) format.  In such cases,
GDB normally works with the virtual format only (the format that makes
sense for your program), but the `info registers' command prints the
data in both formats.

   Normally, register values are relative to the selected stack frame
(*note Selecting a frame: Selection.).  This means that you get the
value that the register would contain if all stack frames farther in

were exited and their saved registers restored.  In order to see the
true contents of hardware registers, you must select the innermost
frame (with `frame 0').

   However, GDB must deduce where registers are saved, from the machine
code generated by your compiler.  If some registers are not saved, or if
GDB is unable to locate the saved registers, the selected stack frame
makes no difference.

   ---------- Footnotes ----------

   (1) This is a way of removing one word from the stack, on machines
where stacks grow downward in memory (most machines, nowadays).  This
assumes that the innermost stack frame is selected; setting `$sp' is
not allowed when other stack frames are selected.  To pop entire frames
off the stack, regardless of machine architecture, use `return'; see
*Note Returning from a function: Returning.

Floating point hardware
=======================

Depending on the configuration, GDB may be able to give you more
information about the status of the floating point hardware.

`info float'
     Display hardware-dependent information about the floating point
     unit.  The exact contents and layout vary depending on the
     floating point chip.  Currently, `info float' is supported on the
     ARM and x86 machines.

Vector Unit
===========

Depending on the configuration, GDB may be able to give you more
information about the status of the vector unit.

`info vector'
     Display information about the vector unit.  The exact contents and
     layout vary depending on the hardware.

Operating system auxiliary vector
=================================

Some operating systems supply an "auxiliary vector" to programs at
startup.  This is akin to the arguments and environment that you
specify for a program, but contains a system-dependent variety of
binary values that tell system libraries important details about the
hardware, operating system, and process.  Each value's purpose is
identified by an integer tag; the meanings are well-known but
system-specific.  Depending on the configuration and operating system
facilities, GDB may be able to show you this information.

`info auxv'
     Display the auxiliary vector of the inferior, which can be either a
     live process or a core dump file.  GDB prints each tag value
     numerically, and also shows names and text descriptions for
     recognized tags.  Some values in the vector are numbers, some bit
     masks, and some pointers to strings or other data.  GDB displays
     each value in the most appropriate form for a recognized tag, and
     in hexadecimal for an unrecognized tag.

Wendet man diese zusätzlichen info-Befehle an, dann erhält man eine nach funktionalen Gruppen strukturierte Ausgabe, allerdings erst dann, nachdem das Programm gestartet wurde.


gerd@kant:~/public_html/fh/II-INF3/II-INF3-TH/VL4> gdb bsp1
GNU gdb 6.1
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i586-suse-linux"...Using host libthread_db library "/lib/tls/libthread_db.so.1".

(gdb) info float
The program has no registers now.
(gdb) r
Starting program: /home/gerd/public_html/fh/II-INF3/II-INF3-TH/VL4/bsp1

Program exited normally.
(gdb) set listsize 25
(gdb) l
1       /****************************
2        *
3        * bsp1_main.c
4        *
5        * idea: simple demo for calling a function
6        *
7        **********************************/
8
9
10      int main(){
11
12        int accum = 0;
13
14        accum = sum(1,3);
15
16        return 0;
17
18      }
(gdb) b 16
Breakpoint 1 at 0x8048385: file bsp1_main.c, line 16.
(gdb) info float
The program has no registers now.
(gdb) info vector
The program has no registers now.
(gdb) info auxv
The program has no auxiliary information now.
(gdb) info registers
The program has no registers now.
(gdb) r
Starting program: /home/gerd/public_html/fh/II-INF3/II-INF3-TH/VL4/bsp1

Breakpoint 1, main () at bsp1_main.c:16
16        return 0;
(gdb) info registers
eax            0x4      4
ecx            0x400474c5       1074033861
edx            0x1      1
ebx            0x40143bd0       1075067856
esp            0xbfffef70       0xbfffef70
ebp            0xbfffef78       0xbfffef78
esi            0x400168c0       1073834176
edi            0x80483a0        134513568
eip            0x8048385        0x8048385
eflags         0x200282 2097794
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) info float
  R7: Empty   0x00000000000000000000
  R6: Empty   0x00000000000000000000
  R5: Empty   0x00000000000000000000
  R4: Empty   0x00000000000000000000
  R3: Empty   0x00000000000000000000
  R2: Empty   0x00000000000000000000
  R1: Empty   0x00000000000000000000
=>R0: Empty   0x00000000000000000000

Status Word:         0x0000
                       TOP: 0
Control Word:        0x037f   IM DM ZM OM UM PM
                       PC: Extended Precision (64-bits)
                       RC: Round to nearest
Tag Word:            0xffff
Instruction Pointer: 0x00:0x00000000
Operand Pointer:     0x00:0x00000000
Opcode:              0x0000
(gdb) info vector
xmm0           {v4_float = {0x0, 0x0, 0x0, 0x0}, v2_double = {0x0, 0x0}, v16_int8 = {0x0 <repeats 16 times>}, v8_int16 = {0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0, 0x0}, v4_int32 = {0x0, 0x0, 0x0, 0x0}, v2_int64 = {0x0, 0x0}, uint128 = 0x00000000000000000000000000000000}
xmm1           {v4_float = {0x0, 0x0, 0x0, 0x0}, v2_double = {0x0, 0x0}, v16_int8 = {0x0 <repeats 16 times>}, v8_int16 = {0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0, 0x0}, v4_int32 = {0x0, 0x0, 0x0, 0x0}, v2_int64 = {0x0, 0x0}, uint128 = 0x00000000000000000000000000000000}
xmm2           {v4_float = {0x0, 0x0, 0x0, 0x0}, v2_double = {0x0, 0x0}, v16_int8 = {0x0 <repeats 16 times>}, v8_int16 = {0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0, 0x0}, v4_int32 = {0x0, 0x0, 0x0, 0x0}, v2_int64 = {0x0, 0x0}, uint128 = 0x00000000000000000000000000000000}
xmm3           {v4_float = {0x0, 0x0, 0x0, 0x0}, v2_double = {0x0, 0x0}, v16_int8 = {0x0 <repeats 16 times>}, v8_int16 = {0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0, 0x0}, v4_int32 = {0x0, 0x0, 0x0, 0x0}, v2_int64 = {0x0, 0x0}, uint128 = 0x00000000000000000000000000000000}
xmm4           {v4_float = {0x0, 0x0, 0x0, 0x0}, v2_double = {0x0, 0x0}, v16_int8 = {0x0 <repeats 16 times>}, v8_int16 = {0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0, 0x0}, v4_int32 = {0x0, 0x0, 0x0, 0x0}, v2_int64 = {0x0, 0x0}, uint128 = 0x00000000000000000000000000000000}
xmm5           {v4_float = {0x0, 0x0, 0x0, 0x0}, v2_double = {0x0, 0x0}, v16_int8 = {0x0 <repeats 16 times>}, v8_int16 = {0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0, 0x0}, v4_int32 = {0x0, 0x0, 0x0, 0x0}, v2_int64 = {0x0, 0x0}, uint128 = 0x00000000000000000000000000000000}
xmm6           {v4_float = {0x0, 0x0, 0x0, 0x0}, v2_double = {0x0, 0x0}, v16_int8 = {0x0 <repeats 16 times>}, v8_int16 = {0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0, 0x0}, v4_int32 = {0x0, 0x0, 0x0, 0x0}, v2_int64 = {0x0, 0x0}, uint128 = 0x00000000000000000000000000000000}
xmm7           {v4_float = {0x0, 0x0, 0x0, 0x0}, v2_double = {0x0, 0x0}, v16_int8 = {0x0 <repeats 16 times>}, v8_int16 = {0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0, 0x0}, v4_int32 = {0x0, 0x0, 0x0, 0x0}, v2_int64 = {0x0, 0x0}, uint128 = 0x00000000000000000000000000000000}
mxcsr          0x1f80   8064
mm0            {uint64 = 0x0, v2_int32 = {0x0, 0x0}, v4_int16 = {0x0, 0x0, 0x0, 0x0}, v8_int8 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
mm1            {uint64 = 0x0, v2_int32 = {0x0, 0x0}, v4_int16 = {0x0, 0x0, 0x0, 0x0}, v8_int8 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
mm2            {uint64 = 0x0, v2_int32 = {0x0, 0x0}, v4_int16 = {0x0, 0x0, 0x0, 0x0}, v8_int8 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
mm3            {uint64 = 0x0, v2_int32 = {0x0, 0x0}, v4_int16 = {0x0, 0x0, 0x0, 0x0}, v8_int8 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
mm4            {uint64 = 0x0, v2_int32 = {0x0, 0x0}, v4_int16 = {0x0, 0x0, 0x0, 0x0}, v8_int8 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
mm5            {uint64 = 0x0, v2_int32 = {0x0, 0x0}, v4_int16 = {0x0, 0x0, 0x0, 0x0}, v8_int8 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
mm6            {uint64 = 0x0, v2_int32 = {0x0, 0x0}, v4_int16 = {0x0, 0x0, 0x0, 0x0}, v8_int8 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
mm7            {uint64 = 0x0, v2_int32 = {0x0, 0x0}, v4_int16 = {0x0, 0x0, 0x0, 0x0}, v8_int8 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
(gdb) info auxv
32   AT_SYSINFO           Special system info/entry points 0xffffe400
33   AT_SYSINFO_EHDR      System-supplied DSO's ELF header 0xffffe000
16   AT_HWCAP             Machine-dependent CPU capability hints 0xbfebf9ff
6    AT_PAGESZ            System page size               4096
17   AT_CLKTCK            Frequency of times()           100
3    AT_PHDR              Program headers for program    0x8048034
4    AT_PHENT             Size of program header entry   32
5    AT_PHNUM             Number of program headers      8
7    AT_BASE              Base address of interpreter    0x40000000
8    AT_FLAGS             Flags                          0x0
9    AT_ENTRY             Entry point of program         0x80482a0
11   AT_UID               Real user ID                   1000
12   AT_EUID              Effective user ID              1000
13   AT_GID               Real group ID                  100
14   AT_EGID              Effective group ID             100
23   AT_SECURE            Boolean, was exec setuid-like? 0
15   AT_PLATFORM          String identifying platform    0xbffff1fd "i686"
0    AT_NULL              End of vector                  0x0
(gdb)


Diese Beispiele mögen genügen, um zu zeigen, wie mächtig der Debugger gdb ist. Zusätzliche Befehle kann man in der info-Datei nachlesen.

Um diesen Debugger nun sinnvoll einsetzen zu können, wird eine ausführlichere Kenntnis der Hardware einer IA32-CPU benötigt. Diese zusätzlichen Informationen sollen in der nachfolgenden Vorlesung vorgestellt werden. Als Quellen werden die eingangs zitierten Bücher und Manuals benutzt.


START

4. Testfragen und Übungen

  1. Wie ist der Zusammenhang zwischen der Formulierung einer Problemstellung, dem C-Kode, dem Assemblerkode, dem Binärkode, der ISA-Schnitttelle und der CPU-Hardware?

  2. Mit welchen Befehlen können Sie C-Quelltext in Assembler und Binärkode übersetzen?

  3. Mit welchem Befehl können Sie sich unter Linux Binärdateien lesbar anzeigen lassen?

  4. Mit welchem Softwarewerkzeug kann man unter Linux den Ablauf von C und C++-Programmen kontrollieren?

  5. Schreiben sie ein kleines C-Programm mit mindestens einem Funktionsaufruf, kompilieren Sie es und zeigen Sie, wie man mit Hilfe des Debuggers gdb den Inhalt der Dateien auflisten kann. Wie können sie die Anzahl der aufgelisteten Zeilen verändern?

  6. Was sind Haltepunkte (breakpoints)? Wie können Sie Haltepunkte in ihrem Programm setzen? Wie können Sie sich alle Haltepunkte anzeigen lassen? Wie können Sie Haltepunkte löschen/ deaktivieren/ wieder neu aktivieren ?

  7. Wie können sie sich die Inhalte von Variablen anzeigen lassen? Was bewirkt der Befehl 'display'?

  8. Welche Möglichkeiten gibt es, sich den Stackinhalt anzeigen zu lassen? Was ist ein Frame? Wie können sie gezielt Informationen über einen bestimmten Frame abrufen?

  9. Was sind Register? Wie können sie sich die verfügbaren Register anzeigen lassen? Gibt es verschiedene Gruppen von Registern? Welche? Wie kann man sich die Inhalte der Register anzeigen lassen?


START