GNU Debugger ή GDB: Ένα ισχυρό εργαλείο εντοπισμού σφαλμάτων πηγαίου κώδικα για προγράμματα Linux


Ο εντοπισμός σφαλμάτων παίζει ζωτικό ρόλο σε οποιοδήποτε σύστημα ανάπτυξης λογισμικού. Κανείς δεν μπορεί να γράψει έναν κώδικα χωρίς σφάλματα ταυτόχρονα. Κατά τη διάρκεια της ανάπτυξης, δημιουργούνται σφάλματα και πρέπει να επιλυθούν για περαιτέρω βελτίωση. Ένα σύστημα ανάπτυξης είναι ατελές χωρίς πρόγραμμα εντοπισμού σφαλμάτων. Λαμβάνοντας υπόψη την κοινότητα προγραμματιστών ανοιχτού κώδικα, το GNU Debugger είναι η καλύτερη επιλογή τους. Χρησιμοποιείται επίσης για εμπορική ανάπτυξη λογισμικού σε πλατφόρμες τύπου UNIX.

Το GNU Debugger, γνωστό και ως gdb, μας επιτρέπει να διερευνούμε κρυφά τον κώδικα ενώ εκτελείται ή τι προσπαθούσε να κάνει ένα πρόγραμμα τη στιγμή πριν διακοπεί. Το GDB βασικά μας βοηθά να κάνουμε τέσσερα κύρια πράγματα για να εντοπίσουμε ελαττώματα στον πηγαίο κώδικα.

  1. Ξεκινήστε το πρόγραμμα, προσδιορίζοντας ορίσματα που μπορεί να επηρεάσουν τη γενική συμπεριφορά.
  2. Σταματήστε το πρόγραμμα σε καθορισμένες συνθήκες.
  3. Εξετάστε τη συντριβή ή πότε διακόπηκε το πρόγραμμα.
  4. Αλλάξτε τον κώδικα και πειραματιστείτε με τον τροποποιημένο κώδικα αμέσως.

Μπορούμε να χρησιμοποιήσουμε το gdb για τον εντοπισμό σφαλμάτων προγραμμάτων γραμμένων σε C και C++ χωρίς μεγάλη προσπάθεια. Προς το παρόν, η υποστήριξη για άλλες γλώσσες προγραμματισμού όπως D, Modula-2, Fortran είναι μερική.

Ξεκινώντας με το GNU Debugger ή το GDB

Το GDB καλείται χρησιμοποιώντας την εντολή gdb. Κατά την έκδοση gdb, εμφανίζει ορισμένες πληροφορίες σχετικά με την πλατφόρμα και σας στέλνει στην προτροπή (gdb) όπως φαίνεται παρακάτω .

[root@fedora20 ~]# gdb
Δείγμα εξόδου
GNU gdb (GDB) Fedora 7.6.50.20130731-19.fc20 
Copyright (C) 2013 Free Software Foundation, Inc. 
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> 
This is free software: you are free to change and redistribute it. 
There is NO WARRANTY, to the extent permitted by law.  Type "show copying" 
and "show warranty" for details. 
This GDB was configured as "x86_64-redhat-linux-gnu". 
Type "show configuration" for configuration details. 
For bug reporting instructions, please see: 
<http://www.gnu.org/software/gdb/bugs/>. 
Find the GDB manual and other documentation resources online at: 
<http://www.gnu.org/software/gdb/documentation/>. 
For help, type "help". 
Type "apropos word" to search for commands related to "word". 
(gdb)

Πληκτρολογήστε help list για να δείτε τις διαφορετικές κατηγορίες εντολών που είναι διαθέσιμες στο gdb. Πληκτρολογήστε help ακολουθούμενη από ένα όνομα κλάσης για μια λίστα εντολών σε αυτήν την κλάση. Πληκτρολογήστε help all για τη λίστα όλων των εντολών. Οι συντομογραφίες ονομάτων εντολών επιτρέπονται εάν είναι σαφείς. Για παράδειγμα, μπορείτε να πληκτρολογήσετε n αντί να πληκτρολογήσετε next ή c για continue και ούτω καθεξής.

Οι πιο συχνά χρησιμοποιούμενες εντολές GDB

Οι εντολές gdb που χρησιμοποιούνται συνήθως παρατίθενται στον παρακάτω πίνακα. Αυτές οι εντολές πρόκειται να χρησιμοποιηθούν από τη γραμμή εντολών gdb (gdb).

