其餘相關內容可參考個人部落格
show language
可檢視當前偵錯環境語言
set language
可檢視GDB支援的所有語言種類
set language <語言>
可設定當前偵錯環境語言
What is GDB?
GDB, the GNU Project debugger, allows you to see what is going on `inside’ another program while it executes – or what another program was doing at the moment it crashed.
GDB can do four main kinds of things (plus other things in support of these) to help you catch bugs in the act:
1.Start your program, specifying anything that might affect its behavior.
2.Make your program stop on specified conditions.
3.Examine what has happened, when your program has stopped.
4.Change things in your program, so you can experiment with correcting the effects of one bug and go on to learn about another.
Those programs might be executing on the same machine as GDB (native), on another machine (remote), or on a simulator. GDB can run on most popular UNIX and Microsoft Windows variants, as well as on Mac OS X.
set args
備註:stop可暫停程式執行,使用info program可檢視程式執行狀態即停止原因
掛接到已在執行的進程來偵錯 attach <process-id>
attach時,再次run,可將原進程殺掉,從頭執行程式
可以使用pidof 進程名來獲得進程ID
檢視原始碼list,縮寫l
(gdb) set listsize 20
(gdb) show listsize
Number of source lines gdb will list by default is 20.
search
可使用該命令搜尋函數、變數等
注意使用時在地址前面加入*
。若你需要打斷點的函數存在若幹(函數過載),這是GDB會給你列出一個所有該函數的列表,可自行選擇
補充:在程式執行時,若沒有遇到斷點,可直接輸入crtl+c停止程式執行,進入GDB命令列
斷點條件管理
condition breakNum expr
修改斷點的停止條件爲expr
,condition breakNum
清除斷點的停止條件ignore breakNUm count
忽略斷點count次上述breakNum均爲info b中顯示的斷點號
執行緒斷點
當你的程式是多執行緒時,你可以定義你的斷點是否在所有的執行緒上,或是在某個特定的執行緒。
break line thread threadNo
其中line
爲你的原始碼行數,threadNo爲info threads
命令中GDB給出的執行緒ID,若不指定threadNo
,則爲所有執行緒打斷點。
範例如下
(gdb) b 27
Breakpoint 1 at 0x400777: file main.c, line 27.
(gdb) b 28
Breakpoint 2 at 0x400785: file main.c, line 28.
(gdb) b 29
Breakpoint 3 at 0x40078f: file main.c, line 29.
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000400777 in main at main.c:27
2 breakpoint keep y 0x0000000000400785 in main at main.c:28
3 breakpoint keep y 0x000000000040078f in main at main.c:29
(gdb) disable 1
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep n 0x0000000000400777 in main at main.c:27
2 breakpoint keep y 0x0000000000400785 in main at main.c:28
3 breakpoint keep y 0x000000000040078f in main at main.c:29
(gdb) enable 1
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000400777 in main at main.c:27
2 breakpoint keep y 0x0000000000400785 in main at main.c:28
3 breakpoint keep y 0x000000000040078f in main at main.c:29
(gdb) clear 27
Deleted breakpoint 1
(gdb) info b
Num Type Disp Enb Address What
2 breakpoint keep y 0x0000000000400785 in main at main.c:28
3 breakpoint keep y 0x000000000040078f in main at main.c:29
可設定捕捉點來補捉程式執行時的一些事件。如:載入共用庫(動態鏈接庫)或是C++的異常。設定捕捉點的格式爲:
catch event
當event發生時,停住程式。event可以是下面 下麪的內容:
tcatch event
只設置一次捕捉點,當程式停住以後,應點被自動刪除。
step
單步跟蹤,如果有函數呼叫,會進入該函數,縮寫爲 s
next
單步跟蹤,如果有函數呼叫,不會進入該函數,縮寫爲n
單步執行加入i參數可單補執行彙編程式碼
finish
執行直到選擇的棧幀返回,縮寫爲 fin(即執行到當前函數返回)
continue
當gdb遇到斷點停下時,恢復程式執行,縮寫爲 c
print
print/f
,列印變數或表達式的值,縮寫爲 p,其中/f
爲可選參數,可指定列印輸出格式,並且使用該命令可以直接給變數或者表達式賦值
若區域性變數和全域性變數衝突,或想列印其他檔案或函數中的某個變數時,可用
file::variable
function::variable來指示
(gdb) p a
$9 = 100
(gdb) p a=10
$10 = 10
(1)列印陣列或記憶體內容
p 陣列名稱
,若變數本身就是陣列,這樣可列印陣列內容p *指針@個數
,若變數爲動態申請的記憶體,想要按照指針型別列印內容,可使用該方式範例如下:
(gdb) p testArray
$1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}
(gdb) p pTmp
$2 = (int *) 0x602010
(gdb) p *pTmp@10
$3 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}
(2)若字串過長,或者陣列過大,則可以設定print列印的元素個數來顯示完全
set print elements number-of-elements
,設定顯示元素個數
show print elements
,檢視顯示元素個數
set print null-stop <on><off>
,如果打開了這個選項,那麼顯示字串時則遇到結束符停止顯示,預設關閉
show print null-stop
(gdb) p testArray
$4 = "global_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_te"...
(gdb) set print elements 1000
(gdb) p testArray
$5 = "global_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_testglobal_array_t"...
(3)設定列印結構體或者類時,將成員分行列印,避免堆積在一起不易檢視
set print pretty <on><off>
,開啓/關閉分行列印
show print pretty
,檢視當前顯示形式
(gdb) p testStruct
$1 = {para1 = 100, para2 = 200, testArray = "global_array_testglobal_array_testglobal_array_testglobal_array_"}
(gdb) set print pretty
(gdb) p testStruct
$2 = {
para1 = 100,
para2 = 200,
testArray = "global_array_testglobal_array_testglobal_array_testglobal_array_"
}
(4)設定列印陣列時,每個元素單獨佔一行
set print array <on><off>
,開啓/關閉元素獨佔一行的方式
show print array
,檢視當前顯示形式
(gdb) p testArray
$4 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}
(gdb) set print array on
(gdb) p testArray
$5 = {1,
2,
3,
4,
5,
6,
7,
8,
9,
0}
(5)設定顯示結構體時,是否顯示其內的聯合體數據
set print union <on><off>
,開啓/關閉顯示其內的聯合體數據
show print union
,檢視當前顯示形式
(6)檢視歷史數據
在每次使用print
命令時,GDB都會爲其輸出編號:$1,$2,$3等
show value
列印所有歷史數據
show value n
列印以n爲中心的10條歷史數據
show value +
列印上次顯示的歷史數據的之後10條歷史數據
watch
如果給出了 -l 或者 -location,則它會對 expr 求值並觀察它所指向的記憶體。例如,watch *(int *)0x12345678 將在指定的地址處觀察一個 4 位元組的區域(假設 int 佔用 4 個位元組)
display
display/fmt <expr><addr>
每次程式停止時列印expr
表達式或addr
地址中的內容的值(自動顯示)
fmt
爲顯示格式,且支援i參數顯示彙編程式碼
關於display的相關控制命令:
undisplay <num>
,刪除自動顯示項enable <num>
,使能自動顯示項disable <num>
,失能自動顯示項(不刪除)info display
,檢視display的相關資訊,上述三個命令的參數均爲info display中列出的num
範例如下
(gdb) display a
1: a = 10
(gdb) info display
Auto-display expressions now in effect:
Num Enb Expression
1: y a
(gdb) display b
2: b = 2
(gdb) info display
Auto-display expressions now in effect:
Num Enb Expression
2: y b
1: y a
(gdb) undisplay 1
(gdb) info display
Auto-display expressions now in effect:
Num Enb Expression
2: y b
(gdb) c
Continuing.
progran is start
Breakpoint 5, main () at main.c:29
29 test();
2: b = 2
(gdb)
examine
檢視記憶體,縮寫爲x,用法: x/nfu <addr>
n、f 和 u 都是可選參數,用於指定要顯示的記憶體以及如何格式化。addr 是要開始顯示記憶體的地址的表達式。
n 重複次數(預設值是 1),指定要顯示多少個單位(由 u 指定)的記憶體值。
f 顯示格式(初始預設值是 x),顯示格式是 print(‘x’,‘d’,‘u’,‘o’,‘t’,‘a’,‘c’,‘f’,‘s’) 使用的格式之一,再加 i(機器指令)。
u 單位大小,b 表示單位元組,h 表示雙位元組,w 表示四位元組,g 表示八位元組。
例如
(gdb) x &a
0x7fffffffe47c: 0x0000000a
(gdb) x/d &a
0x7fffffffe47c: 10
(gdb) x &b
0x7fffffffe478: 2
(gdb) x/4x &b
0x7fffffffe478: 0x00000002 0x0000000a 0x00000000 0x00000000
info register
檢視暫存器的值,其中register可簡寫爲reg
info register
,檢視暫存器(除了浮點暫存器)
info all-register
,檢視所有暫存器(包括浮點暫存器)
info register regName
,檢視指定暫存器regName
的內容
(gdb) info reg
rax 0x4006e7 4196071
rbx 0x0 0
rcx 0x400730 4196144
rdx 0x7fffffffe578 140737488348536
rsi 0x7fffffffe568 140737488348520
rdi 0x1 1
rbp 0x7fffffffe480 0x7fffffffe480
rsp 0x7fffffffe480 0x7fffffffe480
r8 0x7ffff7dd5e80 140737351868032
r9 0x0 0
r10 0x7fffffffdfa0 140737488347040
r11 0x7ffff7a2f410 140737348039696
r12 0x4005b0 4195760
r13 0x7fffffffe560 140737488348512
r14 0x0 0
r15 0x0 0
rip 0x4006eb 0x4006eb <main+4>
eflags 0x246 [ PF ZF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
檢視程式呼叫棧的資訊,縮寫爲 bt, 加入full參數,bt full
可列印出所有的變數資訊
backtrace n
n爲正整數,表示之列印棧頂上n層的棧資訊backtrace -n
-n爲負數,表示之列印棧底n層的棧資訊frame n
n爲正整數,表示第幾層棧,frame可簡寫爲f,使用該命令可切換當前你關注的棧資訊up n
n爲正整數,該命令表示向棧的上面移動n層down n
n爲正整數,該命令表示向棧的下面 下麪移動n層select-frame
對應於 frame
命令up-silently n
對應於 up
命令down-silently n
對應於 down
命令info frame
該命令可列印出當前棧的詳細資訊
info args
列印當前棧的argumentsinfo locals
列印當前函數中的所有區域性變數及其值info catch
列印出當前的函數中的例外處理資訊(gdb) bt
#0 add (a=1, b=2) at add.cpp:6
#1 0x00000000004007d4 in main () at main.c:32
(gdb) bt full
#0 add (a=1, b=2) at add.cpp:6
No locals.
#1 0x00000000004007d4 in main () at main.c:32
testStruct = {
para1 = 100,
para2 = 200,
testArray = "global_array_testglobal_array_testglobal_array_testglobal_array_"
}
strArray = "local_array_test"
a = 10
b = 1634890337
我們可以使用GDB提供的commands
命令來設定停止點的執行命令。當執行的程式在被停止住時,可使其執行指定命令,這很有利行自動化偵錯。對基於GDB的自動化偵錯是一個強大的支援,格式如下:
commands [breakNum]
... command-list ...
end
爲斷點號breakNum指寫一個命令列表。當程式被該斷點停住時,gdb會依次執行命令列表中的命令。
注意設定時,先輸入commands [breakNum],然後GDB會提示你繼續輸入命令列表,一行一個命令
範例如下,一圖流 ♪(^∀^●)ノ:
如果你要清除斷點上的命令序列,那麼只要簡單的執行一下commands
命令,並直接在打個end
就行了。
某些時候,用-g編譯過後的執行程式中只是包括了原始檔的名字,沒有路徑名。GDB提供了可以讓你指定原始檔的路徑的命令,以便GDB進行搜尋。
現在大部分執行程式中都會包括原始檔的路徑,可簡單使用nm -l命令檢視,可發現每個符號後都有原始檔的路徑、名稱和行號
GDB可以在沒有原始碼的情況下偵錯,但只能偵錯彙編程式碼
directory dirname ...
使用該命令可指定原始檔路徑,其中directory可簡寫爲dir
directory
可清除所有的自定義原始檔路徑
show directory
可檢視自定義原始檔路徑
(gdb) dir /home
Source directories searched: /home:$cdir:$cwd
(gdb) show dir
Source directories searched: /home:$cdir:$cwd
(gdb) dir
Reinitialize source path to empty? (y or n) y
Source directories searched: $cdir:$cwd
(gdb) show dir
Source directories searched: $cdir:$cwd
其實這裏就是檢視程式執行時,原始碼在記憶體當中的地址
info line + <line><func><file:line><file:func>
使用disassemble命令可直接檢視原始碼的彙編程式碼,其中會同時顯示載入地址
disassemble <func><'file'::func><start,end><start,+length>
命令可檢視彙編程式碼,具體參數介紹如下
/m
,同時列印原始碼/r
,同時列印16進位制機器碼func
,列印指定函數的彙編程式碼'file'::func
,列印指定檔案中的某個函數的彙編程式碼,格式必須按照前面的寫,注意單引號start,end
,列印start到end地址之間的彙編程式碼start,+length
,列印start到start+length之間的彙編程式碼原文如下:
(gdb) help disas
Disassemble a specified section of memory.
Default is the function surrounding the pc of the selected frame.
With a /m modifier, source lines are included (if available).//同時列印原始碼
With a /r modifier, raw instructions in hex are included.//同時列印16進位制機器碼
With a single argument, the function surrounding that address is dumped.
Two arguments (separated by a comma) are taken as a range of memory to dump,
in the form of "start,end", or "start,+length".
Note that the address is interpreted as an expression, not as a location
like in the "break" command.
So, for example, if you want to disassemble function bar in file foo.c
you must type "disassemble 'foo.c'::bar" and not "disassemble foo.c:bar".
在GDB中可以根據自己的偵錯思路來動態地在GDB中更改當前被偵錯程式的執行線路或是其變數的值
博主在學習了函數呼叫的堆疊變化後,曾嘗試在GDB中通過改變暫存器的值,達到改變執行路線的效果,原來GDB直接提供了這個功能
具體的嘗試見另一篇文章《GDB偵錯之改變程式執行流程》
改變變數值
print a=100
,使用print命令即可直接改變變數值
跳轉執行
jump line
,指定下一條語句的執行點
jump *address
,指定下一條語句的執行地址
注意,jump命令不會改變當前的程式棧中的內容,所以,當你從一個函數跳到另一個函數時,當函數執行完返回時進行彈棧操作時必然會發生錯誤,所以最好是同一個函數中進行跳轉。
而博主的那篇文章則是使用改變棧內容達到安全呼叫和返回的效果的,和GDB的jump還是有些不同的,嘿嘿