GDB - Guida rapida

Un debugger è un programma che esegue altri programmi, consentendo all'utente di esercitare il controllo su questi programmi e di esaminare le variabili quando sorgono problemi.

GNU Debugger, che è anche chiamato gdb, è il debugger più popolare per i sistemi UNIX per eseguire il debug di programmi C e C ++.

GNU Debugger ti aiuta a ottenere informazioni su quanto segue:

  • Se si è verificato un core dump, su quale istruzione o espressione si è verificato il crash del programma?

  • Se si verifica un errore durante l'esecuzione di una funzione, quale riga del programma contiene la chiamata a quella funzione e quali sono i parametri?

  • Quali sono i valori delle variabili del programma in un punto particolare durante l'esecuzione del programma?

  • Qual è il risultato di una particolare espressione in un programma?

Come esegue il debug di GDB?

GDB consente di eseguire il programma fino a un certo punto, quindi interrompere e stampare i valori di determinate variabili in quel punto, oppure scorrere il programma una riga alla volta e stampare i valori di ciascuna variabile dopo aver eseguito ciascuna riga.

GDB utilizza una semplice interfaccia a riga di comando.

Punti da notare

  • Anche se GDB può aiutarti a scoprire bug relativi alla perdita di memoria, ma non è uno strumento per rilevare perdite di memoria.

  • GDB non può essere utilizzato per programmi che si compilano con errori e non aiuta a correggere tali errori.

Prima di procedere all'installazione, controlla se gdb è già installato sul tuo sistema Unix emettendo il seguente comando:

$gdb -help

Se GDB è installato, mostrerà tutte le opzioni disponibili all'interno del tuo GDB. Se GDB non è installato, procedere con una nuova installazione.

Puoi installare GDB sul tuo sistema seguendo i semplici passaggi discussi di seguito.

step 1: Assicurati di avere i prerequisiti per l'installazione di gdb:

  • Un compilatore C conforme ad ANSI (si consiglia gcc - si noti che gdb può eseguire il debug dei codici generati da altri compilatori)

  • Sono necessari 115 MB di spazio libero su disco sulla partizione su cui si costruirà gdb.

  • Sono necessari 20 MB di spazio libero su disco nella partizione su cui installerai gdb.

  • Il programma di decompressione GNU, gzip

  • Il make utility - la versione GNU è nota per funzionare senza problemi, probabilmente lo fanno anche altri.

step 2: Scarica la distribuzione dei sorgenti gdb da ftp.gnu.org/gnu/gdb. (Abbiamo usato gdb-6.6.tar.gz per queste istruzioni.) Posiziona i file di distribuzione nella directory di build.

step 3:Nella directory di compilazione, decomprimere gdb-6.6.tar.gz ed estrarre i file sorgente dall'archivio. Al termine dell'estrazione dei file, cambia la tua directory di lavoro nella directory gdb-6.6 che è stata creata automaticamente nella tua directory di build.

$ build> gzip -d gdb-6.6.tar.gz 
$ build> tar xfv gdb-6.6.tar 
$ build> cd gdb-6.6

step 4: Eseguire lo script di configurazione per configurare l'albero dei sorgenti per la propria piattaforma.

$ gdb-6.6> .⁄configure

step 5: Crea gdb usando il make utilità.

$ gdb-6.6> make

step 6: Accedi come root e installa gdb utilizzando il seguente comando.

$ gdb-6.6> make install

step 7: Se necessario, lo spazio su disco può essere recuperato eliminando la directory di build gdb e il file di archivio al termine dell'installazione.

$ gdb-6.6> cd .. 
$ build> rm -r gdb-6.6 
$ build> rm gdb-6.6.tar

Ora hai gdb installato sul tuo sistema ed è pronto per l'uso.

UN Debugging Symbol Tablemappa le istruzioni nel programma binario compilato sulla variabile, funzione o riga corrispondente nel codice sorgente. Questa mappatura potrebbe essere qualcosa del tipo:

  • Istruzione del programma ⇒ nome dell'elemento, tipo di elemento, file originale, numero di riga definito.

Le tabelle dei simboli possono essere incorporate nel programma o archiviate come file separato. Quindi, se si prevede di eseguire il debug del programma, è necessario creare una tabella dei simboli che conterrà le informazioni richieste per eseguire il debug del programma.

