Avanti Indietro Indice

5. Debugging e Profiling

5.1 Manutenzione preventiva (lint)

Non esiste un lint ampiamente utilizzato per Linux, dal momento che la maggior parte della gente si accontenta degli avvertimenti che gcc può generare. Probabilmente, quello più utile è il -Wall opzione che significa 'Warnings, all' ma probabilmente ha un maggior valore mnemonico, se pensato come qualcosa contro cui si sbatte la testa (NdT. "wall" in inglese significa "muro").

Esiste un lint di dominio pubblico disponibile su ftp://larch.lcs.mit.edu/pub/Larch/lclint. Putroppo non sono in grado di giudicare la sua validità.

5.2 Debugging

Come si ottengono le informazioni di debug in un programma?

È necessario compilare ed eseguire il link di tutte le sue parti con l'opzione -g, e senza -fomit-frame-pointer. Non è necessario ricompilarlo interamente, solo le parti di cui si esegue il debug.

Nelle configurazioni a.out le librerie condivise sono compilate con -fomit-frame-pointer, con la quale gdb non funzionerà. Questo perché l'opzione -g implica un link statico.

Se il linker va in errore fornendo un messaggio che indica l'impossibilità di trovare libg.a, significa che non si possiede /usr/lib/libg.a, che consiste nella speciale libreria C abilitata al debugging. Tale libreria può essere fornita nel pacchetto binario libc, oppure (in versioni di libreria C più recenti) può essere necessario ottenere il codice sorgente libc ed eseguire personalmente la compilazione. Tuttavia, è possibile ottenere sufficienti informazioni per la maggior parte degli scopi semplicemente sostituendola con un collegamento simbolico con /usr/lib/libc.a.

Come eliminarle?

Molto software GNU è impostato affinché la compilazione e il link siano eseguite con l'opzione -g, che determina la generazione di eseguibili molto voluminosi (e spesso statici). Questa non è una buona idea.

Se il programma possiede uno script di configurazione `autoconf', è possibile disabilitare le informazioni di debugging controllando il Makefile. Naturalmente, se si sta utilizzando ELF, il link del programma viene eseguito in modo dinamico indipendentemente dall'impostazione -g, pertanto si può semplicemente usare strip.

Software disponibile

Molte persone utilizzano gdb, che può essere ottenuto in forma sorgente dai siti di archivio GNU ftp://prep.ai.mit.edu/pub/gnu, oppure in formato binario da tsx-11 (ftp://tsx-11.mit.edu/pub/linux/packages/GCC) o da sunsite. xxgdb è un debugger X basato su gdb (ossia, è necessario che sia installato gdb). È possibile trovare i sorgenti presso ftp://ftp.x.org/contrib/xxgdb-1.08.tar.gz.

Rick Sladkey ha eseguito il porting del debugger UPS. Può essere eseguito anche sotto X, ma a differenza di xxgdb, non è un semplice front end X per un debugger basato su testo. Possiede diverse caratteristiche molto interessanti, e se si ha la necessità di eseguire diversi debug, è il caso di provarlo. La versione precompilata per Linux e i patch per i sorgenti UPS possono essere trovati in ftp://sunsite.unc.edu/pub/Linux/devel/debuggers/, mentre i sorgenti originali in ftp://ftp.x.org/contrib/ups-2.45.2.tar.Z.

Un altro strumento utile per il debug è 'strace', che visualizza le chiamate di sistema fatte da un processo. Questo strumento possiede anche molti altri utilizzi, inclusa la possibilità di sapere i nomi di file compilati, di cui non si possiede il sorgente; di esasperare i race condition in programmi che si sospettano contenerle, e in generale di imparare come funzionano le cose. La versione più recente di strace (attualmente la 3.0.8) può essere trovata in ftp://ftp.std.com/pub/jrs/.

Programmi background (demone)

I programmi demone tipicamente eseguono presto la fork(), e terminano il programma chiamante. Questo rende la sessione di debug molto breve.

Il modo più semplice per aggirare questo ostacolo consiste nell'impostare un breakpoint per fork, e quando il programma si blocca, forzare la restituzione di 0.

(gdb) list
1               #include <stdio.h>
2
3               main()
4               {
5               if(fork()==0) printf("child\n");
6               else printf("parent\n");
7               }
(gdb) break fork
Breakpoint 1 at 0x80003b8
(gdb) run
Starting program: /home/dan/src/hello/./fork
Breakpoint 1 at 0x400177c4

Breakpoint 1, 0x400177c4 in fork ()
(gdb) return 0
Make selected stack frame return now? (y or n) y
#0  0x80004a8 in main ()
at fork.c:5
5               if(fork()==0) printf("child\n");
(gdb) next
Step singolo fino all'uscita dalla funzione fork,
che non contiene informazioni sul numero di riga.
child
7               }

Core file

Quando Linux viene avviato, solitamente è configurato per non produrre core file. Se si desidera, è possibile utilizzare il comando interno dell'interprete comandi per riabilitarli: per shell compatibili C (come tcsh) corrisponde al comando

% limit core unlimited

mentre per interpreti comandi di tipo Bourne (sh, bash, zsh, pdksh) utilizzare

$ ulimit -c unlimited

Se si desidera una maggiore flessibilità nell'assegnazione dei nomi ai core file (nel caso, per esempio, di analisi post-mortem con un debugger che contiene errori) è possibile eseguire una piccola modifica al proprio kernel. Cercare in fs/binfmt_aout.c e fs/binfmt_elf.c il codice tipo:


  memcpy(corefile,"core.",5);
#if 0
  memcpy(corefile+5,current->comm,sizeof(current->comm));
#else
  corefile[4] = '\0';
#endif

e modificare gli 0 in 1.

5.3 Profiling

Il profiling rappresenta un modo per esaminare le parti di un programma richiamate più frequentemente o eseguite più a lungo. È buona norma ottimizzare il codice e vedere dove viene perso del tempo. È necessario compilare tutti i file oggetto sui quali si desiderano informazioni sul tempo di esecuzione con l'opzione -p, e per interpretare il file di output sarà necessario anche gprof (dal pacchetto binutils). Si veda la pagina di manuale gprof per ulteriori dettagli.


Avanti Indietro Indice