1. 程式人生 > 實用技巧 >gdb 除錯技巧總結

gdb 除錯技巧總結

GDB 基本命令

如果想要使用gdb除錯程式,再編譯時必須加-g引數。我們可以使用如下兩種方式進行除錯:

  1. 如果是未啟動的程式名,使用gdb 程式名開始除錯當前程式,或者先啟動gdb,再用file 可執行檔名來除錯檔案。

  2. 如果程式已啟動,需要除錯程式的程序,使用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模式,在這個模式下:

  1. 當某個或多個執行緒在一個斷點上,其他執行緒仍會並行執行

  2. 你可以選擇某個被中斷的執行緒,只讓他執行。

  3. 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之前的除錯視窗