| cod | OFFLINE ![]() |
| dndvault | OFFLINE ![]() |
| Joernano | OFFLINE ![]() |
| klaudia | OFFLINE ![]() |
| Lemoeb | OFFLINE ![]() |
| tuttoeniente | OFFLINE ![]() |
Stiamo ricercando: Giornalisti
Manda una mail o il tuo articolo a:
redazione[at]topolinux.org
Aiutaci a fornire servizi sempre
migliori con una donazione
Cos'è un debugger?
Dopo aver creato un qualsiasi programma è buona norma controllare che faccia esattamente ciò per cui è stato progettato.
Di solito basta guardare il codice attentamente per capire se il programma commette degli errori oppure no, ma spesso può succedere che:
Nel primo caso sappiamo che l'errore esiste ma non riusciamo a trovarlo neanche rileggendo il codice più volte. Il secondo caso è più insidioso perché all'inizio tutto sembra funzionare bene, ma poi si verifica inaspettatamente qualcosa che non avevamo previsto.
In ambedue i casi un buon modo per risolvere il problema sarebbe eseguire il programma riga per riga, controllando passo passo e in tempo reale quali operazioni esegue e qual è il valore che assumono le variabili in ogni istante.
Soltanto un'analisi accurata del programma durante la sua esecuzione può permetterci di scovare gli errori visibili e invisibili.
Ma come si può eseguire un programma una riga alla volta?
Fortunatamente esistono programmi appositi che svolgono proprio questo compito.
Questi programmi sono detti debugger (in gergo informatico, il bug è un errore nel programma; l'operazione di rimozione dell'errore è detta debugging).
In questo articolo ci occuperemo del debugger GNU sotto un sistema operativo GNU/Linux.
Questo debugger riesce ad analizzare programmi scritti in vari linguaggi (C, C++ etc.). Affinchè il debugger GNU funzioni correttamente sul nostro programma è necessario compilare il codice con l'opzione '-g'.
Per esempio se il codice di un programma in linguaggio C è contenuto nel file 'programma.c', il modo corretto di compilare sarà:
gcc -g -o prog programma.c
In questo modo abbiamo creato il file autoeseguibile 'prog'. Per eseguire il debugger e farlo lavorare su di esso basta digitare:
gdb prog
Dovrebbe apparire una schermata di questo tipo:
GNU gdb 6.4.90-debian
Copyright (C) 2006 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 "i486-linux-gnu".
(gdb)
Adesso dobbiamo comunicare al debugger almeno un breakpoint, ovvero una riga di codice o una funzione alla quale interrompere l'esecuzione del programma.
Una volta interrotto il programma, sarà possibile eseguirlo riga per riga in una maniera che mostreremo tra un attimo.
Per mettere un breakpoint in corrispondenza, per esempio, della funzione 'main', basta digitare:
(gdb) break main
Se invece si vuole mettere il breakpoint in una riga ben precisa, per esempio la riga 71, la sintassi è la seguente:
(gdb) break 71
Se il programma è composto da vari file compilati assieme, è possibile specificare anche il nome del file a cui appartiene la riga in cui vogliamo mettere il breakpoint. Basta separare il nome del file dal numero di riga con un carattere di due punti ':', come di seguito:
(gdb) break programma.c:71
Possiamo specificare quanti breakpoint desideriamo. Dopo ognuno dovrebbe comparire un messaggio del tipo:
Breakpoint 1 at 0x8048365: file programma.c, line 5.
Il numero che segue la parola 'breakpoint' (in questo caso 1), identifica univocamente il breakpoint nel programma. Se, per esempio, vogliamo rimuovere un breakpoint, basta digitare:
(gdb) delete break 1
A questo punto bisogna eseguire il programma. Per farlo basta usare il comando 'run':
(gdb) run
In questo modo, il debugger esegue il programma dalla prima riga in poi, fermandosi al primo breakpoint incontrato durante l'esecuzione.
Se il nostro programma riceve argomenti dalla riga di comando, basta specificarli dopo 'run':
(gdb) run argomento1 argomento2 argomento3
Adesso siamo fermi a un breakpoint. Il debugger ci mostra una riga di codice. Questa riga non è stata ancora eseguita. In questo momento possiamo fare molte cose.
Per esempio possiamo stampare sullo schermo il valore di una variabile (i comandi di gdb possono essere anche abbreviati; negli esempi successivi mostreremo sia la dicitura per intero che un'abbreviazione. L'effetto è assolutamente equivalente):
(gdb) print nomevariabile
(gdb) p nomevariabile
Oppure possiamo vedere una porzione di codice prima e dopo la riga attuale:
(gdb) list
(gdb) l
In alternativa possiamo impostare a mano il valore di una variabile:
(gdb) set var variabile=valore
Una volta fatto tutto questo possiamo muoverci alla riga successiva. Per farlo si può usare il comando 'next':
(gdb) next
(gdb) n
Questo comando salta alla riga successiva della porzione di codice attuale. Se la riga attuale è la chiamata a una funzione con 'next' non entriamo dentro la funzione, ma passiamo alla riga elaborata dopo la sua esecuzione.
Se invece volessimo entrare nella funzione, si usa il comando 'step':
(gdb) step
(gdb) s
Se desideriamo mostrare costantemente sullo schermo il valore di alcune variabili basta usare 'display':
(gdb) display variabile
Il risultato sarà una riga del tipo:
1: variabile = -1208249712
Il numero precedente il simbolo ':' è l'identificativo del 'display'. Per rimuovere questa variabile dalla visualizzazione costante basta usare il solito 'delete':
(gdb) delete disp 1
Se invece vogliamo che il programma continui a lavorare fino al breakpoint successivo si usa 'continue':
(gdb) continue
(gdb) c
Infine, per uscire dal debugger basta usare 'quit':
(gdb) quit
(gdb) q
Se invece desideriamo avere più informazioni su un determinato comando possiamo usare 'help':
(gdb) help nomecomando
Questi sono i comandi più importanti.
Questa guida non ha la pretesa di essere esaustiva, tuttavia dovrebbe darvi un'idea abbastanza chiara di come utilizzare in pratica uno strumento potente come il debugger GNU.