GDB的基本介紹

GDB是GUN開源組織釋出的一個強大的UNIX下的程式除錯工具。或許,平時大家更加習慣圖形介面的除錯,比如VS上的IDE除錯;但是如果我們在UNIX或Linux下做軟體,我們呢就更加需要熟練GDB這個除錯工具。

一般來說,GDB主要能夠完成以下的幾個功能:

①啟動你的程式,可以按照你自己的要求隨性所欲的執行程式;

②可以讓被除錯的程式在你自己所定的位置的斷點處挺住;

③當程式被停住時,可以檢查此時你的程式中所發生的事情;

④動態的改變你程式的執行環境。

GDB除錯使用的是DEBUG版本的,所以我們在生產可執行檔案時,我們需要在命令的尾部加上 -g,這樣就可以生成的是DEBUG版本下的可執行檔案。

除錯程式碼的基本命令

命令 作用
list或l + 行號 顯示從行號開始的原始碼
list或l + 函式名 列出某個函式的原始碼
run或r  執行程式
step或s 進入函式呼叫
breaktrace或bt 檢視各級函式呼叫及引數
info或i locals檢視當前棧幀區域性變數的值
info break 檢視斷點資訊
finish 執行到當前函式返回,然後停下來等待命令
print或p 打印表達式的值,通過表示式可以修改變數的值或者呼叫函式
break或b + 行號 在某一行設定斷點
set var 修改變數的值
quit 退出除錯
break + 函式名 在某個函式開頭設定斷點
continue或c 從當前位置開始連續而非單步執行除錯程式
run或r 從開頭連續執行程式而非單步執行
delete breakpoints 刪除斷點
delete breakpoints n 刪除序號為n的斷點
disable breakpoints 禁用斷點
enable breakpoints 啟用斷點
info或i breakpoints 檢視當前設定了哪些斷點
display + 變數名 跟蹤檢視一個變數,每次停下來都顯示這個值
undisplay 取消先前對那些變數設定的跟蹤
until + x 跳至第x行
n或next 單步執行
p + 變數 列印變數值
list或l 列出原始碼,接著上次的位置往下列,每次列10行
frame或f 幀編號,選擇棧幀
start 開始執行程式,停在main函式第一行語句前面等待命令
call + 函式名 強制呼叫某個函式

GDB除錯多程序

在預設情況下是除錯多程序程式時GDB會預設除錯主程序,但是GDB支援多程序的分別與同步除錯。即GDB支援同時除錯多個程序,只需要設定follow-fork-mode(預設為parent)和detach-on-fork(預設為on)即可。我們還可以使用catch fork指令,如果fork異常,會停止程式。
follow-fork-mode detach-on-fork 說明
parent on 只調試主程序(GDB預設)
child on 只調試子程序
parent off 同時除錯兩個程序,gdb跟主程序,子程序block(阻塞)在fork位置
child off 同時除錯兩個程序,gdb跟子程序,主程序block在fork位置

設定方法: set follow-fork-mode[parent|child] set detach-on-fork[on|off]

顯示:show follow-fork-mode show detach-on-fork


下面通過程式碼來演示


除錯步驟:

只調試父程序


只調試子程序(與上面的對比起來看)


下面呢我們開始直接除錯兩個程序(父程序執行除錯,子程序阻塞等待)


最後我們進行子程序執行除錯,父程序阻塞等待


GDB除錯多執行緒

在多執行緒程式設計時,當我們需要除錯時,有時需要控制某些執行緒停在斷點處,有些執行緒繼續執行;有時需要控制執行緒的執行程式;有時需要中斷某個執行緒,切換到其他執行緒。這些呢都可以通過gdb來實現。GDB預設支援除錯多執行緒,跟主執行緒,子執行緒block在create+thread。

gdb除錯一般有兩種模式:all-stop模式和no-stop模式(gdb7.0之前不支援no-stop模式)。

1.all-stop模式

在這種模式下,當你的程式在gdb由於任何原因而停止,所有的執行緒都會停止,而不僅僅是當前的執行緒。一般來說,gdb不能單步所有的執行緒。因為執行緒排程是gdb無法控制的。無論什麼時候當gdb停止你的程式,它都會自動切換到觸發斷點的那個執行緒。

2.no-stop模式(網路程式設計常用)

顧名思義,啟動不關模式。當程式在gdb中停止,只有當前的執行緒會被停止,而其他執行緒將會繼續執行。這時候step,next這些命令就只對當前執行緒起作用。

如果需要開啟no-stop模式,可以向~/.gdbinit新增配置檔案:


gdb支援的命裡有兩種型別:前臺的(同步的)和後臺(非同步 )的。區別很簡單,同步的在輸出提示符之前會等待程式report一些執行緒已經終止的資訊,非同步則是直接返回。所以我們需要set target-async 1。set pagination off不要出現 Type <return> to continue 的提示資訊 。最後一步是開啟。

下面看一下gdb除錯多執行緒常用命令:

命令 作用
info threads 顯示所有可除錯的執行緒
thread ID 切換到指定執行緒,gdb為每一個執行緒分配一個ID(與tid不同),編號一般從1開始
breakfilename:linenum thread all 在所有執行緒相應行設定斷點,注意如果主執行緒不會執行到該行,並且啟動all-stop模式,主執行緒執行n或s會切換過去
set scheduler-locking off|on\step 預設off,執行s或c其它執行緒也同步執行。on,只有當前相稱執行。step,只有當前執行緒執行
show scheduler-locking 顯示當前模式
thread apply all command 每個執行緒執行同意命令,如bt。或者thread apply 1 3 bt,即執行緒1,3執行bt。

通過程式碼來演示:


除錯步驟:

開始除錯


然後開始執行程式碼

單步除錯


切換到其他執行緒


再切換到其他執行緒除錯


設定core檔案

core的意思是核心,dumped的意思就是丟擲,轉儲,core dumped就是核心轉儲的意思。當一個程序異常退出前,該程序會丟擲當時該程式程序的記憶體詳細情況儲存在硬碟上,檔名通常是core,這就叫core dump。

程序異常終止通常是因為程式碼存在BUG,比如非法記憶體訪問導致段錯誤,事後可以用偵錯程式檢查core檔案以查清錯誤原因,這叫做事後除錯。

uname -a 檢視機器引數

ulimit -a 檢視預設引數

ulimit -c 1024 設定core檔案大小為1024

ulimit -c unlimit 設定core檔案大小為無限

ulimit -c unlimited 生成core檔案,也可以是指定大小,然後使用gdb ./main core啟動,bt檢視呼叫棧即可。

eg1(可以快速定位出問題的位置)

gdb a.out core.xxx

where

eg2 (在 gdb 中使用)

(gdb) core-file core.xxx