1. 斷點(diǎn)設(shè)置
本節(jié)將繼續(xù)使用 bugging 程序,首先確認(rèn)之前有執(zhí)行過(guò)以下命令
-
建立32位可執(zhí)行程序編譯環(huán)境
$ sudo apt-get update
$ sudo apt-get install gcc-multilib
-
構(gòu)建 bugging 可執(zhí)行程序
$ gcc -g -obugging bugging.c -m32
-
設(shè)置斷點(diǎn)
$ gdb bugging
(gdb) break main
(gdb) info breakpoints
在 main 函數(shù)處設(shè)置了一個(gè)斷點(diǎn),用于進(jìn)行后續(xù)的單步調(diào)試
2. 打印變量
調(diào)試的過(guò)程中需要觀察變量或者表達(dá)式的值,所以先介紹兩個(gè)基本的顯示變量值的命令
-
info locals
打印當(dāng)前斷點(diǎn)處所在函數(shù)的所有局部變量的值,不包括函數(shù)參數(shù)
-
print 變量或表達(dá)式
打印表達(dá)式的值,可顯示當(dāng)前函數(shù)的變量的值、全局變量的值等
print/FMT 可以控制打印的格式,常見的有x(十六進(jìn)制)、t(二進(jìn)制)、c(顯示為字符)等
3. 啟動(dòng)程序
run 命令用于啟動(dòng)待調(diào)試程序,并運(yùn)行到斷點(diǎn)處停下
-
run
不帶任何參數(shù),啟動(dòng)待調(diào)試程序,不傳遞參數(shù)
-
run 參數(shù)
有些程序需要跟參數(shù),直接帶上參數(shù)列表即可,會(huì)傳遞給 main 函數(shù)的 argc、argv變量
4. 單步命令
next, step, finish, continue, until 用于控制整個(gè)調(diào)試過(guò)程中,程序執(zhí)行的流程
-
next
- next 單步執(zhí)行,函數(shù)調(diào)用當(dāng)做一條指令,不會(huì)進(jìn)入被調(diào)用函數(shù)內(nèi)部
- next N,表示單步執(zhí)行N次
-
step
- step 單步執(zhí)行,會(huì)進(jìn)入到函數(shù)調(diào)用內(nèi)部
- step N,表示單步執(zhí)行N次
-
finish
執(zhí)行程序到當(dāng)前函數(shù)結(jié)束
-
continue
執(zhí)行程序到下個(gè)斷點(diǎn)
-
until
until N,執(zhí)行程序到源代碼的某一行
下圖是windows下圖形IDE c-free的調(diào)試菜單,如果理解了 gdb 的單步調(diào)試,這些選項(xiàng)應(yīng)該可以很容易理解
5.bugging程序調(diào)試
bugging 程序
- bugging 示例程序是用來(lái)計(jì)算 1+2+3+...+100 的值的,預(yù)期結(jié)果為高斯數(shù)5050
- 程序運(yùn)行的結(jié)果和我們預(yù)期的不一致,僅僅從代碼不易看出 bug 所在
- 接下來(lái)使用 gdb 單步調(diào)試該程序,找到bug 所在
調(diào)試 bugging,(接著本節(jié)的第1小節(jié))
-
info breakpoints
在main處設(shè)置了一個(gè)斷點(diǎn),位于源文件 bugging.c 的 21 行
-
run
啟動(dòng)bugging程序,停在斷點(diǎn)處,位main函數(shù)的第一條指令處
-
next
單步執(zhí)行,相當(dāng)于執(zhí)行了 result 變量的初始化
-
next
單步執(zhí)行,相當(dāng)于執(zhí)行了 N 變量的初始化
-
step
單步進(jìn)入,進(jìn)入foo函數(shù),停在foo函數(shù)的第一條指令處
-
list
查看下 foo 函數(shù)的源碼
-
info locals
打印下 foo 函數(shù)的所有局部變量,可以看到這些值是無(wú)規(guī)律的,因?yàn)闆](méi)有初始化
-
next
單步執(zhí)行,進(jìn)入循環(huán)體
-
next
單步執(zhí)行,sum = sum + i; 程序繼續(xù)執(zhí)行到 for 語(yǔ)句的判斷處
-
info locals
再次查看變量,i 的值符合預(yù)期,sum 的值依然不合理
-
list foo
檢查 foo 函數(shù)的代碼,很容易發(fā)現(xiàn)定義了兩個(gè)變量 sum 和 i,i 在循環(huán)體被初始化。而 sum 未被初始化
到這里已經(jīng)基本定位程序 bug 所在了,sum 的值從進(jìn)入循環(huán)體到執(zhí)行一次循環(huán)結(jié)束都不對(duì)。bug 根源就是 sum 變量未初始化,導(dǎo)致錯(cuò)誤的累加。我們修改 int sum = 0;
重新構(gòu)建程序,便可以得到預(yù)期結(jié)果
6. 單步調(diào)試小結(jié)
這一節(jié)主要介紹了單步調(diào)試相關(guān)的知識(shí)。主要是幾個(gè)單步相關(guān)的命令。
list
print
info locals
run
next
step
finish
continue
until
不熟悉命令的時(shí)候,記得在 gdb 命令行下鍵入 help next
等命令,查詢幫助文檔