Cách gỡ lỗi chương trình C trong Linux bằng gdb

theanh

Administrator
Nhân viên
Cho dù bạn có kinh nghiệm như thế nào với tư cách là một lập trình viên, bất kỳ phần mềm nào bạn phát triển cũng không thể hoàn toàn không có lỗi. Đó là lý do tại sao việc xác định lỗi và sửa lỗi là một trong những nhiệm vụ quan trọng nhất trong chu trình phát triển phần mềm. Mặc dù có nhiều cách để tìm lỗi (kiểm tra, tự kiểm tra mã, v.v.), nhưng cũng có phần mềm đặc biệt - được gọi là trình gỡ lỗi - giúp bạn hiểu chính xác vấn đề nằm ở đâu để bạn có thể dễ dàng sửa lỗi.

Giả sử bạn là một lập trình viên C/C++ hoặc phát triển phần mềm bằng ngôn ngữ lập trình Fortran và Modula-2, trong trường hợp này, bạn sẽ vui mừng khi biết rằng có một trình gỡ lỗi tuyệt vời - được gọi là GDB - mà bạn có thể sử dụng để dễ dàng kiểm tra lỗi và các vấn đề khác trong mã của mình. Trong bài viết này, chúng ta sẽ thảo luận về những điều cơ bản của GDB và một số tính năng/tùy chọn hữu ích của nó.

Những điều cơ bản về trình gỡ lỗi GDB​

Nói một cách dễ hiểu, GDB cho phép bạn xem trước chương trình khi chương trình đang thực thi, điều này giúp bạn xác định chính xác vấn đề nằm ở đâu. Chúng ta sẽ thảo luận về cách sử dụng trình gỡ lỗi GDB thông qua một ví dụ thực tế trong phần tiếp theo, nhưng trước đó, tại đây, chúng ta sẽ thảo luận về một số điểm cơ bản sẽ giúp ích cho bạn sau này.

Đầu tiên, để sử dụng thành công các trình gỡ lỗi như GDB, bạn phải biên dịch chương trình của mình để trình biên dịch cũng tạo ra thông tin gỡ lỗi mà trình gỡ lỗi yêu cầu. Ví dụ, trong trường hợp trình biên dịch gcc, mà chúng ta sẽ sử dụng để biên dịch chương trình C ví dụ sau trong hướng dẫn này, bạn cần sử dụng tùy chọn dòng lệnh -g trong khi biên dịch mã của mình.

Để biết trang hướng dẫn sử dụng trình biên dịch gcc nói gì về tùy chọn dòng lệnh này, hãy truy cập tại đây.

Bước tiếp theo là đảm bảo rằng bạn đã cài đặt GDB trên hệ thống của mình. Nếu không phải vậy và bạn đang sử dụng hệ thống dựa trên Debian như Ubuntu, bạn có thể dễ dàng cài đặt công cụ bằng lệnh sau:
Mã:
sudo apt install gdb
Để cài đặt trên bất kỳ bản phân phối nào khác, hãy truy cập tại đây.

Bây giờ, sau khi biên dịch chương trình theo cách sẵn sàng gỡ lỗi và GDB có trên hệ thống của bạn, bạn có thể chạy chương trình ở chế độ gỡ lỗi bằng lệnh sau lệnh:
Mã:
gdb [prog-executable-name]
Mặc dù lệnh này sẽ khởi chạy trình gỡ lỗi GDB, nhưng chương trình thực thi của bạn sẽ không được khởi chạy tại thời điểm này. Đây là thời điểm bạn có thể xác định các thiết lập liên quan đến gỡ lỗi của mình. Ví dụ, bạn có thể định nghĩa điểm dừng yêu cầu GDB tạm dừng thực thi chương trình ở số dòng hoặc hàm cụ thể.

Tiếp theo, để khởi chạy chương trình, bạn sẽ phải thực thi lệnh gdb sau:
Mã:
run
Cần đề cập rằng nếu chương trình của bạn yêu cầu truyền một số đối số dòng lệnh, bạn có thể chỉ định chúng tại đây. Ví dụ:
Mã:
run [arguments]
GDB cung cấp nhiều lệnh hữu ích có ích khi gỡ lỗi. Chúng ta sẽ thảo luận một số lệnh trong ví dụ ở phần tiếp theo.

Ví dụ về cách sử dụng GDB​

Bây giờ chúng ta đã có ý tưởng cơ bản về GDB cũng như cách sử dụng của nó. Vậy hãy lấy một ví dụ và áp dụng kiến thức ở đó. Sau đây là một mã ví dụ:
Mã:
#include 