Command

Περιγραφή

run

Ξεκινήστε μια εκτέλεση προγράμματος

quit

Τερματισμός gdb

print expr

Εκτύπωση έκφρασης όπου expr μπορεί να είναι επίσης όνομα μεταβλητής

next

Μετάβαση στην επόμενη γραμμή

step

Μεταβείτε στην επόμενη γραμμή

continue

Συνεχίστε από την τρέχουσα γραμμή μέχρι το τέλος του προγράμματος ή το επόμενο σημείο διακοπής

Σημειώστε τη διαφορά μεταξύ των δύο εντολών βήμα και next. Η εντολή next δεν μπαίνει μέσα στη συνάρτηση εάν η επόμενη γραμμή είναι κλήση συνάρτησης. Ενώ η εντολή step μπορεί να μπει στην εσωτερική λειτουργία και να δει τι συμβαίνει εκεί.

Ένα δείγμα συνεδρίας με το GDB

Εξετάστε τον ακόλουθο πηγαίο κώδικα.


// sum.c
#include <stdio.h> 

int sum (int a, int b) { 
	int c; 
	c = a + b; 
	return c; 
} 

int main() { 
	int x, y, z; 
	printf("\nEnter the first number: "); 
	scanf("%d", &x); 
	printf("Enter the second number: "); 
	scanf("%d", &y); 
	z = sum (x, y); 
	printf("The sum is %d\n\n", z); 
	return 0; 
}

Για να εντοπίσουμε σφάλματα στο αρχείο εξόδου πρέπει να μεταγλωττίσουμε το ίδιο με την επιλογή -g σε gcc ως εξής.

gcc -g sum.c -o sum

Το αρχείο εξόδου sum μπορεί να επισυναφθεί στο gdb με έναν από τους παρακάτω 2 τρόπους:

1. Καθορίζοντας το αρχείο εξόδου ως όρισμα στο gdb.

gdb sum

2. Εκτέλεση αρχείου εξόδου μέσα στο gdb χρησιμοποιώντας την εντολή file.

gdb
(gdb) file sum

Η εντολή list παραθέτει γραμμές στο αρχείο πηγαίου κώδικα και μετακινεί τον δείκτη. Έτσι, η πρώτη listθα εμφανίσει τις πρώτες 10 γραμμές και η επόμενη list εμφανίζει τις επόμενες 10 και ούτω καθεξής.

