日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【软件开发底层知识修炼】十五 快速学习GDB调试二 使用GDB进行断点调试

發布時間:2023/12/10 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【软件开发底层知识修炼】十五 快速学习GDB调试二 使用GDB进行断点调试 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
  • 上一篇文章我們學習了使用GDB的最基本方法:【軟件開發底層知識修煉】十四 快速學習GDB調試一
    入門使用

  • 本篇文章將學習GDB的斷點調試。斷點調試是一種非常重要的調試方法。

文章目錄

  • 1 斷點類型
  • 2 GDB軟件斷點調試相關操作
    • 2.1 通過函數名設置斷點
    • 2.2 通過文件名行號設置斷點
    • 2.3 其他操作
  • 3 GDB硬件斷點及其應用
  • 4 GDB斷點調試實際案例
    • 4.1 GDB軟件斷點調試實際案例
    • 4.2 GDB硬件斷點調試實際案例
  • 5 總結

1 斷點類型

在具體學習GDB的斷點調試之前,先簡單了解斷點的幾種類型:

  • 軟件斷點:由非法指令異常實現(軟件實現,適用于在內存中的程序的調試)
  • 硬件斷點:由硬件特性實現(數量有限,適用于FLASH中運行的程序調試)
  • 數據斷點:由硬件特性實現(數量有限,用于監視一段內存,該內存中的內容被讀或者寫,該程序就會被停下來)

2 GDB軟件斷點調試相關操作

2.1 通過函數名設置斷點

  • break func_name [if var = value]
  • 這種方法設置的斷點一直有效,程序運行一次后下次運行斷點還存在。
  • 如果加上后面方括號里面的內容,就必須在方括號里面的條件成立的時候才能夠暫停程序的執行
  • tbreak func_name [if var = value]
  • 設置的斷點只有這一次有效,下一次重新運行該程序就沒有效果了
  • 如果加上后面方括號里面的內容,就必須在方括號里面的條件成立的時候才能夠暫停程序的執行

2.2 通過文件名行號設置斷點

  • break filen_name:line_num [if var = value ]
  • 這種方法設置的斷點一直有效,程序運行一次后下次運行斷點還存在。
  • 如果加上后面方括號里面的內容,就必須在方括號里面的條件成立的時候才能夠暫停程序的執行
  • tbreak filen_name:line_num [if var = value ]
  • 設置的斷點只有這一次有效,下一次重新運行該程序就沒有效果了
  • 如果加上后面方括號里面的內容,就必須在方括號里面的條件成立的時候才能夠暫停程序的執行

2.3 其他操作

上面是軟件斷點調試時的設置斷點的操作。下面再給一個表格看看軟件斷點調試中的一些其他操作:

  • 其中enable 是將斷點使能,使斷點可以使用
  • disable是將斷點給暫時關閉,但是它還存在,不能使用了而已,下次想使用的時候不需要在重新打斷點,直接使用enable使能它即可

還有一些調試時常用的操作:

3 GDB硬件斷點及其應用

  • 當代碼位于只讀存儲器時(FLASH,一般在在嵌入式軟件開發中用的比較多),只能通過硬件斷點調試
  • 硬件斷點需要硬件支持,數量有限
  • GDB中通過使用hbreak命令支持硬件斷點
  • hbreak與break使用方法完全一樣

4 GDB斷點調試實際案例

本次調試的程序還是和上一篇文章的程序是一樣的:

  • test.c
#include <stdio.h> #include <unistd.h> extern int* g_pointer; extern void func();void test_1() {printf("test_1() : %p\n", test_1); }void test_2() {printf("test_2() : %p\n", test_2); }void test_3() {printf("test_3() : %p\n", test_3); } int main(int argc, char *argv[]) {typedef void(TFunc)();TFunc* fa[] = {test_1, test_2, test_3};int i = 0;printf("main() : begin...\n");for(i=0; i<argc; i++) //argc代表命令行參數的個數{printf("argv[%d] = %s\n", i, argv[i]);}for(i=0; i<100; i++){fa[i%3]();sleep(argc > 1); // 如果argc大于1,則執行睡眠函數}printf("g_pointer = %p\n", g_pointer);func();printf("main() : end...\n");return 0; }
  • func.c
#include <stdio.h>int* g_pointer;void func() {*g_pointer = (int)"D.T.Software"; //注意,這里是出錯的地方,g_pointer是指向0地址,但是在這里卻對0地址賦值return; }
  • 首先對上述程序編譯并且運行:
  • gcc func.c test.c -o test.out
  • ./test.out
  • 毫無疑問,程序肯定會產生錯誤,如下圖:
  • 這是在意料之中的,畢竟在func.c程序中,我們對0地址進行寫內容了。
  • 那么現在我們開始使用gdb來定位出錯誤,在開啟gdb調試之前,需要在編譯源程序的時候加上-g選項,并將程序的崩潰信息轉儲的core文件(這在【軟件開發底層知識修煉】六 Binutils輔助工具之- addr2line與strip工具這篇文章中有講解過)。
  • gcc -g test.c func.c -o test.out //重新編譯加上調試信息
  • ulimit -c unlimited //讓程序在崩潰時產生core文件
  • ./test.out //重新運行看看是否產生core文件
  • 很明顯核心已轉出,生成了core文件----注意,這是GDB調試需要用的文件
  • 現在就是出現了段錯誤,我們需要使用GDB的斷點調試來找出問題所在。那么我們上面介紹了軟件斷點調試,硬件斷點調試,下面我們就分別使用軟件斷點調試與硬件斷點調試找出我們程序中出現的問題。

4.1 GDB軟件斷點調試實際案例

注意:下面的調試示例可能過于繁復,其實可以一兩步就能定位到bug所在,但是這里我做的比較多是想借此來學習一些GDB的一些調試手段。

  • 首先按照下圖中的命令輸入順序在終端中輸入:
  • 其中start命令與上一篇文章我們使用過的run命令的區別是start后,程序已啟動就立馬停止,GDB會自動在程序開始出打上一個斷點。而run命令執行后程序會直接跑起來
  • 然后我們使用命令:break test.c:37 // 這個命令在test.c的37行打斷點
  • 使用命令:info breakpoints //查看我們的斷點數量如下圖所示:
  • 可以看到有一個斷點,是剛才我們再test.c程序中37行打的斷點。
  • 輸入continue命令繼續執行程序,程序肯定會在37行停下來,如下圖:
  • 這很正常因為我們在test.c的37行打了斷點。又因為37行是for循環的結尾處,所以此時才相當于執行了一次for循環但是還沒完全循環一次,此時i=0。
  • 想要單步執行,就繼續輸入next,則程序就會一步一步執行。我們輸入了很多個next,發現這個for循環一直可以正常執行,所以這個for循環肯定是沒有問題的。那么我們就不必在for循環內部執行了,可以直接將i設置為100,執行完for循環。
  • 輸入命令set var i=100.然后輸入兩次next,就跳出了for循環
  • 現在已經確定for循環沒有產生錯誤,那么段錯誤就是在for循環之后。for循環之后只有兩個printf語句和一個func函數調用。現在我們懷疑是func函數內部出現了段錯誤。我們在func函數調用所對應的行(41行)打一個斷點:tbreak test.c:41
  • 然后continue執行,執行到func函數時停下來了,然后使用jump test.c:45 ,程序直接正常退出:

  • 上述圖中沒有執行continue。實際需要在打完斷點后要執行以下,然后再jump
  • 從上述結果可以知道除了func函數,其他地方都是沒有問題的。所以問題應該就是出現在func函數中。
  • 上述是沒有調用func函數,然后程序正常退出所以我們懷疑是func函數的問題。現在還可以這樣,我們調用func函數但是不執行func函數體內的代碼,而是直接強制func函數返回,看看會怎么樣?如下動態圖模式:
  • 上述動態圖只是想展示幾個命令的用法~~~~注意學會使用。

4.2 GDB硬件斷點調試實際案例

注意:下面的調試示例可能過于繁復,其實可以一兩步就能定位到bug所在,但是這里我做的比較多是想借此來學習一些GDB的一些調試手段。

  • 硬件斷點調試實際上是與軟件斷點調試的步驟是一樣的,只不過使用的是hbreak命令而已。
  • 依次輸入:
    • gdb test.out
    • start
  • 進入到調試模式,然后我們想要硬件斷點調試,就得需要知道硬件我們的系統中有沒有硬件斷點可以使用。輸入:show can-use-hw-watchpoints 查看本機是否有硬件斷點可以使用。顯示如下圖:
  • 很明顯,我們有一個硬件斷點可以使用。
  • 輸入:hbreak func并查看當前斷點個數看我們的斷點是否打上了:
  • 然后輸入continue運行到斷點處。
  • 然后我們可以查詢func函數中的g_pointer的值是多少。發現它是0。也就是0地址。我們在func函數中對0地址進行賦值,肯定會產生段錯誤。我們改變g_pointer的值,讓它指向一塊可讀寫的堆空間,然后再執行程序,應該就不會有段錯誤了。如下圖,正是我們的操作步驟:
  • 至此,我們已經找到了導致段錯誤的原因。實際上是在軟件斷點調試中找到的大概出錯范圍是func函數,而在硬件斷點調試中找到了具體的原因是g_pointer指向0地址,但是我們對它進行賦值。
  • 我們之所以這么大費周章的使用這么多方法來找出出錯的原因,純粹是想學習使用GDB 的更多的調試命令,你完全可以幾個步驟就找到出錯的原因。我們只是為了學習。

5 總結

我們還注意到了一個問題就是在整個調試過程中我們沒有修改過一句代碼,也沒有重新編譯程序。這樣很方便的找到源代碼中的問題所在。實在是非常的方便。

  • 學會使用軟件斷點調試
  • 學會使用硬件斷點調試

本文章參考狄泰軟件學院相關課程
想學習的可以加狄泰軟件學院群,
群聊號碼:199546072

學習探討加個人(可以免費幫忙下載CSDN資源):
qq:1126137994
微信:liu1126137994

總結

以上是生活随笔為你收集整理的【软件开发底层知识修炼】十五 快速学习GDB调试二 使用GDB进行断点调试的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。