01 概念
GDB是一個由GNU開源組織發佈的、UNIX/LINUX操做系統下的、基於命令行的、功能強大的程序調試工具。web
在實際應用中,有兩種調試方法:在線調試和離線調試。sass
離線調試適用於開發測試環境,能夠自由啓停進程,設置斷點;在線調試通常用於現場問題分析,不能隨便啓停進程,對於技術要求較高。多線程
02 前提條件
2.1 編譯
若想執行gdb調試,在Makefile文件中須要增長編譯調試選項-g,例如:app
gdb dup_file.c –o dum_file_elf –g –lpthread函數
說明:-g選項的做用是在可執行文件(ELF)中加入源代碼的相關信息,好比ELF中第幾條機器指令對應源代碼的行數。但不是把整個源文件嵌入到可執行文件中,因此在調試時必須保證gdb能找到源文件。工具
-g完整格式是-glevel,其中,level中指定了調試信息中包含了調試信息的多少,默認的是2,level=1最少,level=3最多。測試
2.2 readelf查看段信息
例如:ui
readelf -S helloWorld|grep debugspa
注:helloWorld爲文件名,若是沒有任何debug信息,則不能被調試。操作系統
2.3 file查看strip情況
下面的狀況也是不可調試的:
file helloWorld
helloWorld: (省略前面內容) stripped
注:若是最後是stripped,則說明該文件的符號表信息和調試信息已被去除,不能使用gdb調試。可是not stripped的狀況並不能說明可以被調試。
03 使用方法
3.1 啓動調試
在開發中能夠將源碼和可執行文件拷貝到某一目錄下,使用gdb啓動進程進行調試,也能夠不拷貝源碼和可執行文件,使用NFS掛載到編譯環境執行調試;在現場環境中使用ps獲取進程的pid,而後gdb –p pid執行在線調試。
離線調試:
gdb 進程名
gdb –tui 進程名
在線調試:
ps –A | grep 進程名
gdb –p pid/gdb attach pid
說明:使用-tui參數能夠將調試窗口分爲兩部分:上面是源碼,下面是調試信息,使用Ctrl+n/Ctrl+p或者方向鍵進行翻頁。
帶參數調試:
一、啓動的時候帶上參數
gdb --args xxx 參數
二、啓動以後 run 帶上參數
# gdb xxx
(gdb)run 參數
三、啓動以後 set args 設置參數
# gdb xxx
(gdb)set args 參數
core文件調試
當程序core dump時,可能會產生core文件,它可以很大程序幫助咱們定位問題。但前提是系統沒有限制core文件的產生。可使用命令limit -c查看:
$ ulimit -c
若是結果是0,即使程序core dump了也不會有core文件留下。咱們須要讓core文件可以產生:
ulimit -c unlimied #表示不限制core文件大小
ulimit -c 10 #設置最大大小,單位爲塊,一塊默認爲512字節
上面兩種方式可選其一。第一種無限制,第二種指定最大產生的大小。
針對生成core文件進行調試,能夠採用在線加載和離線加載的方式,以下:
gdb 可執行文件 core文件
3.2 SET命令
注:有時候使用p打印調試信息不完整或者不便於閱讀,可使用set print elelent 0和setprint pretty on設置。
3.3 handle命令
handle命令
handle SIGUSR1 nostop noprint
handle SIGUSR2 nostop noprint
handle SIGPIPE nostop noprint
handle SIGALARM nostop
handle SIGHUP nostop
handle SIGTERM nostop noprint
注:設置GDB調試時對信號的相關動做。
3.4 設置斷點
打斷點仍是比較有技巧的,雖然有不少打斷點的方法,可是實際調試中通常就使用如下幾種:
函數打斷點:b 函數名
某一行打斷點:b 源文件:行號
條件斷點:
break 斷點 if 條件
continue 斷點編號(執行一次表示設定,再次執行表示取消)
continue 斷點編號 條件
注:條件斷點很是有用,實際調試中每每須要調試特定場景下函數調用關係,此時就須要設置斷點觸發的條件。
查看斷點:info breakpoint/info break/info b
刪除斷點:delete 斷點號/delete(刪除全部斷點)
禁用/開啓斷點:disable/enable breakpoint
ignore:
斷點條件的一個特殊用法是,程序只有在到達斷點必定次數以後纔會中止,此時可使用指令:
ignore 斷點編號 次數
ignore 2 10觸發斷點10次後纔會中止,每次觸發斷點count自動減1
說明:打完斷點是否是執行continue就能夠等待着運行到斷點了呢?不必定,有時候斷點處代碼的執行須要外部出發,好比web發送特定消息後才能夠觸發執行,若是一直等待沒有消息出發永遠執行不到斷點處,此時就須要結合本身的業務邏輯,手動設置出發條件。
3.5 執行程序
執行程序的方法有兩種:一種是從main函數開始執行逐步分析,一種是執行到斷點處。
從新運行:r/run
繼續執行:c/continue
單步執行:n/next/next N(執行N次next)
單步進入:step(遇到函數進入函數內部,退出函數時使用finish)
結束函數:finish
強制返回:return(忽略當前未執行的部分,強制返回)
3.6 顯示堆棧
(gbd) backstrace/bt
有時候跳轉的次數太多,不知道具體調用的層級關係了,可使用bt查看堆棧,該命令會產生一張列表,包含着運行過程和相關的參數。
3.7 變量操做
設置變量:set 變量=表達式
在調試的時候,有時候須要設置一些假數據查看對應輸出,好比根據布爾值查看流程執行狀況,此時就須要在執行到指定位置時手動設置一下數據的取值。
監控變量:
watch 變量 (數值改變時暫停運行)
awatch <表達式> (被訪問或改變時暫停運行)
rwatch <表達式> (被訪問時暫停運行)
有時候咱們須要觀察一個變量的變化過程,好比一個全局變量如何初始化,如何調用的,這就須要使用watch監控變量。
變量類型:
ptype var 變量類型
whatis var 顯示一個變量var的類型
打印變量/表達式:
打印變量:p 變量
打印字符/表達式:p 「%s」,字符/表達式
格式化輸出:p/格式控制符 打印內容
說明:
gdb可支持的變量顯示格式有:
x:按16進制格式顯示變量
d:按10進制格式顯示變量
u:按16進制格式顯示無符號整型
o:按8進制格式顯示變量
t:按2進制格式顯示變量
c:按字符格式顯示變量
f:按浮點數格式顯示變量
也可使用x(Examination)來打印須要顯示的字符信息,格式以下:
x/格式 地址
格式(可選)通常是NFU:
一、N表示重複次數(表示顯示內存的長度,也就是說從當前向後顯示幾個地址的內容)
二、F表示顯示格式
三、U表示單位(b:字節,h:半字[2字節],w:字[4字節,默認],g:雙字[8字節])。表示多少個字節做爲一個值取出來,若是不指定的話,GDB默認是1個byte,當咱們指定了字節長度後,GDB會從指定內存的地址開始,讀取指定字節,並把其做爲一個值取出來。
參數u可以使用下面字符代替:
b:表示單字節
h:表示雙字節
w:表示四字節
g:表示八字節
3.8 調試函數
disassemble
可使用反彙編的指令disassemble去探究究竟在函數中發生了哪些操做,具體以下:
一、disassemble
二、disassemble 程序計數器
三、disassemble 開始地址 結束地址
格式1表示反彙編當前整個函數,格式2表示反彙編計數器所在函數的整個函數,格式3表示反彙編從開始地址到結束地址的部分。
call
強制調用函數:call 表達式
3.9 退出調試
q/quit
在執行到斷點後,採用q/quit指令退出。
04 多進程調試
4.1 配置
detach-on-fork
該屬性決定了gdb是同時調試父子進程,仍是在fork了子進程以後,將子進程分離出去。
on:子進程(或者父進程,取決於gdb在初始時,要調試的進程,也就是follow-fork-mode的值)
off:同時調試父子進程,一個進程處於被調試的狀態,而另外一個則被gdb掛起
設置:set detach-on-fork on/off
follow-fork-mode
該屬性決定了gdb在進程調用fork以後的行爲。
set follow-fork-mode parent:默認狀況下,在調用fork以後,gdb選擇跟隨(也就是調試)父進程,而子進程則在處於運行的狀態(此時父進程處於阻塞的狀態)。
set follow-fork-mode child:fork以後gdb選擇調試子進程,而父進程處於運行的狀態。
4.2 查看進程
查看當前調試的進程:info inferiors
05 多線程調試
5.1查看線程
查看線程:info threads
注:輸出信息前面有「*」表示調試的當前線程(通常thread切換線程後查看)。
有的程序會在運行過程當中主線程建立多個子線程,因此先後執行info threads顯示的線程數是會動態變化的。
5.2 查看線程堆棧
查看全部線程堆棧:thread apply all bt
查看指定線程堆棧:thread apply thread1 thread2... bt
5.3 切換線程
切換線程:thread N
注:經過打印counter,能夠看到多個線程都是在運行的,若是想要讓其餘線程處於中止狀態,只有當前調試的線程執行,能夠採用set scheduler-locking on。
5.4 阻塞線程
阻塞其餘線程,僅調試當前線程工做:
set scheduler-locking [on|off|step]
運行指定線程並容許其餘線程並行執行:
thread apply N command
06 總結
對於C語言開發,必須熟練使用gdb進行調試,這能夠幫助咱們快速定位問題並解決問題,在開發中能夠幫助咱們及時找到測試出現的問題,在現場問題中若是日誌打印不是很充分,日誌信息量不夠的狀況下,gdb調試顯得很是重要。
在實際應用中,咱們一般是利用gdb分析core文件,這就須要結合寄存器,彙編,內存相關知識綜合分析,後面會詳細介紹相關分析技巧。