gdb 除錯技巧總結
GDB 基本命令
如果想要使用gdb除錯程式,再編譯時必須加-g
引數。我們可以使用如下兩種方式進行除錯:
-
如果是未啟動的程式名,使用
gdb 程式名
開始除錯當前程式,或者先啟動gdb
,再用file 可執行檔名
來除錯檔案。 -
如果程式已啟動,需要除錯程式的程序,
使用gdb -p 程序ID
,來除錯程序。或者先啟動gdb
,再attach 程序ID
來除錯程序。
主要的命令和用法如下:
命令 | 作用 |
---|---|
directory DIR | 增加目錄 DIR 到搜尋程式程式碼的目錄列表 (如果你的程式程式碼和可執行檔放在同一個目錄下,就不須指定程式程式碼所在目錄) |
l (list) | 從第當前行開始例出原始碼 |
Enter (回車) | 重複上一次輸入的命令 |
b (break) | 設定斷點,如break test.cpp:100 斷行數,break UserManager::GetUser 斷函式 |
clear | 清除斷點,如clear XXX ,XXX格式和上面b的格式相同 |
info break | 檢視斷點資訊 |
delete | 清除斷點,如delete NUM ,NUM是在info break顯示的斷點編號,不加NUM表示刪除所有斷點 |
disable | 禁止斷點,如disable NUM ,NUM是在info break顯示的斷點編號,不加NUM表示禁止所有斷點 |
enable | 啟用斷點,用法和disable類似 |
r (run) | 執行程式 |
bt (backtrace) | 顯示程式堆疊資訊 |
p (print) | 打印表達式的值 |
display | 在斷點的停止的地方,顯示指定的變數的值。 |
set | 設定變數的值。如set val=54 ,將54設定到val變數中 |
n (next) | 在觸發斷點之後,單步執行,不進函式呼叫 |
s (step) | 單步執行,會進入函式呼叫 |
finish | 繼續執行,直到當前函式返回,並在呼叫函式的下一行停止 |
u (until) | 執行一行程式,若此時程式是在 for/while/do loop 迴圈的最後一行,則一直執行到迴圈結束後的第一行程式後停止 |
return |
強制從當前函式返回 |
CTRL + C | 在當前位置停止執行正在執行的程式,斷點在當前行 |
quit | 退出gdb |
gdb 除錯多執行緒
假設現在有一個主執行緒建立了一個子執行緒。
gdb除錯時,設定斷點,單步除錯到pthread_create處的時候,這時候會建立子執行緒,會出現如下資訊
[New Thread 0x7ffff6fd1700 (LWP 6376)]
預設情況下,gdb只跟蹤主執行緒,新建立的執行緒都被阻塞在pthread_create函式處。
info threads
可以除錯的所有執行緒,gdb會為每個執行緒分配一個ID,這個ID和執行緒ID不同,ID號一般從1開始。
如下,表示當前有兩個執行緒1和2,*表示跟蹤主執行緒1
(gdb) info threads
Id Target Id Frame
2 Thread 0x7ffff6fd1700 (LWP 6376) "test" 0x00007ffff70d0851 in clone ()
from /lib64/libc.so.6
* 1 Thread 0x7ffff7fee740 (LWP 6375) "test" main (argc=1, argv=0x7fffffffe2d8) at test.cpp:31
thread ID
切換當前除錯的執行緒為指定ID號,ID是gdb分配的序號,不是執行緒TID。
set scheduler-locking off|on
on鎖定其他執行緒,只有當前選擇除錯的執行緒執行,off表示不鎖定任何執行緒,當執行到斷點處,將所有的執行緒都暫停下來,直到指定某個執行緒繼續執行,如果在當前執行緒下使用continue的話會啟動所有執行緒(GDB預設)。
多執行緒除錯控制指令
thread apply ID1 ID2 ...IDn gdb_command
指定多個執行緒執行gdb中的command指令
thread apply all command
指定所有執行緒執行gdb中的command指令
non-stop模式
上面說過一個執行緒中斷在一個斷點上,其他所有的執行緒都會被freeze。新版本的GDB中,引入了non-stop模式,在這個模式下:
-
當某個或多個執行緒在一個斷點上,其他執行緒仍會並行執行
-
你可以選擇某個被中斷的執行緒,只讓他執行。
-
non-stop模式表示不停止模式,除了斷點有關的程序會被停下來,其他執行緒會繼續執行。
設定non-stop模式,開啟gdb後,在開始r之前,首先連續輸入下面的指令
set target-async 1
set pagination off
set non-stop on
總結除錯多執行緒的命令
info threads
顯示當前可除錯的所有執行緒,每個執行緒會有一個GDB為其分配的ID,後面操作執行緒的時候會用到這個ID。 前面有*的是當前除錯的執行緒
thread ID(1,2,3…)
切換當前除錯的執行緒為指定ID的執行緒
break thread_test.c:123 thread all
(例:在相應函式的位置設定斷點break pthread_run1) 在所有執行緒中相應的行上設定斷點
thread apply ID1 ID2 command
讓一個或者多個執行緒執行GDB命令command
thread apply all command
讓所有被除錯執行緒執行GDB命令command
set scheduler-locking
選項 command 設定執行緒是以什麼方式來執行命令
set scheduler-locking off
不鎖定任何執行緒,也就是所有執行緒都執行,這是預設值
set scheduler-locking on
只有當前被除錯程式會執行
set scheduler-locking on step
在單步的時候,除了next過一個函式的情況(熟悉情況的人可能知道,這其實是一個設定斷點然後continue的行為)以外,只有當前執行緒會執行
執行緒池除錯小技巧
除錯程序池和執行緒池中的程式一個不錯的方法,是將池中的個數減少至1,觀察是否正確,然後逐步增加執行緒數量,除錯執行緒的同步是否正確
gdb 除錯core檔案
什麼是core檔案
如果程式有問題,會產生“段錯誤(核心已轉儲)”時會生成具有堆疊資訊和除錯資訊的檔案,在編譯時需要加-g
選項使程式生成除錯資訊,比如gcc -g test.c -o test
。
怎麼配置生成core檔案
- core檔案開關
使用ulimit -c
檢視core開關,如果為0表示關閉,不會生成core檔案
使用ulimit -c [filesize]
設定core檔案大小,當最小設定為4之後才會生成core檔案
使用ulimit -c unlimited設定core檔案大小為不限制,這是比較推薦的常用做法
- core檔案命名和儲存路徑
core有預設的名稱和路徑,但是開發中通常會自己命名和指定儲存路徑。可以通過/proc/sys/kernel/core_pattern
設定core檔名和儲存路徑,方法如下:
echo "/corefile/core-%e-%p-%t" > /proc/sys/kernel/core_pattern
其中有一些引數含義如下:
%p
:insert pid into filename 新增pid
%u
:insert current uid into filename 添加當前uid
%g
:insert current gid into filename 添加當前gid
%s
:insert signal that caused the coredump into the filename 新增導致產生core的訊號
%t
:insert UNIX time that the coredump occurred into filename 新增core檔案生成時的unix時間
%h
:insert hostname where the coredump happened into filename 新增主機名
%e
:insert coredumping executable name into filename 新增命令名
關於core檔案的除錯
比如現在有一個伺服器程式編譯後的二進位制檔名是GameServer,宕機後生成的core檔案是core.30132。除錯core有以下兩種方法:
方法1:
gdb GameServer core.30132
方法2:
gdb -c core.30132 GameServer
在伺服器開發中,如果伺服器宕機,一般會生成一個core檔案,我們可以用gdb來除錯此core檔案,並使用bt命令檢視函式呼叫堆疊,就可以快速定位到程式的函式。
GDB 分屏操作
在GDB中使用分屏,我們可以很方便的一邊檢視程式碼,一邊輸入命令,主要有以下操作:
layout
:用於分割視窗,可以一邊檢視程式碼,一邊測試。主要有以下幾種用法:
layout src
:顯示原始碼視窗
layout asm
:顯示彙編視窗
layout regs
:顯示原始碼/彙編和暫存器視窗
layout split
:顯示原始碼和彙編視窗
layout next
:顯示下一個layout
layout prev
:顯示上一個layout
Ctrl + L
:重新整理視窗
Ctrl + x,再按1
:單視窗模式,顯示一個視窗
Ctrl + x,再按2
:雙視窗模式,顯示兩個視窗
Ctrl + x,再按a
:回到傳統模式,即退出layout,回到執行layout之前的除錯視窗