gdb 入門
簡介
gdb是GNU開源組織發布的一個強大的Linux下的程序調試工具。
一般來說,GDB主要幫助你完成下面四個方面的功能:
1、啟動你的程序,可以按照你的自定義的要求隨心所欲的運行程序。
2、可讓被調試的程序在你所指定的調置的斷點處停住。(斷點可以是條件表達式)
3、當程序被停住時,可以檢查此時你的程序中所發生的事。
4、你可以改變你的程序,將一個BUG產生的影響修正從而測試其他BUG。
gdb可以調試的對象
gdb 可以調試的語言
Ada, Assembly, C, C++, D, Fortran, Go, Objective-C, OpenCL, Modula-2, Pascal, Rust
gdb 可以調試的文件類型
注意在編譯時需要加上-g
選項。gdb可以調試的文件類型有三種:
-
二進制文件。
gdb a.out
-
core文件。通常,我們在遇到錯誤時得到一個core文件(如果沒有,請通過
ulimit -a
命令查看core file siez
是否為0,若為0,通過ulimit -c unlimited
改為unlimited
即可)gdb a.out core.12345
-
運行中的進程,其中
[1234]
時要調試的進程號gdb -p 1234
gdb的常用命令(入門)
本小節僅介紹入門級的常用命令,稍微進階的用法會慢慢補全。
以下索引表解釋常用命令基本的含義,有些細節會在下一小節具體說。
命令(簡寫) | 含義 |
---|---|
help (h) | 查看命令幫助 |
run (r) | 重新開始運行文件 |
run argv[1] argv[2] | 調試時命令行傳參 |
start | 單步執行,運行程序,停在第一執行語句 |
list (l) | 查看源代碼 |
set | 設置變量的值 |
next (n) | 單步調試(逐過程,函數直接執行) |
step (s) | 單步調試(逐語句,跳入自定義函數內部執行) |
braktrace (bt) | 查看函數的調用的棧幀和層級關系 |
frame (f) | 切換函數的棧楨 |
info (i) | 查看函數內部局部變量的值 |
finish | 結束當前函數,返回到調用點 |
continue (c) | 繼續運行(至下一個斷點或程序結束) |
print (p) | 打印值 |
quit (q) | 退出gdb |
break (b) | 設置斷點 |
info breakpoints(i break) | 查看當前設置的所有斷點 |
enable/disable breakpoints | 啟用 / 禁用斷點 |
delete num(d num) | 刪除第num個斷點 |
display | 追蹤查看具體的變量值 |
undisplay | 取消追蹤觀察變量 |
watch | 被設置觀察點的變量發生修改時,打印顯示 |
info watchpoints(i watch) | 顯示觀察點 |
x | 查看內存x/20xw 顯示20個單元,16進制,4字節每單元 |
幾個常用的命令詳解
list
list
可簡寫為l
,可以列出所調試程序的代碼
list linenumber
:列出linenumber附近的代碼list function
:列出某個函數附近的源代碼
break
gdb調試時使用break命令來設置斷點,簡寫為b,有如下幾種下斷點地方法:
-
break function
:在進入指定的函數function處打斷點,C++中可以使用class::function或function(type, type)格式來指定函數名稱break filename:function
:在指定文件的指定函數處打斷點 -
break linenumber
:在指定的行數打斷點break filename:linenumber
:在指定文件的指定行數打斷點 -
break +/- offeset
:在當前行的前面或后面打斷點 -
break *address
:在程序運行的指定地址出打斷點 -
break
:在下一條命令處停止運行 -
break .. if condition
:在在處理某些循環體中可使用此方法進行調試,其中…可以是上述的break lineNumber
、break +/-offset
中的參數,其中condition表示條件,在條件成立時程
序即停止運行,如設置break if i=100
表示當i為100時程序停止運行。
查看斷點時,也可以使用info
命令如info breakpoints [n]、info break [n]
其中n
表示斷點號來查看斷點信息。
可以通過delete
命令刪除所有的斷點
next
使用next命令單步執行程序代碼,next的單步不會進入函數的內部,與next對應的step命令則在單步執行一個函數時進入函數內部,類似于VC++中的step into,其用法為next count
,單步跟蹤,如果有函數調用不會進入函數,如果后面不加count表示一條一條的執行,加count表示執行后面的count條指令。
continue
continue
:當程序遇到斷點停下來之后,可以執行continue繼續執行到下一個斷點或到程序結束。
簡寫為p,可以通過print命令查看參數或程序運行數據
值得注意的是print輸出可以指定顯示變量的輸出格式:
符號 | 輸出格式 |
---|---|
x | 十六進制 |
d | 十進制 |
u | 十六進制無符號數 |
o | 八進制 |
t | 二進制 |
c | 字符格式 |
f | 浮點數格式 |
print可以輸出東西可多:全局變量,靜態全局變量,局部變量,如果你的局部變量和全局變量發生沖突(也就是重名),一般情況下是局部變量會隱藏全局變量。
-
全局變量利用
::
,例如在1.c中看x:(gdb)p "1.c"::x
-
數組(動):
p *array@len
array:數組的首地址,len:數據的長度 -
數組(靜):直接p數組名
-
所有寄存器的值:
info registers
-
查看指定的寄存器的值:
p $eip
-
結構體。如果你想很漂亮的輸出結構體請設置
set print pretty on
,打開print pretty這個東西,沒錯,輸出很漂亮滴。
disassemble
用disassemble function
來查看匯編代碼,如下圖示某個main函數的反匯編代碼:
我們可以通過反匯編代碼的偏移量來在匯編代碼中打上斷點,比如我們想要在圖中紅色箭頭處打斷點,只需b *main+45
。
我們可以通過disassemble /m function
指令,來將C/C++源代碼和其反匯編一起顯示,這樣會更加直觀:
backtrace
可以簡寫為bt,功能為顯示函數的棧。
當你的程序調用了一個函數,函數的地址,函數參數,函數內的局部變量都會被壓入“棧”(Stack)中。你可以用這條命令來查看當前的棧中的所有信息。
在遞歸時可以很方便地查看棧上各個遞歸函數的棧幀:
圖中的Delete函數會被遞歸調用,功能時刪除二叉搜索樹種的某個節點,具體功能不重要,這里是為了展示遞歸函數多層遞歸時通過backtrace
來查看棧幀信息。
顯示棧頂的幾個層的信息:bt n
顯示棧底下的幾層信息:bt -n
但是,如果要查看某一層的信息,你需要在切換當前的棧,一般來說,程序停止時,最頂層的棧就是當前棧,如果你要查看棧下面層的詳細信息,首先要做的是切換當前棧。這就要用到下面的frame
命令。
frame
可以簡寫為f,n是一個從0開始的整數,是棧中的層編號。比如:frame 0,表示棧頂,即當前函數的棧幀,frame 1,表示棧的第二層,即調用當前函數的函數的棧幀。
up n
:表示向棧的上面移動n層,可以不打n,表示向上移動一層。
down n
:表示向棧的下面移動n層,可以不打n,表示向下移動一層。
info f
:會打印出更為詳細的當前棧層的信息。
layout
用于分割窗口,可以一邊查看代碼,一邊測試。如下圖是layout src
的窗口展示:
命令及參數 | 功能 |
---|---|
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之前的調試窗口。
Ref
https://www.gnu.org/software/gdb/
https://blog.csdn.net/awm_kar98/article/details/82840811
http://blog.chinaunix.net/uid-29611934-id-5168746.html