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. 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;
    }
  1. quick.c
    #include <stdio.h>
    #include <stdbool.h>
    #define MAX 7
     
    #define MAGIC 100000
    int intArray[MAX] = {4,6,3,2,1,9,7};
     
    void printline(int count) {
       int i;
     
       for(i = 0;i <count-1;i++) {
          printf("=");
       }
     
       printf("=\n");
    }
     
    void display() {
       int i;
       printf("[");
     
       // navigate through all items
       for(i = 0;i<MAX;i++) {
          printf("%d ",intArray[i]);
       }
     
       printf("]\n");
    }
     
    void swap(int num1, int num2) {
       int temp = intArray[num1];
       intArray[num1+MAGIC] = intArray[num2];
       intArray[num2] = temp;
    }
     
    int partition(int left, int right, int pivot) {
       int leftPointer = left -1;
       int rightPointer = right;
     
       while(true) {
          while(intArray[++leftPointer] < pivot) {
             //do nothing
          }
     
          while(rightPointer > 0 && intArray[--rightPointer] > pivot) {
             //do nothing
          }
     
          if(leftPointer >= rightPointer) {
             break;
          } else {
             printf(" item swapped :%d,%d\n", intArray[leftPointer],intArray[rightPointer]);
             swap(leftPointer,rightPointer);
          }
       }
     
       printf(" pivot swapped :%d,%d\n", intArray[leftPointer],intArray[right]);
       swap(leftPointer,right);
       printf("Updated Array: ");
       display();
       return leftPointer;
    }
     
    void quickSort(int left, int right) {
       if(right-left <= 0) {
          return;
       } else {
          int pivot = intArray[right];
          int partitionPoint = partition(left, right, pivot);
          quickSort(left,partitionPoint-1);
          quickSort(partitionPoint+1,right);
       }
    }
     
    int main() {
       printf("Input Array: ");
       display();
       printline(50);
       quickSort(0,MAX-1);
       printf("Output Array: ");
       display();
       printline(50);
    }
ii/lab/laborator4.txt · Last modified: 2016/12/08 10:03 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