GNU/Linux >> Linux Esercitazione >  >> Linux

Come eseguire il debug di programmi C in Linux usando gdb

Indipendentemente dalla tua esperienza come programmatore, qualsiasi software che sviluppi non può essere completamente privo di bug. Quindi, identificare i bug e risolverli è una delle attività più importanti nel ciclo di sviluppo del software. Sebbene ci siano molti modi per identificare i bug (test, revisione automatica del codice e altro), esistono software dedicati - soprannominati debugger - che ti aiutano a capire esattamente dove si trova il problema, in modo da poterlo risolvere facilmente.

Se sei un programmatore C/C++ o sviluppi software utilizzando i linguaggi di programmazione Fortran e Modula-2, sarai felice di sapere che esiste un eccellente debugger, denominato GDB, che ti consente di eseguire facilmente il debug del codice per bug e altri problemi. In questo articolo, discuteremo le basi di GDB, incluse alcune delle utili funzioni/opzioni che fornisce.

Ma prima di andare avanti, vale la pena ricordare che tutte le istruzioni e gli esempi presentati in questo articolo sono stati testati su Ubuntu 14.04LTS. Il codice di esempio utilizzato nel tutorial è scritto in linguaggio C; la shell della riga di comando che abbiamo usato è bash (versione  4.3.11); e la versione GDB che abbiamo utilizzato è 7.7.1.

Nozioni di base sul debugger GDB

In parole povere, GDB ti consente di sbirciare all'interno di un programma mentre il programma è in esecuzione, qualcosa che ti consente di aiutare a identificare dove si trova esattamente il problema. Discuteremo l'utilizzo del debugger GDB attraverso un esempio funzionante nella prossima sezione, ma prima, qui, discuteremo alcuni punti di base che ti aiuteranno in seguito.

In primo luogo, per utilizzare correttamente debugger come GDB, devi compilare il tuo programma in modo tale che il compilatore produca anche le informazioni di debug richieste dai debugger. Ad esempio, nel caso del compilatore gcc, che useremo per compilare il programma C di esempio più avanti in questo tutorial, devi usare -g opzione della riga di comando durante la compilazione del codice.

Per sapere cosa dice la pagina di manuale del compilatore gcc su questa opzione della riga di comando, vai qui.

Il prossimo passo è assicurarsi di avere GDB installato sul tuo sistema. Se non è così e sei su un sistema basato su Debian come Ubuntu, puoi installare facilmente lo strumento usando il seguente comando:

sudo apt-get install gdb

Per l'installazione su qualsiasi altra distribuzione, vai qui.

Ora, una volta che hai compilato il tuo programma in modo che sia pronto per il debug e GDB è presente sul tuo sistema, puoi eseguire il tuo programma in modalità di debug usando il seguente comando:

gdb [prog-executable-name]

Anche se questo avvierà il debugger GDB, il tuo programma eseguibile non verrà avviato a questo punto. Questo è il momento in cui puoi definire le impostazioni relative al debug. Ad esempio, puoi definire un punto di interruzione che indichi a GDB di sospendere l'esecuzione del programma in corrispondenza di un particolare numero di riga o funzione.

Andando avanti, per avviare effettivamente il tuo programma, dovrai eseguire il seguente comando gdb:

run

Vale la pena ricordare qui che se il tuo programma richiede il passaggio di alcuni argomenti della riga di comando, puoi specificarli qui. Ad esempio:

run [arguments]

GDB fornisce molti comandi utili che sono utili durante il debug. Ne discuteremo alcuni nell'esempio nella prossima sezione.

Esempio di utilizzo del GDB

Ora abbiamo un'idea di base su GDB e sul suo utilizzo. Quindi prendiamo un esempio e applichiamo la conoscenza lì. Ecco un codice di esempio:

#include <stdio.h>

int main()
{
int out = 0, tot = 0, cnt = 0;
int val[] = {5, 54, 76, 91, 35, 27, 45, 15, 99, 0};

while(cnt < 10)
{
out = val[cnt];
tot = tot + 0xffffffff/out;
cnt++;
}

printf("\n Total = [%d]\n", tot);
return 0;
}

Quindi, in pratica, ciò che fa questo codice è raccogliere ogni valore contenuto nell'array 'val', assegnarlo all'intero 'out' e quindi calcolare 'tot' sommando il valore precedente della variabile e il risultato di '0xffffffff/ fuori.'

