GDB (The GNU Project Debugger) è un tool essenziale per il programmatore, dato che lo mette in condizione di vedere cosa accade all’interno di un programma mentre questo è in esecuzione. In particolare GDB vi permette di fare quattro principali cose:
In questa pagina trovere alcune indicazioni preliminari su come configurare GDB per un suo utilizzo più efficace, ed una lista dei comandi principali disponibili.
go
In questo corso consigliamo di definire un comando custom chiamato go
in gdb
. Per definirlo occorre editare il file .gdbinit
all’interno della home dell’utente. Ad esempio sulla VM BIAR, possiamo editarlo con:
$ geany ~/.gdbinit
Dove ~/
denota la home directory dell’utente loggato nel sistema.
Inserire nel file il seguente contenuto:
define go
start
layout src
layout regs
focus cmd
end
Per facilitare la fase di debugging di un programma, dobbiamo compilare il binario utilizzando anche la flag -g
. Ad esempio:
gcc -m32 e_main.c e.s -o e -g
Dove e.s
contiene il nostro codice ASM e e
sarà l’eseguibile generato.
Per avviare la fase di debugging su un eseguibile e
:
$ gdb ./e
È possibile trovare un sunto dei comandi disponibili in questo GDB Cheatsheet
Avvio e terminazione:
(gdb) go // esegue uno script che lancia il debugging del programma e si ferma sulla prima istruzione del main
(gdb) run [<arg1> ...] // per (ri)lanciare l'esecuzione con eventuali argomenti
(gdb) quit // per uscire da gdb (o CTRL-d)
Controllo esecuzione:
(gdb) cont // per riprendere l'esecuzione normalmente dopo un breakpoint
(gdb) step // prosegue l'esecuzione di una singola istruzione
(gdb) next // esegue istruzione in modo atomico: se è una chiamata a funzione, viene eseguita fino al suo return
(gdb) finish // esegue fino al termine della funzione corrente
Gestione breakpoint:
(gdb) break e.c:20 // inserisco un breakpoint alla linea 20 di e.c
(gdb) break e.s:20 // inserisco un breakpoint alla linea 20 di e.s
(gdb) info break // per mostrare breakpoint attivi
(gdb) clear e.s:20 // per eliminare breakpoint su una locazione di riferimento
(gdb) delete 1 // per eliminare il breakpoint contrassegnato come 1 da 'info break'
Ispezione dello stato:
(gdb) print $eax // stampa il contenuto di un registro
(gdb) print x // stampa il contenuto della variabile x nello stack frame corrente
(gdb) x addr // stampa il contenuto della memoria all'indirizzo addr
(gdb) x $eax + 4 // stampa il contenuto della memoria all'indirizzo dat dall'espressione (eax + 4)
(gdb) x/nfu addr // stampa il contenuto della memoria all'indirizzo addr secondo un formato.
Formato nfu
(documentazione):
n
: quante volte si ripete un dato (repeat count), default=1, utile per stampare arrayf
: tipo del dato (‘x’, ‘d’, ‘u’, ‘o’, ‘t’, ‘a’, ‘c’, ‘f’, ‘s’)u
: dimensione del dato (‘b’: 1, ‘h’: 2, ‘w’: 4, ‘g’: 8)Abbreviazioni dei comandi:
print
=> p
next
=> n
cont
=> c
step
=> s
Altri comandi:
(gdb) refresh // refresh output (utile in caso di garbage nella tui)
(gdb) start // si posiziona all'inizio del main; non necessario quando si usa go
(gdb) file <nome_eseguibile> // per caricare un eseguibile
(gdb) break e.c:20 if x == 0 // breakpoint condizionale: si ferma solo se quando la riga 20 è eseguita x è uguale a zero
(gdb) frame n // selezione frame (utile per ispezionare lo stato)
(gdb) where // mostra la posizione corrente nell'esecuzione
(gdb) list // mostra il contenuto del file sorgente che contiene la funzione corrente
(gdb) backtrace // elenco frame attivi