int main()
{
 int out = 0, tot = 0, cnt = 0;
 int val[] = {5, 54, 76, 91, 35, 27, 45, 15, 99, 0};

 while(cnt < 10)
 {
 out = val[cnt];
 tot = tot + 0xffffffff/out;
 cnt++;
 }

 printf("\n Total = [%d]\n", tot);
 return 0;
}
Về cơ bản, mã này thực hiện như sau: nó chọn từng giá trị có trong mảng 'val', gán giá trị đó cho số nguyên 'out', sau đó tính toán 'tot' bằng cách cộng giá trị trước đó của biến và kết quả của '0xffffffff/out.'

Vấn đề ở đây là khi mã được chạy, nó tạo ra kết quả sau lỗi:
Mã:
$ ./gdb-test 
Floating point exception (core dumped)
Vì vậy, để gỡ lỗi mã, bước đầu tiên là biên dịch chương trình với -g. Đây là lệnh:
Mã:
gcc -g -Wall gdb-test.c -o gdb-test
Tiếp theo, hãy chạy GDB và cho nó biết tệp thực thi nào chúng ta muốn gỡ lỗi. Đây là lệnh cho việc đó:
Mã:
gdb ./gdb-test
Bây giờ, lỗi tôi gặp phải là 'ngoại lệ dấu phẩy động' và như hầu hết các bạn có thể đã biết, lỗi này do n % x gây ra khi x bằng 0. Vì vậy, với suy nghĩ đó, tôi đặt điểm dừng ở dòng số 11, nơi phép chia đang diễn ra. Việc này được thực hiện theo cách sau:
Mã:
(gdb) [B]break 11[/b]
Lưu ý rằng '(gdb)' là dấu nhắc của trình gỡ lỗi. Tôi vừa viết lệnh 'break'.

Bây giờ, tôi yêu cầu GDB bắt đầu thực thi chương trình:
Mã:
run
Vì vậy, khi điểm dừng được chạm đến lần đầu tiên, đây là những gì GDB hiển thị trong đầu ra:
Mã:
Breakpoint 1, main () at gdb-test.c:11
11 tot = tot + 0xffffffff/out;
(gdb)
Như bạn có thể thấy trong đầu ra ở trên, trình gỡ lỗi đã hiển thị dòng nơi điểm dừng được đặt. Bây giờ, hãy in giá trị hiện tại của 'out.' Bạn có thể thực hiện theo cách sau:
Mã:
(gdb)[B] print out[/b]
[B]$1 = 5[/b]
(gdb)
Như bạn thấy, giá trị '5' đã được in ra. Vậy là mọi thứ vẫn ổn vào lúc này. Tôi đã yêu cầu trình gỡ lỗi tiếp tục thực thi chương trình cho đến điểm dừng tiếp theo, điều này có thể thực hiện được bằng lệnh 'c'.
Mã:
c
Tôi tiếp tục thực hiện công việc này cho đến khi tôi thấy giá trị của 'out' bằng không.
Mã:
...
...
...
Breakpoint 1, main () at gdb-test.c:11
11 tot = tot + 0xffffffff/out;
(gdb) print out
$2 = 99
(gdb) c
Continuing.

Breakpoint 1, main () at gdb-test.c:11
11 tot = tot + 0xffffffff/out;
(gdb) [B]print out[/b]
[B]$3 = 0[/b]
(gdb)
Bây giờ, để xác nhận đây chính xác là vấn đề, tôi đã sử dụng 's' của GDB (hoặc lệnh 'step') thay vì 'c' lần này. Tôi chỉ muốn dòng 11, nơi chương trình đang tạm dừng thực thi, được thực thi và xem lỗi có xảy ra tại thời điểm này không.

Đây là những gì đã xảy ra:
Mã:
(gdb) s

[B]Program received signal SIGFPE, Arithmetic exception.[/b]
0x080484aa in main () at gdb-test.c:11
11 tot = tot + 0xffffffff/out;
Đúng vậy, như đã xác nhận bằng đầu ra được tô sáng ở trên, đây là nơi ngoại lệ được ném ra. Xác nhận cuối cùng xuất hiện khi tôi thử chạy lệnh 's' một lần nữa:
Mã:
(gdb) s 

Program terminated with signal SIGFPE, Arithmetic exception.
The program no longer exists.
Theo cách này, bạn có thể gỡ lỗi chương trình của mình bằng GDB.

Kết luận​

Chúng ta vừa mới khám phá bề nổi ở đây, vì GDB cung cấp nhiều tính năng để người dùng khám phá và sử dụng. Hãy xem qua trang hướng dẫn của GDB để tìm hiểu thêm về công cụ này và thử sử dụng bất cứ khi nào bạn gỡ lỗi một cái gì đó trong mã của mình. Trình gỡ lỗi có một chút đường cong học tập, nhưng nó đáng để làm việc chăm chỉ.
 
Back
Bên trên