• 正文
  • 相關(guān)推薦
申請入駐 產(chǎn)業(yè)圖譜

【調(diào)試】GDB使用總結(jié)

9小時前
162
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

啟動

在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í)行下一行
print 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

相關(guān)推薦

登錄即可解鎖
  • 海量技術(shù)文章
  • 設(shè)計資源下載
  • 產(chǎn)業(yè)鏈客戶資源
  • 寫文章/發(fā)需求
立即登錄

作者就職于某500強公司,擔(dān)任BSP工程師。具有豐富的嵌入式開發(fā)經(jīng)驗。專欄主要分享計算機基礎(chǔ),操作系統(tǒng),Linux驅(qū)動開發(fā),Arm體系與架構(gòu),C/C++,數(shù)據(jù)結(jié)構(gòu)與算法等相關(guān)文章。歡迎關(guān)注我的公眾號【嵌入式與Linux那些事】,一起學(xué)習(xí)交流。