GDB: DON’T PANIC!

Articoli Leave a reply

don_t_panic_buttonChiunque di noi si sia cimentato almeno una volta nella programmazione C, sa quanto questa sia versatile ed utile per molte delle applicazioni più complesse, prime fra tutte i sistemi operativi.

È pur vero che se si è provato almeno una volta a creare un programma, anche il più semplice, questo puntualmente la prima volta si è rivelato un fiasco, andando in errore, o ci si è trovati ad affrontare il temibile SEGMENTATION FAULT, o in italiano, Errore di Segmentazione.

Il C non è molto di aiuto nello scovare queste inefficienze dei programmi e può portare la persona più santa del mondo ad imprecare come il miglior scaricatore di porto.

Esiste però un rimedio a tutto questo o almeno un piccolo aiuto: il suo nome è GDB, un applicativo da linea di comando in grado di permetterci un debug degno dei migliori linguaggi di programmazione ed anche di più.

Sottolineiamo che in questo articolo non abbiamo intenzione di scrivere una guida completa e perfetta di questo programma, in quanto non siamo in possesso delle conoscenze per poterlo fare; vogliamo però aiutare chi si trova nelle difficoltà precedentemente accennate, a districarsene come abbiamo fatto noi con un po’ di conoscenze da auto didatta.

Vediamo innanzitutto come questo programma funziona: è in grado di eseguire tutti gli eseguibili, ma eccelle con l’input di speciali file compilati in modo da mantenere molte delle caratteristiche che hanno in fase di programmazione (numeri di riga, nessuna ottimizzazione, etc…).

Per creare un eseguibile di questo tipo dobbiamo mettere mano ad un Makefile, o comunque a gcc, e compilare i nostri file C utilizzando la seguente opzione:

gcc -g [FILES] -o [OUTPUT FILE]

Una volta generato il nostro file, possiamo cominciare a debuggarlo: eseguiamo quindi sempre da riga di comando, nella cartella dove abbiamo generato il nuovo file:

gdb [OUTPUT FILE]

se però ci troviamo nella situazione in cui il nostro programma richieda dei dati in input dobbiamo far si che questi pervengano all’eseguibile, e scopriremo a nostre spese che non è possibile farlo dopo la chiamata di gdb. Andremo quindi ad utilizzare questo comando:

gdb –args [OUTPUT FILE] [ARGS]

Siamo a cavallo! Il programma è stato caricato in memoria dall’applicativo e possiamo cominciare a lavorare! Ma come?!
segmentation-faultGdb si presenta come un programma a linea di comando ed è molto di aiuto per l’utilizzo: basta scrivere il domando “help” per avere un’idea di come poter cominciare.

Vediamo un utilizzo base tipico. Per cominciare proviamo ad eseguire un programma: trovandoci nella shell di gdb digitiamo il semplice carattere “r” e subito il programma si eseguirà, come si eseguirebbe ad un semplice avvio del vero eseguibile; c’è però un aspetto interessante: anche senza l’ausilio dei break point, tipico esempio di esecuzione di programma in modalità debug, gdb è in grado di catturare segnali (es: SIGPIPE) o i temibili Segmentation Fault. Quando questo accade, il programma viene fermato, ponendo in evidenza la riga esatta in cui questo è avvenuto, ed è possibile visualizzare i valori delle variabili presenti in quel contesto, nel loro stato attuale; scrivendo nella shell

print [NOME VARIABILE]

o

print [FUNZIONE RITORNANTE]

possiamo verificare quale abbia causato l’errore e provare a capirne la motivazione.

Potrebbe essere però utile seguire l’esecuzione passo passo, cosi da capirne la logica mentre questa viene eseguita.

Porre un break point è un’operazione molto semplice: scrivendo semplicemente

break

possiamo porre un’interruzione nell’istruzione subito successiva a quella attuale. Questo tipo di utilizzo è però molto raro e poco utile; è di gran lunga più utile il seguente comando

break [NOME FUNZIONE]

in questo modo non appena la logica del programma ci porta all’interno della funzione indicata, l’esecuzione viene bloccata e possono essere stampati i valori delle variabile, verificare il ritorno delle funzioni, eseguire la prossima istruzione (Comando: “next” o semplicemente “n”) o riportare il programma ad un esecuzione lineare, fino almeno al prossimo break point (Comando: “continue”).

A volte una funzione può essere molto lunga e potrebbe non essere necessario eseguire le prime righe di codice per effettuare un debug; può risultare utile, se si è a conoscenza del numero di riga dal quale vogliamo cominciare, la seguente variante

break [NUMERO DI RIGA]

in grado di bloccarci solamente quando raggiunta tale riga, evitando tediose e ripetute pressioni di tasti.

I progetti C sono solitamente divisi in molti file di codice, alcuni dei quali contengono funzioni con stesso nome di quelle di altri. Come fa gdb a capire su quale di queste bloccarsi? E se il file C non contiene il dato numero di riga, in quanto presente in un altro file?

Ci vengono in aiuto due ulteriori versioni di questo comando, dedicate alle nostre specifiche richieste

break [NOME FILE]:[NOME FUNZIONE]

e

break [NOME FILE]:[NUMERO DI RIGA]

Ultima (nella nostra trattazione), ma non banale o poco utile, variante di questo comando è la seguente

break … if [CONDIZIONE]

questa ci permette di eseguire il debug nel migliore dei modi: al verificarsi di un dato evento, permettendo di facilitare ulteriormente il nostro lavoro.

L’utilizzo di gdb può essere immenso. Il nostro articolo purtroppo non può coprire tutti i casi, ma vi rimandiamo a seguente link http://www.chemie.fu-berlin.de/chemnet/use/info/gdb/ dove è possibile quietare i dubbi più intricati, se il nostro articolo non è riuscito a delucidarvi.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *