使用gdb除錯多執行緒多程序程式
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