Il problema qui è che quando il codice viene eseguito, produce il seguente errore:

$ ./gdb-test 
Floating point exception (core dumped)

Quindi, per eseguire il debug del codice, il primo passo sarebbe compilare il programma con -g. Ecco il comando:

gcc -g -Wall gdb-test.c -o gdb-test

Successivamente, eseguiamo GDB e facciamogli sapere quale eseguibile vogliamo sottoporre a debug. Ecco il comando per questo:

gdb ./gdb-test 

Ora, l'errore che sto ricevendo è "eccezione in virgola mobile" e, come molti di voi potrebbero già sapere, è causato da n% x, quando x è 0. Quindi, con questo in mente, metto un punto di interruzione al numero di riga 11, dove è in corso la divisione. Questo è stato fatto nel modo seguente:

(gdb) break 11

Nota che '(gdb)' è il prompt del debugger, ho appena scritto il comando 'break'.

Ora ho chiesto a GDB di avviare l'esecuzione del programma:

run

Quindi, quando il punto di interruzione è stato raggiunto per la prima volta, ecco cosa ha mostrato GDB nell'output:

Breakpoint 1, main () at gdb-test.c:11
11 tot = tot + 0xffffffff/out;
(gdb)

Come puoi vedere nell'output sopra, il debugger ha mostrato la riga in cui è stato inserito il punto di interruzione. Ora, stampiamo il valore corrente di 'out.' Questo può essere fatto nel modo seguente:

(gdb) print out
$1 = 5
(gdb)

Come puoi vedere, è stato stampato il valore "5". Quindi, le cose vanno bene in questo momento. Ho chiesto al debugger di continuare l'esecuzione del programma fino al punto di interruzione successivo, cosa che può essere fatta usando il comando 'c'.

c  

Ho continuato a fare questo lavoro, finché non ho visto che il valore di 'out' era zero.

...
...
...
Breakpoint 1, main () at gdb-test.c:11
11 tot = tot + 0xffffffff/out;
(gdb) print out
$2 = 99
(gdb) c
Continuing.

Breakpoint 1, main () at gdb-test.c:11
11 tot = tot + 0xffffffff/out;
(gdb) print out
$3 = 0
(gdb)

Ora, per confermare che questo è il problema esatto, questa volta ho usato il comando 's' (o 'step') di GDB invece di 'c'. Il motivo è che volevo solo la riga 11, in cui l'esecuzione del programma è attualmente in pausa, da eseguire e vedere se si verifica un arresto anomalo a questo punto.

Ecco cosa è successo:

(gdb) s

Program received signal SIGFPE, Arithmetic exception.
0x080484aa in main () at gdb-test.c:11
11 tot = tot + 0xffffffff/out;

Sì, come confermato dall'output evidenziato sopra, è qui che è stata generata l'eccezione. La conferma finale è arrivata quando ho provato a eseguire nuovamente il comando 's':

(gdb) s 

Program terminated with signal SIGFPE, Arithmetic exception.
The program no longer exists.

Quindi, in questo modo, puoi eseguire il debug dei tuoi programmi utilizzando GDB.

Conclusione

Abbiamo appena scalfito la superficie qui, poiché GDB offre molte funzionalità che gli utenti possono esplorare e utilizzare. Scorri la pagina man di GDB per saperne di più sullo strumento e prova a usarlo ogni volta che esegui il debug di qualcosa nel tuo codice. Il debugger ha un po' di curva di apprendimento associata, ma ne vale la pena.


Linux
  1. Esegui il debug di Linux usando ProcDump

  2. Come creare un utente Linux usando Ansible

  3. Come riavviare Linux utilizzando la riga di comando

  4. Come eseguire il debug del programma C utilizzando gdb in 6 semplici passaggi

  5. Come eseguire il debug del kernel Linux con GDB e QEMU?

Come fare screenshot su Linux usando Scrot

Come rinominare i file usando la riga di comando in Linux

Come rimuovere i programmi installati dal sorgente utilizzando GNU Stow in Linux

Come elencare i filesystem in Linux usando Lfs

Come formattare i programmi Shell usando Shfmt in Linux

Come utilizzare GDB per eseguire il debug di programmi in Ubuntu 20.04