(gdb) list
1	#include <stdio.h>   
2	 
3	int sum (int a, int b) { 
4		int c; 
5		c = a + b; 
6		return c; 
7	} 
8	 
9	int main() { 
10		int x, y, z;

Για να ξεκινήσετε την εκτέλεση, εκδώστε την εντολή run. Τώρα το πρόγραμμα εκτελείται κανονικά. Αλλά ξεχάσαμε να βάλουμε κάποια σημεία διακοπής στον πηγαίο κώδικα για τον εντοπισμό σφαλμάτων, σωστά; Αυτά τα σημεία διακοπής μπορούν να καθοριστούν για συναρτήσεις ή σε καθορισμένες γραμμές.

(gdb) b main

Σημείωση: Έχω χρησιμοποιήσει μια συντομογραφία b για διάλειμμα.

Αφού ρυθμίσετε το σημείο διακοπής στην κύρια λειτουργία, η επανάληψη του προγράμματος θα σταματήσει στη γραμμή 11. Το ίδιο πράγμα μπορεί να εφαρμοστεί εάν ο αριθμός γραμμής είναι γνωστός από πριν.

(gdb) b sum.c:11

Τώρα περάστε μέσα από τις γραμμές κώδικα χρησιμοποιώντας την εντολή next ή n. Είναι σημαντικό να σημειωθεί ότι η εντολή next δεν μπαίνει στον κώδικα συνάρτησης εκτός εάν οριστεί ένα σημείο διακοπής στη συνάρτηση. Ας δοκιμάσουμε τώρα την εντολή print. Ορίστε το σημείο διακοπής στο άθροισμα συνάρτησης όπως παρακάτω.

(gdb) b sum 
Breakpoint 1 at 0x4005aa: file sum.c, line 5. 
(gdb) r 
Starting program: /root/sum 

Enter the first number: 2 
Enter the second number: 3 

Breakpoint 1, sum (a=2, b=3) at sum.c:5 
5		c = a + b; 
(gdb) p a 
$1 = 2 
(gdb) p b 
$2 = 3
(gdb) c 
Continuing. 
The sum is 5 

[Inferior 1 (process 3444) exited normally]

Εάν το πρόγραμμα που εκτελείται απαιτεί παραμέτρους γραμμής εντολών, τότε δώστε τις ίδιες μαζί με την εντολή run ως.

(gdb) run   . . .

Τα αρχεία κοινόχρηστης βιβλιοθήκης που σχετίζονται με το τρέχον πρόγραμμα που εκτελείται μπορούν να παρατίθενται ως.

(gdb) info share 
From                To                  Syms Read   Shared Object Library 
0x00000035a6000b10  0x00000035a6019c70  Yes         /lib64/ld-linux-x86-64.so.2 
0x00000035a641f560  0x00000035a6560bb4  Yes         /lib64/libc.so.6

Τροποποίηση μεταβλητών

Το GDB είναι επίσης ικανό να τροποποιεί μεταβλητές σε όλη την εκτέλεση του προγράμματος. Ας το δοκιμάσουμε αυτό. Όπως αναφέρθηκε παραπάνω, ορίστε το σημείο διακοπής στη γραμμή 16 και εκτελέστε το πρόγραμμα.

(gdb) r 
Starting program: /root/sum 

Enter the first number: 1 
Enter the second number: 2 

Breakpoint 1, main ( ) at sum.c:16 
16		printf("The sum is %d\n\n", z); 
(gdb) set z=4 
(gdb) c 
Continuing. 
The sum is 4

Τώρα a=1, b=2 και το αποτέλεσμα θα πρέπει να είναι z=3. Αλλά εδώ αλλάξαμε το τελικό αποτέλεσμα σε z=4 στην κύρια συνάρτηση. Με αυτόν τον τρόπο ο εντοπισμός σφαλμάτων μπορεί να γίνει ευκολότερος χρησιμοποιώντας το gdb.

Ενεργοποίηση/απενεργοποίηση σημείων διακοπής

Για να λάβετε τη λίστα με όλα τα σημεία διακοπής, πληκτρολογήστε σημεία διακοπής πληροφοριών.

(gdb) info breakpoints 
Num     Type           Disp Enb Address            What 
1       breakpoint     keep y   0x00000000004005c2 in main at sum.c:11

Εδώ υπάρχει μόνο ένα σημείο διακοπής και είναι το To. enabled disable the breakpoints καθορίζουν τον αριθμό του σημείου διακοπής μαζί με την εντολή disable. Για να ενεργοποιήσετε στη συνέχεια χρησιμοποιήστε την εντολή enable.

(gdb) disable 1 
(gdb) info breakpoints 
Num     Type           Disp Enb Address            What 
1       breakpoint     keep n   0x00000000004005c2 in main at sum.c:11

Μπορείτε επίσης να διαγράψετε τα σημεία διακοπής με την εντολή delete.

Εντοπισμός σφαλμάτων εκτελούμενων διεργασιών

Πολλές διεργασίες εκτελούνται στο παρασκήνιο σε ένα σύστημα GNU/Linux. Για τον εντοπισμό σφαλμάτων μιας διεργασίας που εκτελείται πρώτα από όλα πρέπει να βρούμε το αναγνωριστικό διεργασίας της συγκεκριμένης διεργασίας. Η εντολή pidof σας δίνει το pid μιας διαδικασίας.

pidof <process_name>

Τώρα πρέπει να επισυνάψουμε αυτό το pid στο gdb. Υπάρχουν 2 τρόποι.

1. Καθορίζοντας το pid μαζί με το gdb.

gdb -p <pid>

2. Χρησιμοποιώντας την εντολή attach από το gdb.

(gdb) attach <pid>

Αυτα για τωρα. Αυτά είναι μόνο τα βασικά του gdb για να κάνετε μια καλή αρχή στον εντοπισμό σφαλμάτων του πηγαίου κώδικα και είναι πολύ περισσότερα από τα πράγματα που εξηγήθηκαν παραπάνω. Για παράδειγμα, μπορούμε να εντοπίσουμε σφάλματα χρησιμοποιώντας τις πληροφορίες στοίβας, τις μεταβλητές περιβάλλοντος και πολλά άλλα. Προσπαθήστε να παίξετε με όλα αυτά τα πράγματα…