目錄
3.3 gdb filename corename 偵錯core檔案
GDB(GNU Debugger)是類 Unix(如 Linux)操作系統下的一款開源的 C/C++ 程式偵錯程式。Linux平臺下C/C++程式都是使用GDB偵錯,注:gcc、g++和gdb都需要額外安裝.GDB偵錯程式支援C,C ++,Fortran,Java,Chill,彙編語言和Modula-2。GDB提供gdbserver以支援遠端偵錯。
部分應用不能使用斷點偵錯,因爲中斷偵錯影響程式結果,只能使用跟蹤點技術,但跟蹤點只適用遠端目標機。
GDB偵錯程式提供覆蓋技術支援程式太大無法載入目標系統記憶體的應用。
編譯時使用-g選項使編譯後的可執行檔案保留偵錯符號資訊。偵錯符號資訊包括但不侷限與可以偵錯程式碼、呼叫堆疊、變數名和函數名。但偵錯資訊不包含程式碼,若需要在執行環境看到程式碼,需要連同程式碼打包。
可以使用strip命令移除程式中偵錯資訊,不帶偵錯資訊可以減少程式體積和提高程式執行效率。
偵錯程式,加上-g選項並建議關閉編譯器優化。O0到O4,預設O0不優化;符號檔案顯示的偵錯變數等能與原始碼對應起來。
Debug、Release模式和GCC選項沒有嚴格對應關係。一般情況下,Debug模式使用GCC的-g -O0開啓偵錯和不優化選項,Release模式使用GCC的-O2 -s -DNDEBUG開啓優化和移除偵錯資訊選項。
GCC預設情況下使用-O0不優化作爲預設值,-O等於-O1,-Os開啓除增加程式碼大小優化外所有O2的優化。
gdb filename 偵錯程式,使用run(r)命令啓動程式;
gdb attach pid將GDB偵錯程式附加到正在執行的進程。偵錯程式暫停下來,可以新增斷點或continue;偵錯結束後,detach使程式和偵錯程式分離,continue繼續,退出GDB即可。
Linux預設不開啓生成core檔案,使用ulimit -c檢視。使用ulimit -c unlimited開啓,但只能當前對談有效。希望永久有效,將ulimit -c unlimited加入到/etc/profile檔案最後一行,再讓組態檔生效。預設生成的core檔名爲core.
預設core檔名core,但可通過修改/proc/sys/kernel/core_uses_pid檔案內容控制是否新增pid作爲擴充套件,內容1表示擴充套件.
/proc/sys/kernel/core_pattern檔案可控制core檔案生成位置和檔名。
通過echo "/corefile/core-%e-%p-%t" > /proc/sys/kernel/core_pattern 修改檔案內容。生成的core檔案將儲存在/corefile目錄下。
注:使用者必須對core檔案目錄具有寫許可權,否則因許可權不足無法生成core檔案.
以下爲支援的參數設定:
參數名稱 | 參數含義(中文) |
---|---|
%p | 新增 pid 到 core 檔名中。主進程號,即包含main函數進程 |
%t | 新增 core 檔案生成時間(UNIX)到 core 檔名中 |
%e | 新增程式名到 core 檔名中 |
%u | 新增當前 uid 到 core 檔名中 |
%g | 新增當前 gid 到 core 檔名中 |
%s | 新增導致產生 core 的信號到 core 檔名中 |
%h | 新增主機名到 core 檔名中 |
GDB執行選項 | 含義 |
gdb --help | GDB幫助文件 |
gdb -silent | GDB不列印版本和介紹資訊 |
gdb -d directory | 指定gdb的原始碼搜尋路徑 |
path directory | 將directory新增到path.path值儲存可執行檔案搜尋路徑列表 |
show paths | 顯示path值.path值儲存可執行檔案搜尋路徑列表 |
cd directory | 設定GDB工作目錄 |
pwd | 輸出GDB工作目錄 |
run > outfile | 改變程式輸出位置。預設輸出到終端,info terminal可檢視 |
show directories | 顯示原始碼查詢路徑。原始碼路徑預設包含cdir、cwd。可通過directory dirname或dir dirname加入path到搜尋路徑 |
signal signal | 向程式發送信號signal |
TAB | 補全命令 |
使用gdb attach時,查詢可執行程式和原始碼先後順序:1)當前工作目錄,2)原始檔搜尋目錄。gdb attach時,執行run,將殺死進程;不執行detach,直接quit,預設detach,不會殺死進程。
命令 | 含義 |
x | 以十六進制輸出 |
d | unsigned int 輸出 |
o | 八進制輸出 |
t | 二進制輸出 |
a | 作爲地址輸出 |
c | 作爲字元輸出 |
f | 浮點型輸出 |
注:動態陣列輸出方式,int *array = (int *) malloc (len * sizeof (int)); p *array@len;vector直接p v
命令 | 含義 |
x addr | 輸出addr記憶體 |
x/nfu addr | n重複幾次,f顯示格式,u位元組單元.b bytes,h two bytes,w four bytes.g eight bytes. |
命令名稱 | 命令縮寫 | 命令說明 |
---|---|---|
run | r | 執行一個程式 |
continue | c | 讓暫停的程式繼續執行 |
next | n | 單步執行,遇到函數直接跳過 |
step | s | 單步步入遇到函數進入 |
until | u | 執行到指定行停下來.u 84 |
finish | fi | 結束當前呼叫函數,到上一層函數呼叫處.執行整個函數 |
return | return | 結束當前呼叫函數並返回指定值,到上一層函數呼叫處.立即結束,後面程式碼不執行 |
p |
列印變數或暫存器值。p &server.port 來輸出 server.port 的地址值;p this 顯示當前物件的地址,p *this 來列出當前物件的各個成員變數值;p func() 命令輸出該變數的執行結果,可以使用 p strerror(errno) 將這個錯誤碼對應的文字資訊列印出來;print也可修改變數值p server.port=6060,修改之後的值對程式後續執行產生影響 print列印較長變數,例如字串和陣列,輸出不全。使用set print element 0設定,可全部輸出 |
|
backtrace | bt | 檢視當前執行緒的呼叫堆疊 |
frame | f | 切換到當前呼叫執行緒的指定堆疊,具體堆疊通過堆疊序號指定 |
thread | thread | 切換到指定執行緒 |
break | b | 新增斷點 |
watch | watch | 監視某一個變數或記憶體地址的值是否發生變化.監視值變化時,斷點命中.監視變數失效後,觀察點也失效 |
list | l |
顯示原始碼.list + 行數,list - 行數.用於向前向後檢視原始碼 list function:以function爲中心列印原始碼 list first,last:列印first到last行 list filename:number:列印檔案中number行前後的原始碼 list number:列印檔案number前後的原始碼 |
info | info |
檢視斷點 / 執行緒等資訊 info program:可檢視進程狀態、停止位置及原因; info line linespec:顯示程式對映的地址; info address symbol:依據符號名顯示地址; info symbol addr:依據地址顯示符號名 |
ptype | ptype | 檢視變數型別,也可檢視複合數據型別的成員名 |
disassemble | dis | 檢視彙編程式碼.set disassembly-flavor intel設定彙編顯示格式 |
jump | j | 將當前程式執行流跳轉到指定行或地址.慎用 |
tbreak | tb | 新增臨時斷點.觸發後刪除 |
delete | del | 刪除斷點.如果後面不跟隨斷點編號,表示刪除所有斷點.delete 3 5 |
enable | enable | 啓用某個斷點.如果後面不跟隨斷點編號,表示啓動所有斷點 |
disable | disable | 禁用某個斷點.如果後面不跟隨斷點編號,表示禁用所有斷點 |
display | display監視變數和記憶體,每次中斷觸發自動輸出變數或記憶體的值。info display檢視當前自動新增哪些值,使用delete display清除自動輸出的變數。使用delete display編號刪除某個自動輸出的變數 | |
set args | 設定程式啓動命令列參數.set args 1 2,多個命令列參數,空格.若參數包含空格,使用引號包裹
使用set args不加參數清除已設定的參數 |
|
show args | 檢視設定的命令列參數 |
info thread檢視程式所有進程/執行緒.星號*表示GDB作用於執行緒.可通過bt檢視呼叫堆疊看是否存在main判斷主進程.bt檢視當前執行緒呼叫堆疊.
info args檢視當前函數的參數值.指針型別參數,輸出變數地址,使用*解除參照輸出物件值
help info 檢視info幫助手冊
因程式碼中經常使用條件編譯方式,生成的可執行程式不一定包含條件程式碼,導致原始碼與gdb偵錯程式碼不匹配。所以建議以gdb list命令的程式碼行號爲準。
可以使用make命令對makefile檔案進行編譯:make CFLAGS="-g -O0" -j 4.
gcc編譯器,使用CFLAGS選項;g++編譯器,使用CXXFLAGS選項。-j表示使用4個進程同時編譯,加快編譯速度.
whatis expr:顯示expr的數據型別
1.break functionname:在函數名上加斷點;
2.break lineNo:在行號上加斷點;
3.break filename:lineNo:在檔案的lineNo行號上加斷點;
4.break filename:functionname:在檔案的functionname上加斷點;
5.break lineNo if condition:條件斷點
6.condition 斷點編號 condition:普通斷點加條件
7.break *address:在沒有偵錯資訊或原始碼,只有地址時很有用
8.break linespec thread threadno 指定執行緒上設定斷點
9.break linespec thread threadno if ... 可以在指定執行緒上設定斷點
GDB顯示字串或字元陣列時,如果數值連續重複n次,GDB將以''{0 \<repeats n times\>}''顯示節約空間
常用函數呼叫方式_cdecl(c語言預設)和_stdcall,c++非靜態成員函數的呼叫方式_thiscall.
catchpoint 斷點用於c++拋出異常和載入庫,catch xxx.catchpoint只能捕獲指定的事件。可通過help catch檢視
watchpoint:只要表達式的值發送變化就停止偵錯。觀察點的實現有可能以軟體或硬體實現,取決於系統。系統儘可能使用硬體斷點,無法設定硬體觀察點,纔會設定軟體觀察點
預設情況下,偵錯程式信號觸發時,信號會被GDB接收.可通過以下方式解決
1.GDB手動使用signal函數發送資訊.signal SIGINT
2.GDB命令中輸入handle SIGINT nostop print改變GDB信號處理設定,通知GDB收到SIGINT不停止並將信號傳遞給目標程式
注:存在斷點失效情況,換種斷點設定方式
多執行緒下偵錯會出現執行過程錯亂,這是由於執行緒切換導致.可以使用set scheduler-locking on 開啓鎖定當前執行緒,禁止執行緒切換;set sheduler-locking off關閉選項.
GDB偵錯程式預設情況下偵錯父進程
1.偵錯父進程,等子進程fork出來後,使用gdb attach到子進程中,但需要開啓一個session視窗偵錯。
2.進程fork出子進程時,通過set follow-fork mode設定偵錯父進程還是子進程.
set follow-fork child偵錯子進程,set follow-fork parent偵錯父進程.show follow-fork mode檢視當前值.
1.gdbtui -q 可執行檔名
2.進入gdb偵錯頁面,快捷鍵Ctrl+X+A顯示GDB TUI
GDB TUI模式提供多個視窗模式,command(cmd),source(src),assembly(asm),register(reg).
使用layout+視窗型別切換視窗,例如layout asm,可以使用help layout檢視手冊;help winheight檢視修改視窗大小手冊;當GDB TUI 視窗放大或縮小後,內容不會重新整理適應新視窗,通過space 空格鍵強行重新整理;通過focus next切換焦點,help focus檢視手冊.
《Debugging with GDB:The The gnu Source-Level Debugger》 書籍介紹了GDB 偵錯知識,pdf版本已儲存在百度雲盤中.