啟動
在shell下敲gdb命令即可啟動gdb,啟動后會顯示下述信息,出現(xiàn)gdb提示符。
???example?gdb????????????????????????????????
GNU?gdb?(Ubuntu?8.1.1-0ubuntu1)?8.1.1
Copyright?(C)?2018?Free?Software?Foundation,?Inc.
License?GPLv3+:?GNU?GPL?version?3?or?later?<http://gnu.org/licenses/gpl.html>
This?is?free?software:?you?are?free?to?change?and?redistribute?it.
There?is?NO?WARRANTY,?to?the?extent?permitted?by?law.??Type?"show?copying"
and?"show?warranty"?for?details.
This?GDB?was?configured?as?"x86_64-linux-gnu".
Type?"show?configuration"?for?configuration?details.
For?bug?reporting?instructions,?please?see:
<http://www.gnu.org/software/gdb/bugs/>.
Find?the?GDB?manual?and?other?documentation?resources?online?at:
<http://www.gnu.org/software/gdb/documentation/>.
For?help,?type?"help".
Type?"apropos?word"?to?search?for?commands?related?to?"word".
(gdb)
測試代碼
#include?<stdio.h>
int?minus(int?a,int?b){
???printf("In?minus():n");?
???int?c?=?a-b;
????return?c;
}
int?sum(int?a,?int?b)?{
????printf("In?sum():n");
?int?c?=?a+b;
????return?c;
}
void?print(int?xx,?int?*xxptr)?{
??printf("In?print():n");
??printf("???xx?is?%d?and?is?stored?at?%p.n",?xx,?&xx);
??printf("???ptr?points?to?%p?which?holds?%d.n",?xxptr,?*xxptr);
??int?c?=?sum(2,3);
??int?d?=?minus(3,2);
}
int?main(void)?{
??int?x?=?10;
??
??int?*ptr?=?&x;
??printf("In?main():n");
??printf("???x?is?%d?and?is?stored?at?%p.n",?x,?&x);
??printf("???ptr?points?to?%p?which?holds?%d.n",?ptr,?*ptr);
??
??print(x,?ptr);
??return?0;
}
設(shè)置斷點
可以在函數(shù)名和行號等上設(shè)置斷點。程序運行后,到達斷點就會自動暫停運行。此時可以查看該時刻的變量值、顯示棧幀、重新設(shè)置斷點或重新運行等。斷點命令(break)可以簡寫為b。
格式
break?斷點
舉例
(gdb)?b?main
Breakpoint?1?at?0x758:?file?gdb_example.c,?line?9.
格式
break?函數(shù)名
break?行號
break?文件名:行號
break?文件名:函數(shù)名
break??+?偏移量
break??-?偏移量
break??*?地址
舉例
(gdb)?b?print
Breakpoint?2?at?0x709:?file?gdb_example.c,?line?4.
(gdb)?b?gdb_example.c:5
Breakpoint?3?at?0x715:?file?gdb_example.c,?line?5.
(gdb)?b?+3
Note:?breakpoint?2?also?set?at?pc?0x709.
Breakpoint?4?at?0x709:?file?gdb_example.c,?line?4.
(gdb)?b?*0x709
Note:?breakpoints?2?and?4?also?set?at?pc?0x709.
Breakpoint?5?at?0x709:?file?gdb_example.c,?line?4.
(gdb)
上面的例子分別對print函數(shù),gdb_example.c第5行,現(xiàn)在暫停位置往后第3行,地址0x709設(shè)置斷點。
設(shè)置好的斷點可以通過info break 確認(rèn)
(gdb)?info?break
Num?????Type???????????Disp?Enb?Address????????????What
1???????breakpoint?????keep?y???0x0000000000000758?in?main?at?gdb_example.c:9
2???????breakpoint?????keep?y???0x0000000000000709?in?print?at?gdb_example.c:4
3???????breakpoint?????keep?y???0x0000000000000715?in?print?at?gdb_example.c:5
4???????breakpoint?????keep?y???0x0000000000000709?in?print?at?gdb_example.c:4
5???????breakpoint?????keep?y???0x0000000000000709?in?print?at?gdb_example.c:4
顯示棧幀
backtrace命令可以在遇到斷點而暫停執(zhí)行時顯示棧幀。該命令簡寫為bt。此外, backtrace的別名還有where和info stack(簡寫為info s)。
backtrace
bt
顯示所有棧幀
backtrace?N
bt?N
只顯示開頭N個棧幀
backtrace?-N
bt?-N
只顯示最后N個棧幀
backtrace?full
bt?full
backtrace?full?N
bt?full?N
backtrace?full?-N
bt?full?-N
舉例
(gdb)?b?4
Breakpoint?1?at?0x714:?file?gdb_example.c,?line?4.
(gdb)?r
Starting?program:?/home/zhongyi/code/example/gdb_example?
In?main():
???x?is?10?and?is?stored?at?0x7fffffffe2fc.
???ptr?points?to?0x7fffffffe2fc?which?holds?10.
In?print():
???xx?is?10?and?is?stored?at?0x7fffffffe2cc.
???ptr?points?to?0x7fffffffe2fc?which?holds?10.
In?sum():
In?minus():
Breakpoint?1,?minus?(a=3,?b=2)?at?gdb_example.c:4
4??????????int?c?=?a-b;
#?顯示棧幀
(gdb)?bt
#0??minus?(a=3,?b=2)?at?gdb_example.c:4
#1??0x00005555555547c0?in?print?(xx=10,?xxptr=0x7fffffffe2fc)?at?gdb_example.c:17
#2??0x0000555555554841?in?main?()?at?gdb_example.c:28
#只顯示前2個棧幀
(gdb)?bt?2
#0??minus?(a=3,?b=2)?at?gdb_example.c:4
#1??0x00005555555547c0?in?print?(xx=10,?xxptr=0x7fffffffe2fc)?at?gdb_example.c:17
(More?stack?frames?follow...)
#?從外向內(nèi)顯示2個棧幀,及其局部變量
(gdb)?bt?full?-2
#1??0x00005555555547c0?in?print?(xx=10,?xxptr=0x7fffffffe2fc)?at?gdb_example.c:17
????????c?=?5
????????d?=?21845
#2??0x0000555555554841?in?main?()?at?gdb_example.c:28
????????x?=?10
????????ptr?=?0x7fffffffe2fc
(gdb)?
顯示棧幀后,就可以確認(rèn)程序在何處停止,及程序的調(diào)用路徑。
顯示變量
格式
print?變量
舉例
(gdb)?p?x
$1?=?10
(gdb)?p?ptr
$2?=?(int?*)?0x7fffffffe2fc
(gdb)?
顯示寄存器
舉例
(gdb)?info?reg
rax????????????0xc??????12
rbx????????????0x0??????0
rcx????????????0x7ffff7af2104???140737348837636
rdx????????????0x7ffff7dcf8c0???140737351841984
rsi????????????0x555555756260???93824994337376
rdi????????????0x1??????1
rbp????????????0x7fffffffe310???0x7fffffffe310
rsp????????????0x7fffffffe2f0???0x7fffffffe2f0
r8?????????????0x7ffff7fe14c0???140737354011840
r9?????????????0x0??????0
r10????????????0x0??????0
r11????????????0x246????582
r12????????????0x5555555545f0???93824992232944
r13????????????0x7fffffffe3f0???140737488348144
r14????????????0x0??????0
r15????????????0x0??????0
rip????????????0x555555554841???0x555555554841?<main+123>
eflags?????????0x202????[?IF?]
cs?????????????0x33?????51
ss?????????????0x2b?????43
ds?????????????0x0??????0
es?????????????0x0??????0
fs?????????????0x0??????0
gs?????????????0x0??????0
寄存器前加$,可以顯示寄存器的內(nèi)容。
(gdb)?p?$rdi
$7?=?1
(gdb)?p?$rax
$8?=?12
(gdb)?
顯示寄存器可以用以下格式
p/格式 變量
格式 | 說明 |
---|---|
x | 顯示為16進制數(shù) |
d | 顯示為十進制數(shù) |
u | 顯示為無符號十進制數(shù) |
o | 顯示為八進制數(shù) |
t | 顯示為二進制數(shù) |
a | 地址 |
c | 顯示為ascii |
f | 浮點小數(shù) |
s | 顯示為字符串 |
i | 顯示為機器語言(僅在顯示內(nèi)存的x命令中可用) |
顯示內(nèi)存
x命令可以顯示內(nèi)存的內(nèi)容
格式
x/格式?地址
舉例
(gdb)?x?$r12
???0x5555555545f0?<_start>:?????xor????%ebp,%ebp
(gdb)?x?$r8
???0x7ffff7fe14c0:??????rclb???$0xf7,(%rsi,%rdi,8)
(gdb)?
x/i 可以顯示匯編指令。一般用x命令時,格式為x/NFU ADDR。此處ADDR為希望顯示的地址,N為重復(fù)次數(shù)。F為前面講過的格式,u代表的單位如下。
單位 | 說明 |
---|---|
b | 字節(jié) |
h | 半字(2字節(jié)) |
w | 字(4字節(jié)) |
g | 雙字(8字節(jié)) |
下面顯示從rsp開始的10條指令。
(gdb)?x/10i?$rsp
???0x7fffffffe2f0:??????(bad)??
???0x7fffffffe2f1:??????rex.W?push?%rbp
???0x7fffffffe2f3:??????push???%rbp
???0x7fffffffe2f4:??????push???%rbp
???0x7fffffffe2f5:??????push???%rbp
???0x7fffffffe2f6:??????add????%al,(%rax)
???0x7fffffffe2f8:??????lock?rex.RB?push?%r13
???0x7fffffffe2fb:??????push???%rbp
???0x7fffffffe2fc:??????or?????(%rax),%al
???0x7fffffffe2fe:??????add????%al,(%rax)
顯示反匯編
格式
disassemble
disassemble?程序計數(shù)器
disassemble?開始地址?結(jié)束地址
格式1為反匯編當(dāng)前整個函數(shù),2為反匯編程序計數(shù)器所在函數(shù)的整個函數(shù)。3為反匯編從開始地址到結(jié)束地址的部分。
(gdb)?disassemble?
Dump?of?assembler?code?for?function?sum:
???0x0000555555554722?<+0>:?????push???%rbp
???0x0000555555554723?<+1>:?????mov????%rsp,%rbp
???0x0000555555554726?<+4>:?????sub????$0x20,%rsp
???0x000055555555472a?<+8>:?????mov????%edi,-0x14(%rbp)
???0x000055555555472d?<+11>:????mov????%esi,-0x18(%rbp)
???0x0000555555554730?<+14>:????lea????0x1bd(%rip),%rdi????????#?0x5555555548f4
???0x0000555555554737?<+21>:????callq??0x5555555545b0?<puts@plt>
=>?0x000055555555473c?<+26>:????mov????-0x14(%rbp),%edx
???0x000055555555473f?<+29>:????mov????-0x18(%rbp),%eax
???0x0000555555554742?<+32>:????add????%edx,%eax
???0x0000555555554744?<+34>:????mov????%eax,-0x4(%rbp)
???0x0000555555554747?<+37>:????mov????-0x4(%rbp),%eax
???0x000055555555474a?<+40>:????leaveq?
???0x000055555555474b?<+41>:????retq???
End?of?assembler?dump.
單步執(zhí)行
執(zhí)行源代碼中的一行:next
進入函數(shù)內(nèi)部執(zhí)行:step
逐條執(zhí)行匯編指令:nexti,stepi
繼續(xù)運行
格式
continue
continue?次數(shù)
指定次數(shù)可以忽略斷點,例如,continue 5 則5次遇到斷點不會停止,第6次遇到斷點才會停止。
監(jiān)視點
格式
watch?<表達式>
<表達式>發(fā)生變化時暫停運行,<表達式>意思是常量或變量
awatch?<表達式>
<表達式>被訪問,改變時暫停運行
rwatch?<表達式>
<表達式>被訪問時暫停運行
舉例
(gdb)?watch?c
Hardware?watchpoint?2:?c
(gdb)?c
Continuing.
Hardware?watchpoint?2:?c
Old?value?=?21845
New?value?=?5
sum?(a=2,?b=3)?at?gdb_example.c:10
10??????????return?c;
(gdb)?
格式
刪除斷點和監(jiān)視點
delete?<編號>
<編號>指的是斷點或監(jiān)視點
舉例
(gdb)?info?b
Num?????Type???????????Disp?Enb?Address????????????What
1???????breakpoint?????keep?y???0x000055555555473c?in?sum?at?gdb_example.c:9
????????breakpoint?already?hit?1?time
2???????hw?watchpoint??keep?y??????????????????????c
????????breakpoint?already?hit?1?time
(gdb)?delete??2
(gdb)?info?b
Num?????Type???????????Disp?Enb?Address????????????What
1???????breakpoint?????keep?y???0x000055555555473c?in?sum?at?gdb_example.c:9
????????breakpoint?already?hit?1?time
(gdb)?
改變變量的值
格式
set?variable?<變量>=<表達式>
舉例
(gdb)?p?c
$1?=?5
(gdb)?set?variable?c=0
(gdb)?p?c
$2?=?0
(gdb)?
生成內(nèi)核轉(zhuǎn)儲文件
(gdb)?generate-core-file?
warning:?Memory?read?failed?for?corefile?section,?4096?bytes?at?0xffffffffff600000.
Saved?corefile?core.2380
有了內(nèi)核轉(zhuǎn)儲文件,即使退出了GDB也能查看生成轉(zhuǎn)儲文件時的運行歷史。
gcore?'pidof?gdb_example'
該命令無需停止正在運行的程序,可以直接從命令行直接生成轉(zhuǎn)儲文件。當(dāng)需要在其他機器上單獨分析問題原因時,或者是分析客戶現(xiàn)場問題時十分有用。
條件斷點
break?斷點?if?條件
如果條件為真,則暫停運行
condition?斷點編號
condition?斷點編號?條件
第一條指令刪除指定斷點編號的觸發(fā)條件,第二條指令給斷點添加觸發(fā)條件
反復(fù)執(zhí)行
ignore?斷點編號?次數(shù)
在編號指定的斷點,監(jiān)視點忽略指定的次數(shù)
continue與ignore一樣,也可以指定次數(shù),達到指定次數(shù)前,執(zhí)行到斷點時不暫停。
continue次數(shù)
step?次數(shù)
stepi?次數(shù)
next?次數(shù)
nexti?次數(shù)
finish
until
until?地址
finish 執(zhí)行完當(dāng)前函數(shù)后暫停,until命令執(zhí)行完當(dāng)前函數(shù)等代碼塊后暫停,常用于跳出循環(huán)。、
刪除斷點或禁用斷點
clear?
clear?函數(shù)名
clear?行號
clear?文件名:行號
clear?文件名:函數(shù)名
delete?[breakpoints]?斷點編號
clear 用于刪除已定義的斷點
disable?[breakpoints]?
disable?[breakpoints]?斷點編號
disable?display?顯示編號
disable?mem?內(nèi)存區(qū)域
disable 臨時禁用斷點。第3種格式禁用display命令定義的自動顯示,第4種格式禁用mem命令定義的內(nèi)存區(qū)域。
enable
enable?[breakpoints]?斷點編號
enable?[breakpoints]?once?斷點編號
enable?[breakpoints]?delete?斷點編號
enable?disable?display?顯示編號
enable??mem?內(nèi)存區(qū)域
once 使指定的斷點只啟用一次。delete表示在運行暫停后刪除斷點。
斷點命令
格式
commands?斷點編號
?命令
?...
?end
程序在指定的斷點處暫停,就會自動執(zhí)行命令。
舉例
(gdb)?b?17
Breakpoint?3?at?0x5555555547b1:?file?gdb_example.c,?line?17.
(gdb)?command?3
Type?commands?for?breakpoint(s)?3,?one?per?line.
End?with?a?line?saying?just?"end".
>p?c
>end
(gdb)?r
Starting?program:?/home/zhongyi/code/example/gdb_example?-e?'p?1'
In?main():
???x?is?10?and?is?stored?at?0x7fffffffe2ec.
???ptr?points?to?0x7fffffffe2ec?which?holds?10.
In?print():
???xx?is?10?and?is?stored?at?0x7fffffffe2bc.
???ptr?points?to?0x7fffffffe2ec?which?holds?10.
In?sum():
Breakpoint?3,?print?(xx=10,?xxptr=0x7fffffffe2ec)?at?gdb_example.c:17
17????????int?d?=?minus(3,2);
$1?=?5
上例表示在17行暫停后打印c的值。
與前面的條件斷點組合使用,可以在斷點暫停時執(zhí)行復(fù)雜的動作。
舉例
break?17?if?c==5
?commands
?silent
?printf?“x?is?%dn”,x
?cont
?end
常用命令及其縮略形式
命令 | 簡寫形式 | 說明 |
---|---|---|
backtrace | bt/where | 顯示backtrace |
break | 設(shè)備斷點 | |
continue | c/cont | 繼續(xù)運行 |
delete | d | 刪除斷點 |
finish | 運行到函數(shù)結(jié)束 | |
info breakpoints | 顯示斷點信息 | |
next | n | 執(zhí)行下一行 |
p | 顯示表達式 | |
run | r | 運行程序 |
step | s | 一次執(zhí)行一行,包括函數(shù)內(nèi)部 |
x | 顯示內(nèi)存內(nèi)容 | |
until | u | 執(zhí)行到指定行 |
directory | dir | 插入目錄 |
disable | dis | 禁用斷點 |
down | do | 在當(dāng)前棧幀中選擇要顯示的棧幀 |
edit | e | 編輯文件或函數(shù) |
frame | f | 選擇要顯示的棧幀 |
forward-search | fo | 向前搜索 |
generate-core-file | gcore | 生成內(nèi)核轉(zhuǎn)儲 |
help | h | 顯示幫助文檔 |
info | i | 顯示信息 |
list | l | 顯示函數(shù)行 |
nexti | ni | 執(zhí)行下一行(以匯編代碼為單位) |
print-object | po | 顯示目標(biāo)信息 |
sharedlibrary | share | 加載共享庫的符號 |
stepi | si | 執(zhí)行下一行 |
值的歷史
通過print命令顯示過的值會記錄在內(nèi)部的值歷史中,這些值可以在其他表達式中使用。
舉例
(gdb)?b?16
Breakpoint?1?at?0x79f:?file?gdb_example.c,?line?16.
(gdb)?b?17
Breakpoint?2?at?0x7b1:?file?gdb_example.c,?line?17.
(gdb)?b?29
Breakpoint?3?at?0x841:?file?gdb_example.c,?line?29.
(gdb)?r
Starting?program:?/home/zhongyi/code/example/gdb_example?
In?main():
???x?is?10?and?is?stored?at?0x7fffffffe2fc.
???ptr?points?to?0x7fffffffe2fc?which?holds?10.
In?print():
???xx?is?10?and?is?stored?at?0x7fffffffe2cc.
???ptr?points?to?0x7fffffffe2fc?which?holds?10.
Breakpoint?1,?print?(xx=10,?xxptr=0x7fffffffe2fc)?at?gdb_example.c:16
16????????int?c?=?sum(2,3);
(gdb)?p?c
$1?=?1431651824
(gdb)?c
Continuing.
In?sum():
Breakpoint?2,?print?(xx=10,?xxptr=0x7fffffffe2fc)?at?gdb_example.c:17
17????????int?d?=?minus(3,2);
(gdb)?p?c
$2?=?5
(gdb)?c
Continuing.
In?minus():
Breakpoint?3,?main?()?at?gdb_example.c:29
29????????return?0;
最后的值可以使用$ 訪問。
通過show values 可以顯示歷史中的最后10個值
舉例
(gdb)?show?values?
$1?=?1431651824
$2?=?5
$3?=?10
$4?=?10
(gdb)?
值的歷史的訪問變量和說明
變量 | 說明 |
---|---|
$ | 值歷史中的最后一個值 |
$n | 值歷史的第n個值 |
$$ | 值歷史的倒數(shù)第二個值 |
$$n | 值歷史的倒數(shù)第n個值 |
$_ | x命令顯示過的最后的地址 |
$__ | x命令顯示過的最后的地址的值 |
$_exitcode | 調(diào)試中的程序的返回代碼 |
$bpnum | 最后設(shè)置的斷點的編號 |
可以隨意定義變量。變量以$開頭,有英文和數(shù)字組成。
舉例
(gdb)?set?$i=0
(gdb)?p?$i
$5?=?0
(gdb)?
命令歷史
可以把命令保存在文件中,保存命令歷史后,就可以在其他調(diào)試會話中使用。默認(rèn)命令歷史文件位于./.gdb_history
set?history?expansion
show?history?expansion
可以使用csh風(fēng)格的!字符
set?history?filename?文件名
show?history?filename
可將命令歷史保存到文件中,可以通過環(huán)境變量GDBHISTFILE改變默認(rèn)文件。
set?history?save
show?history?save
啟用命令歷史保存到文件和恢復(fù)的功能。
set?history?size?數(shù)字
show?history?size
設(shè)置保存到命令歷史中的命令數(shù)量,默認(rèn)為256。
初始化文件(.gdbinit)
Linux下gdb初始化文件為.gdbinit。如果存在.gdbinit文件,GDB在啟動之前將其作為命令文件運行。
順序如下:
- $HOME/.gdbinit運行命令行選項./.gdbinit加載通過-x選項給出的命令文件
命令定義
用define可以自定義命令,用document可以給自定義的命令加說明,利用help 命令名可以查看定義的命令。
define格式:
define?命令名
?命令
?…………
?end
document格式:
document?命令名
?說明
?end
help格式:
help?命令名
以下示例定義了名為li的命令。
舉例
(gdb)?define?li
Type?commands?for?definition?of?"li".
End?with?a?line?saying?just?"end".
>x/10i?$rbp
>end
(gdb)?document?li
Type?documentation?for?"li".
End?with?a?line?saying?just?"end".
>list?machine?instruction
>end
(gdb)?li
???0x7fffffffe310:??????(bad)??
???0x7fffffffe311:??????rex.W?push?%rbp
???0x7fffffffe313:??????push???%rbp
???0x7fffffffe314:??????push???%rbp
???0x7fffffffe315:??????push???%rbp
???0x7fffffffe316:??????add????%al,(%rax)
???0x7fffffffe318:??????xchg???%edi,(%rax,%riz,4)
???0x7fffffffe31b:??????idiv???%edi
???0x7fffffffe31d:??????jg?????0x7fffffffe31f
???0x7fffffffe31f:??????add????%al,(%rcx)
(gdb)?help?li
list?machine?instruction
還可以把各種設(shè)置寫在文件中,運行調(diào)試器時讀取這些文件。
source?文件名
總結(jié)
本文只是對gdb命令腳本做了一個粗淺的介紹,旨在起到拋磚引玉的效果。如果大家想更深入地了解這部分知識,可以參考gdb手冊的相關(guān)章節(jié):Extending GDB (https://sourceware.org/gdb/onlinedocs/gdb/Extending-GDB.html)。
最后向大家推薦一個github上的.gdbinit文件:https://github.com/gdbinit/Gdbinit,把這個弄懂,相信gdb腳本文件就不在話下了。
文章推薦:https://blog.csdn.net/lyshark_lyshark/article/details/125846778