This shows you the differences between two versions of the page.
ii:lab:laborator4 [2016/10/07 17:33] iulian_gabriel.radu |
ii:lab:laborator4 [2016/12/08 10:03] (current) iulian_gabriel.radu [Exerciții și aplicații] |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Laborator 5 - GDB ====== | + | ====== Laborator 4 - GDB ====== |
===== Introducere ===== | ===== Introducere ===== | ||
- | TODO | + | 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 ===== | ===== Rulare GDB ===== | ||
- | TODO | + | Pentru exemplificare considerăm următorul program: |
+ | |||
+ | <code c 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; | ||
+ | } | ||
+ | </code> | ||
+ | După compilare, observăm că la executarea programului se produce un segmentation fault. | ||
+ | |||
+ | <code bash> | ||
+ | $ gcc bug.c -o bug | ||
+ | $ ./bug | ||
+ | Segmentation fault (core dumped) | ||
+ | </code> | ||
+ | |||
+ | ''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'': | ||
+ | |||
+ | <code bash> | ||
+ | $ gcc -g bug.c -o bug | ||
+ | </code> | ||
+ | |||
+ | În continuare, rulăm programul folosind ''gdb'': | ||
+ | <code bash> | ||
+ | $ 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) | ||
+ | </code> | ||
+ | |||
+ | <note important> | ||
+ | |||
+ | 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 | ||
+ | |||
+ | </note> | ||
===== Comenzi de bază GDB ===== | ===== Comenzi de bază GDB ===== | ||
- | TODO | + | 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 | ||
+ | |||
+ | <code bash> | ||
+ | [...] | ||
+ | (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 | ||
+ | </code> | ||
+ | |||
+ | * **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 ===== | ===== Exerciții și aplicații ===== | ||
- | - Folosiți gdb pentru a depana următorul program C: <code c divide.c> | + | - <code c divide.c> |
#include <stdio.h> | #include <stdio.h> | ||
Line 38: | Line 150: | ||
return 0; | return 0; | ||
}</code> | }</code> | ||
- | - TODO | + | |
+ | - <code c 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); | ||
+ | }</code> | ||