GDB斷點調試詳解


GDB斷點調試詳解

通過在程序的適當位置打斷點,觀察程序執行至該位置時某些變量(或表達式)的值,進而不斷縮小導致程序出現異常或 Bug 的語句的搜索范圍,並最終找到,整個過程就稱為斷點調試。

整個斷點調試的過程,除了要借助 break、watch 或者 catch 命令以外,還要借助其它一些命令,例如在前面章節中,我們已經使用過的 print 命令(查看變量的值)、continue 命令(使程序繼續執行)等。表 1 羅列了斷點調試程序過程中,常用的一些命令以及各自的含義。

表 1 GDB斷點調試常用命令
命令(縮寫) 功 能
run(r) 啟動或者重啟一個程序。
list(l) 顯示帶有行號的源碼。
continue(c) 讓暫停的程序繼續運行。
next(n) 單步調試程序,即手動控制代碼一行一行地執行。
step(s) 如果有調用函數,進入調用的函數內部;否則,和 next 命令的功能一樣。
until(u)
until location(u location)
當你厭倦了在一個循環體內單步跟蹤時,單純使用 until 命令,可以運行程序直到退出循環體。
until n 命令中,n 為某一行代碼的行號,該命令會使程序運行至第 n 行代碼處停止。
finish(fi) 結束當前正在執行的函數,並在跳出函數后暫停程序的執行。
return(return) 結束當前調用函數並返回指定值,到上一層函數調用處停止程序執行。
jump(j) 使程序從當前要執行的代碼處,直接跳轉到指定位置處繼續執行后續的代碼。
print(p) 打印指定變量的值。
quit(q) 退出 GDB 調試器。

表 1 中 run、continue、list、next、print 以及 quit 命令的用法都非常簡單,唯一需要注意的一點是,run 命令除了可以啟動程序的執行,還可以在任何時候重新啟動程序。

GDB finish和return命令

實際調試時,在某個函數中調試一段時間后,可能不需要再一步步執行到函數返回處,希望直接執行完當前函數,這時可以使用 finish 命令。與 finish 命令類似的還有 return 命令,它們都可以結束當前執行的函數。

finish 命令和 return 命令的區別是,finish 命令會執行函數到正常退出;而 return 命令是立即結束執行當前函數並返回,也就是說,如果當前函數還有剩余的代碼未執行完畢,也不會執行了。除此之外,return 命令還有一個功能,即可以指定該函數的返回值。

示例:

#include <stdio.h>
int print(int num){
    int ret = num * num;
    return ret;
}
int myfunc(int num){
    int i = 1;
    int sum = 0;
    while(i <= num){
        sum += print(i);
        i++;
    }
    return sum;
}
int main(){
    int num =0;
    scanf("%d", &num);
    int result = myfunc(num);
    printf("%d", result);
    return 0;
}

仍然以該程序為例,來演示 finish 和 return 命令的使用。

可以看到,當程序運行至第 9 行處使用 finish 命令,GDB 調試器會執行完 myfunc() 函數中的剩余代碼,並在執行完函數后停止。接下來重新執行程序,觀察 return 命令的功能:

可以看到,同樣程序執行至第 9 行,借助 return 命令會立即終止執行 myfunc() 函數,同時手動指定該函數的返回值為 5。因此,最終 result 變量的值為 5,而不再是 14。

GDB jump命令

jump 命令的功能是直接跳到指定行繼續執行程序,其語法格式為:

(gdb) jump location

其中,location 通常為某一行代碼的行號。
也就是說,jump 命令可以略過某些代碼,直接跳到 location 處的代碼繼續執行程序。這意味着,如果你跳過了某個變量(對象)的初始化代碼,直接執行操作該變量(對象)的代碼,很可能會導致程序崩潰或出現其它 Bug。另外,如果 jump 跳轉到的位置后續沒有斷點,那么 GDB 會直接執行自跳轉處開始的后續代碼。

示例:

可以看到,由於借助 jump 指令跳過了 result 變量的初始化過程,因此 result 變量的值為 0(或者垃圾值)

注意,從第 16 行直接跳到第 19 行執行,並不意味着 result 變量不能使用。因為對於可執行文件而言,並不存在 num、result 這些變量名,它們都已經被轉化為了地址(確定地說是偏移地址),並且程序在執行時,位於 main() 函數中的所有變量的存儲地址都會被確定。也就是說,當我們跳到第 19 行輸出 result 的值時,實際上是取其存儲地址中的數據,只不過由於 result 沒有初始化,所以最終結果值可能為 0,也可能為垃圾值。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM