Bài 35.122 phút đọc
Biên dịch để gỡ lỗi và khởi động GDB
Sau bài này bạn sẽ làm được
- Dịch với thông tin gỡ lỗi đầy đủ
- Giải thích vì sao gỡ lỗi ở -O2 rất khó
- Nạp chương trình có tham số dòng lệnh
- Gắn GDB vào tiến trình đang chạy và vào core dump
GDB không đoán được gì cho bạn. Nó chỉ trả lời câu hỏi bạn đặt, nên giá trị của nó phụ thuộc vào việc bạn đã có giả thuyết hay chưa. Bài này lo phần chuẩn bị: dịch đúng cách và mở đúng cách.
#Ba cờ dịch
gcc -g main.c -o main # thong tin go loi co ban
gcc -g3 main.c -o main # them ca macro, xem duoc #define trong gdb
gcc -g3 -O0 main.c -o main # khuyen dung: khong toi uu gi ca
gcc -ggdb3 -O0 main.c -o main # dinh dang rieng cua GDB, chi tiet hon| Cờ | Thêm gì | Nên dùng |
|---|---|---|
| -g | Số dòng, tên biến, tên hàm, kiểu | Tối thiểu |
| -g3 | Thêm định nghĩa macro | Nên dùng, kích thước lớn hơn chút |
| -ggdb3 | Định dạng riêng của GDB, chi tiết nhất | Khi chỉ dùng GDB |
| -O0 | Tắt mọi tối ưu | Bắt buộc khi gỡ lỗi |
| -fno-omit-frame-pointer | Giữ con trỏ khung, cho backtrace tin cậy | Nên bật |
| -fno-inline | Không nội tuyến hàm | Khi cần bước vào hàm nhỏ |
#Vì sao gỡ lỗi ở -O2 rất khó
Gỡ lỗi ở -O2
$ gcc -g -O2 -o prog prog.c
$ gdb ./prog
(gdb) print x
$1 = <optimized out>
(gdb) next
main () at prog.c:12
(gdb) next
main () at prog.c:8 <- nhay NGUOC?
(gdb) break tinh
(gdb) run
<- khong bao gio dung: ham da bi noi tuyen
(gdb) bt
#0 main () <- mat ca chuoi goi hamGỡ lỗi ở -O0
$ gcc -g3 -O0 -o prog prog.c
$ gdb ./prog
(gdb) print x
$1 = 42
(gdb) next
main () at prog.c:9 <- di theo dung thu tu ma nguon
(gdb) break tinh
(gdb) run
Breakpoint 1, tinh (a=3, b=4) at prog.c:5
(gdb) bt
#0 tinh (a=3, b=4) at prog.c:5
#1 main () at prog.c:12#Năm cách nạp chương trình
# 1. Binh thuong
gdb ./main
# 2. Co tham so dong lenh
gdb --args ./main tep.txt --dai-dong
# Hoac dat sau khi vao gdb:
(gdb) set args tep.txt --dai-dong
(gdb) show args
# 3. Gan vao tien trinh dang chay
gdb -p 12345
gdb ./main 12345
# 4. Phan tich core dump
gdb ./main core
gdb ./main /var/lib/systemd/coredump/core.main.1000.xxx
# 5. Go loi tu xa, dung cho he nhung
gdbserver :1234 ./main # tren may dich
gdb ./main # tren may cua ban
(gdb) target remote 192.168.1.5:1234#Giao diện TUI
gdb -tui ./main # bat ngay tu dau
# Hoac trong gdb:
(gdb) layout src # cua so ma nguon
(gdb) layout asm # cua so hop ngu
(gdb) layout split # ca hai
(gdb) layout regs # them cua so thanh ghi
(gdb) tui disable # tat
# Phim tat khi dang o TUI:
# Ctrl-x a bat tat TUI
# Ctrl-x 1 mot cua so
# Ctrl-x 2 hai cua so
# Ctrl-l ve lai man hinh khi bi loan
# Ctrl-p, Ctrl-n lich su lenh, vi mui ten dieu khien cuon ma nguonTệp .gdbinit tối thiểu
# Dat o ~/.gdbinit de ap dung cho moi phien
set print pretty on # in struct xuong dong, de doc
set print array on # in mang xuong dong
set print array-indexes on # kem chi so: [0] = 5, [1] = 3
set pagination off # khong dung lai hoi "Press enter"
set history save on # nho lenh giua cac phien
set history size 10000
set confirm off # khong hoi lai khi quit hay delete
# Bai 35.6 se noi ky ve tep nay, ke ca lenh tu dinh nghia.#Phiên làm việc đầu tiên
dslk.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Nut {
int ma;
char ten[16];
struct Nut *sau;
} Nut;
static Nut *them(Nut *dau, int ma, const char *ten) {
Nut *n = malloc(sizeof *n);
n->ma = ma;
strncpy(n->ten, ten, sizeof n->ten - 1);
n->ten[sizeof n->ten - 1] = '\0';
n->sau = dau;
return n;
}
static int tong(const Nut *dau) {
int t = 0;
for (const Nut *p = dau; p != NULL; p = p->sau)
t += p->ma;
return t;
}
int main(void) {
Nut *dau = NULL;
dau = them(dau, 10, "mot");
dau = them(dau, 20, "hai");
dau = them(dau, 30, "ba");
int a[5] = { 5, 3, 9, 1, 7 };
int t = tong(dau);
printf("tong = %d\n", t);
printf("a[2] = %d\n", a[2]);
return 0;
}terminal
gcc -std=c11 -g3 -O0 -o dslk.exe dslk.c
# Tệp lệnh g1.gdb: break tong, run, bt, info args, print *dau
gdb -q -batch -x g1.gdb ./dslk.exe
Breakpoint 1 at 0x4015be: file dslk.c, line 23.
Thread 1 hit Breakpoint 1, tong (dau=0x752830) at dslk.c:23
23 int t = 0;
#0 tong (dau=0x752830) at dslk.c:23
#1 0x000000000040168c in main () at dslk.c:39
dau = 0x752830
$1 = {ma = 30, ten = "ba", '\000' <repeats 13 times>, sau = 0x7527e0}Tự làm thử
- Dịch cùng một chương trình với
-gvà-g3, so kích thước tệp nhị phân. - Thử
printmột macro với-grồi với-g3. - Dịch ở
-O2và đếm xem bao nhiêu biến hiện<optimized out>. - Dịch ở
-Ogvà so với cả-O0lẫn-O2. - Chạy một chương trình vòng lặp vô tận rồi gắn GDB vào nó bằng
-p. - Viết một tệp
.gdbinitvà xác nhận nó được nạp.
Trình chấm điểm tự động sẽ được bổ sung ở giai đoạn sau. Hiện tại bạn tự chạy thử trên máy.
Tóm tắt
-g3cho xem cả macro, còn-gchỉ cho số dòng và tên biến.-gkhông làm chương trình chậm đi, chỉ-O0mới làm, và đó là hai cờ riêng biệt.- Ở
-O2thì biến biến mất, thứ tự dòng bị đảo, hàm bị nội tuyến và backtrace ngắn đi. gdb -pgắn vào tiến trình đang chạy, vàthread apply all btlà ba lệnh giải quyết phần lớn khóa chéo.gdb -q -batch -x tep.gdbchạy một chuỗi lệnh không tương tác, rất tiện để lặp lại và để chia sẻ.