This is an old revision of the document!


Laborator 4 - GDB

Introducere

GDB, sau (G)NU (D)e(B)ugger, este un utilitar ce poate fi folosit pentru a vedea ce se întâmplă înăuntrul unui program în timp ce acesta rulează sau pentru a putea vedea starea în care se află programul la momentul în care a crash-uit.

GDB este folosit în principal pentru a depana programe scrise în C sau C++. Acesta poate fi folosit în două moduri pentru a depana un program:

- rulându-l folosind comanda gdb - folosind fişierul core generat în urma unei erori grave (de obicei segmentation fault)

În acest laborator vom analiza doar prima modalitate de depanare.

Rulare GDB

Pentru exemplificare considerăm următorul program:

bug.c
int add(int a, int b)
{
    int c;
    c = a + b;
    return c;
}
 
int main(int argc, char **argv)
{
	char *bug = 0;
	bug[2] = add(2, 4);
	return 0;
}

După compilare, observăm că la executarea programului se produce un segmentation fault.

$ gcc bug.c -o bug
$ ./bug
Segmentation fault (core dumped)

gdb este unealta potrivită pentru astfel de situații. Ca să aflăm la ce linie a avut loc acest segmentation fault, mai întâi trebuie să revenim la pasul de compilare și să activăm simbolurile de depanare folsind opțiunea -g a compilatorului gcc:

$ gcc -g bug.c -o bug

În continuare, rulăm programul folosind gdb:

$ gdb bug
[...]
(gdb) run
Program received signal SIGSEGV, Segmentation fault.
0x000000000040054f in main (argc=1, argv=0x7fffffffe038) at bug.c:13
13		bug[2] = add(2, 4);
(gdb)

Simbolurile de depanare nu sunt în mod implicit adăugate deoarece prin adăugarea acestora, executabilul rezultat va avea o dimensiune mai mare. Folosiți opțiunea -g doar în faza de dezvoltare.

  $ gcc exemplu.c -o exemplu
  $ gcc -g exemplu.c -o exemplu_debug
  $ ls -l
  -rwxrwxr-x. 1 student student 6.0K Dec  7 23:55 exemplu
  -rwxrwxr-x. 1 student student 6.8K Dec  7 23:55 exemplu_debug

Comenzi de bază GDB

Câteva din comenzile de bază în gdb sunt:

  • breakpoint - primeşte ca argument un nume de funcţie (ex: main), un număr de linie şi, eventual, un fişier (ex: break sursa.c:50), o funcţie (b sursa.c:my_function) sau o adresă (ex: breakpoint *0x80483d3).
  • next - va continua execuţia programului până ce se va ajunge la următoarea linie din codul sursă. Dacă linia de executat conţine un apel de funcţie, funcţia se va executa complet.
  • step - se “pășește” în interiorul funcții pentru inspectarea ei.
  • finish - se iese din funcţia curentă.
  • quit - se părăsește shell-ul gdb
[...]
(gdb) break main                                                        # adăugăm breakpoint în funcția main
Breakpoint 1 at 0x400530: file bug.c, line 12.
(gdb) run                                                               # pornim programul
Starting program: /home/master/github/labs/ii/bug 
 
Breakpoint 1, main (argc=1, argv=0x7fffffffe038) at bug.c:12
12		char *bug = 0;
(gdb) next                                                              # trecem la următoarea linie din codul sursă
13		bug[2] = add(2, 4);
(gdb) next
 
Program received signal SIGSEGV, Segmentation fault.
0x000000000040054f in main (argc=1, argv=0x7fffffffe038) at bug.c:13
13		bug[2] = add(2, 4);
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/master/github/labs/ii/bug 
 
Breakpoint 1, main (argc=1, argv=0x7fffffffe038) at bug.c:12
12		char *bug = 0;
(gdb) next
13		bug[2] = add(2, 4);
(gdb) step                                                              # intrăm în funcția add pentru a o analiza pas cu pas
add (a=2, b=4) at bug.c:6
6	    c = a + b;
(gdb) next
7	    return c;
(gdb) next
8	}
(gdb) next
 
Program received signal SIGSEGV, Segmentation fault.
0x000000000040054f in main (argc=1, argv=0x7fffffffe038) at bug.c:13
13		bug[2] = add(2, 4);
(gdb) quit
A debugging session is active.
 
	Inferior 1 [process 331] will be killed.
 
Quit anyway? (y or n) y
  • print - cu ajutorul acesteia se pot afişa valorile variabilelor din funcţia curentă sau a variabilelor globale. print poate primi ca argument şi expresii complicate (dereferenţieri de pointeri, referenţieri ale variabilelor, expresii aritmetice, aproape orice expresie C validă). În plus, print poate afişa structuri de date precum struct şi union sau evalua funcţii şi întoarcerea rezultatului lor.
  • list - afișează o parte din fișierul sursă al programulu debanat.
  • backtrace - afișează un backtrace. Un backtrace afișează, în ordine inversă, funcțiile ce au fost apelate pentru a se ajunge la linia curentă.

Exerciții și aplicații

  1. Folosiți gdb pentru a depana următorul program C:
    divide.c
    #include <stdio.h>
     
    int divide(int a, int b)
    {
        printf("Dividing %d by %d\n", a, b);
        return a / b;
    }
     
    int main(void)
    {
        int x, y, result;
     
        x = 10; y = 2;
        result = divide(x, y);
        printf("%d\n", result);
     
        x = 5; y = 0;
        result = divide(x, y);
        printf("%d\n", result);
     
        return 0;
    }
  2. TODO
ii/lab/laborator4.1481150963.txt.gz · Last modified: 2016/12/08 00:49 by iulian_gabriel.radu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0