GDB 使用小結
Gdb 不用說,兩個字,非常強大 >.<,我最討厭不識數的人了
本文適合GDB 初學和沒學過的,如果你懂了,可以相互交流
既然說它很強大,它強大在哪里呢?
一般情況下,大部分人使用VS 自帶的調試器來調試BUG ,直觀,清晰。
在Linux下,為什么還要苦苦選擇這樣一個命令行工具呢?
關於CMD 與 圖形界面的事情不想再說....囧
開始我們的GDB 小旅
首先來調試一個很小的程序:
程序夠簡單吧,一目了然
可以不加 #include <stdio.h>
黑喂狗~
編譯選項 cc -g endin.c -o endin
這里的 endin.c 是我電腦上的文件名,你自己選一個你喜歡的就OK
注意編譯選項一定要加 -g ,這個是為GDB 保留源程序的符號表選項,不然一會兒你加載程序將出現問題。
ok, 生成二進制 endin文件以后
gdb -q ./endin
-q 的目的在於消除廣告,你懂得
現在提示
(gdb)_
開始介紹命令
(gdb) ls 1 , n (n = 1,2,3.....n )
比如 li 1,20 或者簡寫為 l 1,20 將源程序的第1-20行列出來
ok,下一步,根據行,我們可以下斷點
(gdb)b 2
在第2行下斷點
(gdb)b 10
在第10行下斷點
提示斷點成功
(gdb) run
開始運行程序,到斷點時候會停下來
(gdb) info locals (查看當前函數局部變量)
可以看到,出現了 x 和 buf ,len 三個局部變量
現在我們的目標是 buf
(gdb)x/32xb buf
這樣,我們就可以查看關於buf 里面的內容
(gdb)x 是檢查的意思,32是查看多少位,比如 12 , 55 ... 各種的,可以指定不同的格式
比如
(gdb)x/s buf
以字符流的形式來查看 buf
(gdb)x/32xw buf
以十六進制方式查看
(gdb)x/10b buf
以十進制查看
各種的... 以上的方式夠用了
還有一種方式是利用
(gdb)print (value) 形式來
比如
(gdb)print buf
這樣來查看變量,其實還可以設置變量等,這里就不一一列舉了
在來看看關於最頭疼的段錯誤問題,很多人在遇到程序收到異常信號的時候無法調試
其實很簡單,gdb提供了查看堆棧的操作,很多調試器都提供了
(gdb)backtrack或者直接 (gdb)bt
我們來模擬一個段錯誤
退出(gdb)quit
加上第11 行代碼,很明顯我們的意圖
同樣編譯運行代碼后出現
現在假設我們不知道問題出在哪里,但是我們得事先有一個大致的定位
提示出現很多關於 stack 和 Memory map ,我們這個時候得大致有一個認識這種錯誤一般是發生了段違規,也就是訪問越界或者使用了未初始化的指針等情況。好了,現在gdb 登場了
gdb -q ./endin
直接(gdb)run
可以看到,調用堆棧的情況,從下往上看,在main() 函數上面的#5 檢查棧(stack)使用情況,注意是棧,不是堆,檢查失敗。發送失敗信息,接着調用__libc_message()函數,這個是標准C 的輸出函數,然后向上,#2 abort() 退出,#1發起一個信號,信號sig=6 是退出信號。然后#0 __kernel_vsyscall() 函數調用
整個過程就大致清楚了,我們在檢查 stack 的時候產生了錯誤輸出,必定是棧訪問違規引起,其實未初始化指針是另外一種狀況。
這里因為涉及到調用堆棧遞歸層次比較少,看不出優越性。當程序較大的時候可以看出來。
下面讓我們來看看未初始化指針的情況。這個問題常常遇到,但是很多人找不到解決方案,其實很簡單。
我們再修改一下程序
在第13 和第 14 行,我們加入了一個未初始化的指針,並且我們在后面給他賦值
運行一下看結果
程序提示Segmentation fault
現在這種情況應該有一個直觀的影響就是使用了未初始化的指針。那么我們該怎么辦?
繼續(gdb)run
看,gdb 清楚的給我打印出錯誤鎖在行數和代碼位置。下次這種問題還會出現么?
事實上,還有很多東西沒有例舉出來的,今天就到這里吧