Possiamo dedurre i seguenti fatti sulle tabelle dei simboli:

  • Una tabella dei simboli funziona per una particolare versione del programma: se il programma cambia, è necessario creare una nuova tabella.

  • Le build di debug sono spesso più grandi e più lente delle build al dettaglio (non di debug); le build di debug contengono la tabella dei simboli e altre informazioni ausiliarie.

  • Se desideri eseguire il debug di un programma binario che non hai compilato da solo, devi ottenere le tabelle dei simboli dall'autore.

Per consentire a GDB di leggere tutte quelle informazioni riga per riga dalla tabella dei simboli, è necessario compilarle in modo leggermente diverso. Normalmente compiliamo i nostri programmi come:

gcc hello.cc -o hello

Invece di farlo, dobbiamo compilare con il flag -g come mostrato di seguito:

gcc -g hello.cc -o hello

GDB offre un ampio elenco di comandi, tuttavia i seguenti comandi sono quelli utilizzati più frequentemente:

  • b main - Inserisce un punto di interruzione all'inizio del programma

  • b - Inserisce un punto di interruzione nella riga corrente

  • b N - Mette un punto di interruzione alla riga N

  • b +N - Inserisce un punto di interruzione di N righe sotto la riga corrente

  • b fn - Mette un punto di interruzione all'inizio della funzione "fn"

  • d N - Elimina il punto di interruzione N

  • info break - elenca i punti di interruzione

  • r - Esegue il programma fino a un punto di interruzione o un errore

  • c - Continua l'esecuzione del programma fino al successivo punto di interruzione o errore

  • f - Viene eseguito fino al termine della funzione corrente

  • s - Esegue la riga successiva del programma

  • s N - Esegue le successive N righe del programma

  • n - Come s, ma non entra nelle funzioni

  • u N - Funziona fino a quando non si ottengono N linee davanti alla linea corrente

  • p var - Stampa il valore corrente della variabile "var"

  • bt - Stampa una traccia dello stack

  • u - Sale di un livello nella pila

  • d - Scende di un livello nella pila

  • q - Esce da gdb

Guida introduttiva: avvio e arresto

  • gcc -g mioprogramma.c

    • Compila myprogram.c con l'opzione di debug (-g). Hai ancora un a.out, ma contiene informazioni di debug che ti consentono di utilizzare variabili e nomi di funzioni all'interno di GDB, piuttosto che posizioni di memoria non elaborate (non divertente).

  • gdb a.out

    • Apre GDB con il file a.out, ma non esegue il programma. Vedrai un prompt (gdb): tutti gli esempi provengono da questo prompt.

  • r

  • r arg1 arg2

  • r <file1

    • Tre modi per eseguire "a.out", caricato in precedenza. Puoi eseguirlo direttamente (r), passare argomenti (r arg1 arg2) o inserire un feed in un file. Di solito imposterai i punti di interruzione prima di eseguire.

  • help

  • h punti di interruzione

    • Elenca gli argomenti della guida (guida) o ottiene la guida su un argomento specifico (punti di interruzione h). GDB è ben documentato.

  • q - Esci da GDB

Passaggio attraverso il codice

Stepping ti consente di tracciare il percorso del tuo programma e di concentrarti sul codice che si blocca o che restituisce un input non valido.

  • l

  • l 50

  • la mia funzione

    • Elenca 10 righe di codice sorgente per la riga corrente (l), una riga specifica (l 50) o per una funzione (l myfunction).

  • Il prossimo

    • Esegue il programma fino alla riga successiva, quindi si interrompe. Se la riga corrente è una funzione, esegue l'intera funzione, quindi si interrompe.next è utile per esaminare rapidamente il codice.

  • passo

    • Esegue l'istruzione successiva, non la riga. Se l'istruzione corrente sta impostando una variabile, è uguale anext. Se è una funzione, salterà nella funzione, eseguirà la prima istruzione, quindi si fermerà.step è utile per immergersi nei dettagli del codice.

  • finire

    • Termina l'esecuzione della funzione corrente, quindi mette in pausa (chiamata anche uscita). Utile se sei entrato accidentalmente in una funzione.

Punti di interruzione o punti di osservazione

I punti di interruzione svolgono un ruolo importante nel debug. Mettono in pausa (interrompono) un programma quando raggiunge un certo punto. È possibile esaminare e modificare le variabili e riprendere l'esecuzione. Ciò è utile quando si verifica un errore di input o è necessario testare gli input.

  • rompere 45

  • interrompere la mia funzione

    • Imposta un punto di interruzione alla riga 45 o alla mia funzione. Il programma si fermerà quando raggiunge il punto di interruzione.
  • guarda x == 3

    • Imposta un watchpoint, che mette in pausa il programma quando cambia una condizione (quando x == 3 cambia). I punti di controllo sono ottimi per determinati input (myPtr! = NULL) senza dover interrompere ogni chiamata di funzione.

  • Continua

    • Riprende l'esecuzione dopo essere stato messo in pausa da un breakpoint / watchpoint. Il programma continuerà fino a quando non raggiunge il punto di interruzione / controllo successivo.

  • eliminare N

    • Elimina il punto di interruzione N (i punti di interruzione vengono numerati quando vengono creati).

Impostazione delle variabili

La visualizzazione e la modifica delle variabili in fase di esecuzione è una parte fondamentale del debug. Prova a fornire input non validi alle funzioni o ad eseguire altri casi di test per trovare la causa principale dei problemi. In genere, verranno visualizzate / impostate le variabili quando il programma è in pausa.

  • stampa x

    • Stampa il valore corrente della variabile x. Essere in grado di utilizzare i nomi delle variabili originali è il motivo per cui è necessario il flag (-g); ai programmi compilati regolarmente queste informazioni vengono rimosse.

  • impostare x = 3

  • impostare x = y

    • Imposta x su un valore impostato (3) o su un'altra variabile (y)
  • chiama myfunction ()

  • chiama la mia altra funzione (x)

  • chiama strlen (mystring)

    • Richiama funzioni definite dall'utente o di sistema. Questo è estremamente utile, ma attenzione a non chiamare funzioni con errori.

  • visualizzare x

    • Visualizza costantemente il valore della variabile x, che viene mostrato dopo ogni passaggio o pausa. Utile se controlli costantemente un certo valore.

  • undisplay x

    • Rimuove la visualizzazione costante di una variabile visualizzata dal comando di visualizzazione.

Backtrace e modifica dei fotogrammi

Uno stack è un elenco delle chiamate di funzione correnti: ti mostra dove ti trovi nel programma. Un frame memorizza i dettagli di una singola chiamata di funzione, come gli argomenti.

  • bt

    • Backtraceso stampa lo stack di funzioni corrente per mostrare dove ti trovi nel programma corrente. Se main chiama la funzione a (), che chiama b (), che chiama c (), il backtrace è

  • c <= current location 
    b 
    a 
    main
  • up

  • giù

    • Passa al fotogramma successivo in alto o in basso nello stack delle funzioni. Se sei inc, puoi passare a b o a esaminare le variabili locali.

  • ritorno

    • Restituisce dalla funzione corrente.

Segnali di gestione

I segnali sono messaggi lanciati dopo determinati eventi, come un timer o un errore. GDB può fermarsi quando incontra un segnale; potresti invece ignorarli.

  • handle [signalname] [action]

  • maniglia SIGUSR1 nostop

  • maniglia SIGUSR1 noprint

  • gestire SIGUSR1 ignorare

    • Indicare a GDB di ignorare un determinato segnale (SIGUSR1) quando si verifica. Esistono diversi livelli di ignoranza.

Passare attraverso i seguenti esempi per comprendere la procedura di debug di un programma e core dump.

  • Debug Esempio 1

    Questo esempio dimostra come catturare un errore che si sta verificando a causa di un'eccezione sollevata durante la divisione per zero.

  • Debug Esempio 2

    Questo esempio mostra un programma che può eseguire il dump di un core a causa della memoria non inizializzata.

Entrambi i programmi sono scritti in C ++ e generano core dump per diversi motivi. Dopo aver esaminato questi due esempi, dovresti essere in grado di eseguire il debug dei tuoi programmi C o C ++ che generano core dump.

Dopo aver seguito questo tutorial, è necessario aver acquisito una buona conoscenza del debug di un programma C o C ++ utilizzando GNU Debugger. Ora dovrebbe essere molto facile per te imparare le funzionalità di altri debugger perché sono molto simili a GDB. Si consiglia vivamente di esaminare anche altri debugger per acquisire familiarità con le loro funzionalità.

Ci sono alcuni buoni debugger disponibili sul mercato:

  • DBX Debugger- Questo debugger viene fornito insieme a Sun Solaris ed è possibile ottenere informazioni complete su questo debugger utilizzando la pagina man di dbx, ovvero man dbx .

  • DDD Debugger- Questa è una versione grafica di dbx e disponibile gratuitamente su Linux. Per avere un dettaglio completo, usa la pagina man di ddd, cioè man ddd .

È possibile ottenere un dettaglio completo su GNU Debugger dal seguente collegamento: Debug con GDB