H. Högl, 2017-10-22
Inhalt
# main.s # H. Hoegl, 2017-10-23 # --- BSS section --- .section .bss .lcomm buffer, 256 # --- DATA section --- .section .data array: .long 5, 9, 1, 3, 8 ,7, 10, 6, 12, 11, 0 var1: .long 42 str1: .asciz "ABC" # --- TEXT section --- .section .text .globl _start _start: movl var1, %eax call f1 _L1: incl %eax jmp _L1 f1: movl $1, %eax ret # vim: expandtab ts=4 sw=4
Für GDB 7.11, 2016 (und neuer):
1 # .gdbinit 2 3 # add "set auto-load safe-path /" to your ~/.gdbinit 4 5 set confirm off 6 # do not pause during output 7 set pagination off 8 9 # siehe .gdb_history 10 set history save on 11 12 set logging file gdb_log.txt 13 set logging on 14 15 tui enable 16 layout regs 17 winheight src +3 18 winheight regs 7 19 set prompt (gdb) 20 file main 21 br _start 22 run
Damit startet man den GDB mit gdb oder gdbtui.
Man muss auch im Home-Verzeichnis eine Datei ~/.gdbinit anlegen, in der zumindest die eine Zeile steht:
set auto-load safe-path /
Auf das Symbol _start wird ein Breakpoint gesetzt. Nach dem run stoppt das Programm bei _start.
Die GDB Eingabeaufforderung (gdb) erinnert sich immer an das letzte eingegebene Kommando. Falls das z.B. s war, wird bei jedem Betätigen der Eingabetaste wieder s aufgerufen.
Man sollte das TUI einschalten, um übersichtlich Debuggen zu können. Wir bevorzugen das Layout auf dem man von oben nach unten sieht: Register, Quellcode und Kommandoeingabe.
Es gibt zwei Möglichkeiten:
Kommandozeilenoption: --tui
Auf dem Eingabeprompt anschliessen mehrmals C-x 2 eingeben, damit schaltet man nacheinander die verschiedenen Layouts durch bis das Gewünschte erreicht ist.
.gdbinit
Zum Aktivieren des bei Systemnaher Programmierung verwendeten TUI Layouts kann man in die Datei .gdbinit schreiben:
tui enable layout regs(bei moderneren GDB Versionen) oder
tui reg general(bei älteren Versionen).
Mit C-x o schaltet den Fokus auf ein anderes TUI Fenster um.
Programm starten und unterbrechen
# Programm von Anfang an starten (gdb) run [args] # Programm nach breakpoint wieder weiterlaufen lassen (gdb) continue # Laufendes Programm über Tastatur abbrechen (gdb) Strg-C
Breakpoints
(gdb) br _start (gdb) br 26 (gdb) br main.s:26 (gdb) br *<addr> (gdb) br f1 (gdb) br _L1 if $eax == 1000 # Führe Kommandos bei breakpoints aus (gdb) br <label> commands ... end # gibt aktuelle breakpoints aus (gdb) info br Num Type Disp Enb Address What 1 breakpoint keep y 0x0804807a main.s:28 breakpoint already hit 1 time 2 breakpoint keep y 0x08048084 main.s:33 # enable/disable breakpoint (gdb) disable 2 (gdb) enable 2 # breakpoint loeschen (gdb) del 2
Einzelschritte
Beachte den Unterschied zwischen step und next:
# s(step) - Eine Zeile in einer Hochsprache (gdb) s # s(tep) i(nstruction) - Ein Maschinenbefehl (gdb) si # n(ext) (gdb) n # n(ext) i(nstruction) (gdb) ni
Um das Programm wieder mit voller Geschwindigkeit auszuführen, gibt man c(ontinue) ein.
Register
(gdb) p $eax (gdb) set $eax = 42
An das $-Zeichen vor dem Registernamen im Debugger denken. Im Assembler muss es hingegen ein %-Zeichen sein.
Variablen
Die Variable var1 ist in der data section definiert:
.section .data var1: .int 42
Hier sind ein paar nützliche gdb Kommandos:
# var1 ausgeben (gdb) p var1 $1 = 42 # var1 in hex ausgeben (gdb) p/x var1 $1 = 0x2a # var1 auf Wert setzen (gdb) set variable var1 = 43 set var1 = 43 # short (gdb) set var1 = 43 set var1 = 43 # Adresse von var1 im Speicher ausgeben (gdb) p &var1 $1 = (<data variable, no debug info> *) 0x80490a7 (gdb) set {int}0x80490a7 = 0xAFFE (gdb) (gdb) whatis var1 type = <data variable, no debug info> (gdb) ptype var1 type = <data variable, no debug info>
Strings
Definition:
.section .data str1: .asciz "ABC"
Kommandos:
(gdb) p str1 $6 = 4407873 (was ist das?) (gdb) p/x str1 #$8 = 0x434241 (gdb) p/x &str1 $5 = 0x80490a7 (gdb) x/s &str1 0x80490a7: "ABC" (gdb) x/4c &str1 0x80490a7: 65 'A' 66 'B' 67 'C' 0 '\000' (gdb) set (0x80490a7 + 1) = 'm (gdb) x/s &str1 0x80490a7: "AmC"
Arrays
Ausgeben der Elemente
(gdb) p array@5 $2 = {3, 67, 34, 12, 17} (gdb) p array@6 $3 = {3, 67, 34, 12, 17, 0} (gdb) p array@7 $4 = {3, 67, 34, 12, 17, 0, 1835008}
Ausgeben der Elemente (alternative Syntax)
(gdb) p {int[6]} &array $5 = {3, 67, 34, 12, 17, 0}
Elemente verändern
(gdb) set *(unsigned int *)0x804909e = 18 (gdb) p array@5 $7 = {18, 67, 34, 12, 17}
Buffer
Definiert eine Variable buffer mit 256 Bytes im bss Abschnitt (alle 256 Bytes werden auf 0 initialisiert):
.section .bss .lcomm buffer, 256
GDB Kommandos:
(gdb) p buffer $1 = 0 (gdb) p buffer@256 $2 = {0 <repeats 256 times>} (gdb) p (char[256]) buffer $1 = '\000' <repeats 255 times> (gdb) p {char[256]} &buffer $1 = '\000' <repeats 255 times> (gdb) p &buffer $3 = (<data variable, no debug info> *) 0x80490d8 <buffer> (gdb) set {int} (&buffer+3) = 2017 (gdb) x/8xw &buffer 0x80490d8 <buffer>: 0x00000000 0x00000000 0x00000000 0x000007e1 0x80490e8 <buffer+16>: 0x00000000 0x00000000 0x00000000 0x00000000 # Vorsicht: 5 Worte offset (gdb) set {char}(&buffer+5) = 'A' (gdb) x/16xw &buffer 0x80490e0 <buffer>: 0x00000000 0x00000000 0x00000000 0x00000000 0x80490f0 <buffer+16>: 0x00000000 0x00000041 0x00000000 0x00000000 # Adresse statt &buffer (5 byte offset) set {char[3]}(0x80490e0+5) = {'a', 'b', 'c'} # Setze drittes Zeichen in Buffer auf 'y' set {char}(&(char[1])buffer+3) = 'y' # Setze ab dem fuenften Buchstaben den String "DEF\0" set {char[4]}(&(char[1])buffer+5) = "DEF" set {char[4]} &buffer = "ABC" set {char[4]} (&buffer+4) = "DEF" # Buffer "dump" (cb = char/byte; xw = hex/word) x/32cb &buffer x/8xw &buffer # Vorsicht: malloc (gdb) set &buffer+11 = {'a', 'b', 'c'} evaluation of this expression requires the program to have a function "malloc".
Stack (Kommandozeilenargumente)
Auf dem gdb Prompt startet man ein Programm mit Argumenten arg1, arg2 und arg3 wie folgt (breakpoint auf _start setzen):
(gdb) run arg1 arg2 arg3
(gdb) p $esp $6 = (void *) 0xbffff4d0 # Anzahl Argumente (gdb) p/x *(int*)$esp $8 = 0x4 # Alternative: (gdb) x/1xw $esp (gdb) x/s *(char**)($esp+4) 0xbffff637: "/home/hhoegl/Sysprog/gdb-uebersicht/main" # Alternative: (gdb) x/s {char*}($esp+4) 0xbffff637: "/home/hhoegl/Sysprog/gdb-uebersicht/main" (gdb) x/s *(char**)($esp+8) 0xbffff660: "arg1" (gdb) x/s *(char**)($esp+12) 0xbffff665: "arg2" (gdb) x/s *(char**)($esp+16) 0xbffff66a: "arg3"
Anleitung zu type-casts:
Kommandozeilenoptionen des GDB ausgeben:
gdb --help
GDB beenden mit q(uit) oder Strg-D.
GDB ohne "Banner" starten: gdb -q.