Bỏ qua điều hướng, tới nội dung chính
Học C
Bài 35.228 phút đọc

Điểm dừng và điều khiển luồng chạy

Sau bài này bạn sẽ làm được

  • Đặt điểm dừng theo hàm, theo dòng và theo điều kiện
  • Phân biệt next với step và biết khi nào dùng cái nào
  • Dùng finish để thoát nhanh khỏi hàm đã lỡ bước vào
  • Quản lý danh sách điểm dừng bằng info, disable, delete

Điểm dừng có điều kiện là thứ biến GDB từ đồ chơi thành công cụ. Không có nó, bạn bấm continue chín trăm chín mươi bảy lần. Có nó, bạn dừng đúng lần lặp cần xem.

#Đặt điểm dừng

break main                # theo ten ham          (viet tat: b main)
break 42                  # theo dong trong tep hien tai
break dslk.c:23           # theo tep va dong
break *0x4015be           # theo dia chi
break                     # tai dong hien tai

tbreak tong               # diem dung TAM: chi dung mot lan roi tu xoa
rbreak ^sv_               # moi ham co ten bat dau bang sv_

start                     # tuong duong: tbreak main + run
terminal
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;

#Điểm dừng có điều kiện

vong.c
#include <stdio.h>

static int xu_ly(int i) { return i * i; }

int main(void) {
    int tong = 0;

    for (int i = 0; i < 1000; ++i)
        tong += xu_ly(i);

    printf("tong = %d\n", tong);
    return 0;
}
terminal
# Tệp lệnh: break xu_ly if i > 996, run, info args, bt
gdb -q -batch -x g5.gdb ./vong.exe
Breakpoint 1 at 0x401557: file vong.c, line 3.

Thread 1 hit Breakpoint 1, xu_ly (i=997) at vong.c:3
3	static int xu_ly(int i) { return i * i; }
i = 997
#0  xu_ly (i=997) at vong.c:3
#1  0x0000000000401587 in main () at vong.c:9
# Ba cach khac de bo qua nhung lan dung khong can

ignore 1 500              # bo qua 500 lan dung dau tien cua diem dung 1
                          # nhanh hon dieu kien, vi khong phai danh gia bieu thuc

break xu_ly
commands
  silent
  if i < 990
    continue
  end
  printf "i = %d\n", i
end                       # lenh tu dong, xem muc cuoi bai

#Quản lý danh sách

info breakpoints          # liet ke tat ca      (viet tat: i b)
delete 2                  # xoa diem dung so 2
delete                    # xoa HET, co hoi lai neu confirm on
disable 1                 # tat tam thoi, giu lai
enable 1                  # bat lai
enable once 1             # bat, dung mot lan roi tu tat
enable delete 1           # bat, dung mot lan roi tu xoa

clear tong                # xoa diem dung o ham tong
clear dslk.c:23           # xoa theo vi tri
(gdb) info breakpoints
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000000401557 in xu_ly at vong.c:3
	stop only if i > 996
	breakpoint already hit 1 time
2       breakpoint     keep n   0x0000000000401587 in main at vong.c:9
3       hw watchpoint  keep y                      sv.diem

/* Doc cac cot:
     Disp  keep = giu lai, del = tu xoa sau lan dung dau
     Enb   y = dang bat, n = dang tat
     What  vi tri, va dong duoi la dieu kien neu co */

#Năm cách bước

LệnhViết tắtLàm gì
runrChạy từ đầu
continuecChạy tiếp tới điểm dừng sau
nextnChạy một dòng, BƯỚC QUA lời gọi hàm
stepsChạy một dòng, BƯỚC VÀO hàm nếu có mã nguồn
finishfinChạy hết hàm hiện tại rồi dừng ở hàm gọi
until 50u 50Chạy tới dòng 50
untiluNhư next, nhưng không quay lại đầu vòng lặp
advance tongChạy tới khi vào hàm tong hoặc thoát khung hiện tại
nexti / stepini / siBước một LỆNH MÁY thay vì một dòng
killkDừng chương trình, giữ phiên GDB
buoc.c
static int binh_phuong(int x) {
    int t = x * x;

    return t;
}

static int tinh(int a, int b) {
    int u = binh_phuong(a);
    int v = binh_phuong(b);

    return u + v;
}

int main(void) {
    int kq = tinh(3, 4);

    printf("kq = %d\n", kq);
    return 0;
}
terminal
# break tinh, run, display u, next, step, info args
gdb -q -batch -x g7.gdb ./buoc.exe
Breakpoint 1 at 0x40157c: file buoc.c, line 10.

Thread 1 hit Breakpoint 1, tinh (a=3, b=4) at buoc.c:10
10	    int u = binh_phuong(a);
11	    int v = binh_phuong(b);
1: u = 9
binh_phuong (x=4) at buoc.c:4
4	    int t = x * x;
x = 4
terminal
# finish: chạy hết hàm hiện tại
gdb -q ./buoc.exe
(gdb) tbreak binh_phuong
Temporary breakpoint 1 at 0x40155b: file buoc.c, line 4.
(gdb) run

Thread 1 hit Temporary breakpoint 1, binh_phuong (x=3) at buoc.c:4
4	    int t = x * x;
(gdb) finish
Run till exit from #0  binh_phuong (x=3) at buoc.c:4

#Chạy lệnh tự động khi dừng

Gắn một chuỗi lệnh vào điểm dừng
(gdb) break them
(gdb) commands
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>silent
>printf "them: ma=%d ten=%s\n", ma, ten
>continue
>end

/* Bay gio moi lan them() duoc goi, GDB in mot dong roi chay tiep,
   khong dung lai.

   "silent" bo dong "Breakpoint 1, them (...)" ma GDB in mac dinh,
   nen ket xuat gon.

   Day thuc chat la printf debugging ma KHONG PHAI dich lai chuong trinh.
   Do la uu the lon nhat cua no. */
terminal
gdb -q -batch -x g_them.gdb ./dslk.exe
Breakpoint 1 at 0x401563: file dslk.c, line 12.
them: ma=10 ten=mot
them: ma=20 ten=hai
them: ma=30 ten=ba
tong = 60
a[2] = 9

Tự làm thử

  1. Đặt điểm dừng theo tên hàm, theo dòng và theo tệp, rồi so ba cách.
  2. Đặt break xu_ly if i > 996 trên vòng lặp nghìn lần và xác nhận nó dừng đúng lần.
  3. So thời gian giữa break f if x == 999999 và ignore 1 999998.
  4. Dùng next và step trên cùng một dòng có gọi hàm và đối chiếu.
  5. Dùng until để thoát khỏi một vòng lặp nghìn vòng bằng một lệnh.
  6. Viết một khối commands ghi nhật ký mọi lời gọi một hàm mà không dịch lại chương trình.

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

  • break tong dừng sau phần mở đầu hàm, nên tham số đã sẵn sàng khi bạn gọi info args.
  • Điều kiện của điểm dừng là biểu thức C đầy đủ, gọi được cả strcmp và đi theo được con trỏ.
  • next bước qua lời gọi hàm, step bước vào, finish chạy hết hàm và in giá trị trả về.
  • until ở cuối thân vòng lặp thoát thẳng ra khỏi vòng, thay cho hàng nghìn lần next.
  • Khối commands với silent và continue cho bạn gỡ lỗi bằng printf mà không phải dịch lại.