日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

gdb 的使用方法

發布時間:2024/4/15 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 gdb 的使用方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

linux下編程有一段時間了,但是對gdb的使用還是不太熟練,在網上看到一篇不錯的文章復制下來;

GDBGNU開源組織發布的一個強大的UNIX下的程序調試工具,GDB主要可幫助工程師完成下面4個方面的功能:

·?啟動程序,可以按照工程師自定義的要求隨心所欲的運行程序。

·?讓被調試的程序在工程師指定的斷點處停住,斷點可以是條件表達式。

·?當程序被停住時,可以檢查此時程序中所發生的事,并追索上文。

·?動態地改變程序的執行環境。

不管是調試Linux內核空間的驅動還是調試用戶空間的應用程序,掌握gdb的用法都是必須。而且,調試內核和調試應用程序時使用的gdb命令是完全相同的,下面以代碼清單22.2的應用程序為例演示gdb調試器的用法。?

[cpp]view?plaincopy

?

1?1??int?add(int?a,?int?b)??

2?2??{??

3?3????return?a?+?b;??

4?4??}??

5?5????

6?6??main()??

7?7??{??

8?8????int?sum[10]?=???

9?9????{??

10?10?????0,?0,?0,?0,?0,?0,?0,?0,?0,?0???????

11?11???}??;??

12?12???int?i;??

13?13?????

14?14???int?array1[10]?=??

15?15???{??

16?16?????48,?56,?77,?33,?33,?11,?226,?544,?78,?90??

17?17???};??

18?18???int?array2[10]?=??

19?19???{??

20?20?????85,?99,?66,?0x199,?393,?11,?1,?2,?3,?4??

21?21???};??

22?22???

23?23???for?(i?=?0;?i?<?10;?i++)??

24?24???{??

25?25?????sum[i]?=?add(array1[i],?array2[i]);??

26?26???}??

27?27?}??

?

使用命令gcc?–g?gdb_example.c?–o?gdb_example編譯上述程序,得到包含調試信息的二進制文件example,執行gdb?gdb_example命令進入調試狀態:

[cpp]view?plaincopy

?

28?[root@localhost?driver_study]#?gdb?gdb_example??

29?GNU?gdb?Red?Hat?Linux?(5.3post-0.20021129.18rh)??

30?Copyright?2003?Free?Software?Foundation,?Inc.??

31?GDB?is?free?software,?covered?by?the?GNU?General?Public?License,?and?you?are??

32?welcome?to?change?it?and/or?distribute?copies?of?it?under?certain?conditions.??

33?Type?"show?copying"?to?see?the?conditions.??

34?There?is?absolutely?no?warranty?for?GDB.??Type?"show?warranty"?for?details.??

35?This?GDB?was?configured?as?"i386-redhat-linux-gnu"...??

36?(gdb)??

1list命令

gdb中運行list命令(縮寫l)可以列出代碼,list的具體形式包括:

·?list?<linenum>,顯示程序第linenum行周圍的源程序,如:

[cpp]view?plaincopy

?

37?(gdb)?list?15??

38?10??????????

39?11????????int?array1[10]?=??

40?12????????{??

41?13??????????48,?56,?77,?33,?33,?11,?226,?544,?78,?90??

42?14????????};??

43?15????????int?array2[10]?=??

44?16????????{??

45?17??????????85,?99,?66,?0x199,?393,?11,?1,?2,?3,?4??

46?18????????};??

47?19??

·?list?<function>,顯示函數名為function的函數的源程序,如:

[cpp]view?plaincopy

?

48?(gdb)?list?main??

49?2???????{??

50?3?????????return?a?+?b;??

51?4???????}??

52?5??

53?6???????main()??

54?7???????{??

55?8?????????int?sum[10];??

56?9?????????int?i;??

57?10??????????

58?11????????int?array1[10]?=??

·?list,顯示當前行后面的源程序。

·?list?-?,顯示當前行前面的源程序。

下面演示了使用gdb中的run(縮寫r)、break(縮寫b)、next(縮寫n)命令控制程序的運行,并使用print(縮寫p)命令打印程序中的變量sum的過程:

(gdb)?break?add

Breakpoint?1?at?0x80482f7:?file?gdb_example.c,?line?3.(gdb)?run??

Starting?program:?/driver_study/gdb_example?

?

Breakpoint?1,?add?(a=48,?b=85)?at?gdb_example.c:3warning:?Source?file?is?more?recent?than?executable.

3?????????return?a?+?b;(gdb)?next4???????}(gdb)?nextmain?()?at?gdb_example.c:2323????????for?(i?=?0;?i?<?10;?i++)(gdb)?next25??????????sum[i]?=?add(array1[i],?array2[i]);(gdb)?print?sum

$1?=?{133,?0,?0,?0,?0,?0,?0,?0,?0,?0}

2run命令

gdb中,運行程序使用run命令。在程序運行前,我們可以設置如下4方面的工作環境:

·?程序運行參數

set?args可指定運行時參數,如:set?args?10?20?30?40?50show?args?命令可以查看設置好的運行參數。?

·?運行環境

path?<dir>?可設定程序的運行路徑;how?paths可查看程序的運行路徑;set?environment?varname?[=value]用于設置環境變量,如set?env?USER=baohua

show?environment?[varname]則用于查看環境變量。

·?工作目錄

cd?<dir>相當于shellcd命令;pwd?顯示當前所在的目錄。?

·?程序的輸入輸出

info?terminal?用于顯示程序用到的終端的模式;gdb中也可以使用重定向控制程序輸出,如run?>?outfile

tty命令可以指定輸入輸出的終端設備,如:tty?/dev/ttyS1

3break命令

gdb中用break命令來設置斷點,設置斷點的方法包括:

·?break?<function>

在進入指定函數時停住,C++中可以使用class::functionfunction(type,?type)格式來指定函數名。?

·?break?<linenum>

在指定行號停住。?

·?break?+offset?/?break?-offset

在當前行號的前面或后面的offset行停住,offiset為自然數。?

·?break?filename:linenum

在源文件filenamelinenum行處停住。?

·?break?filename:function

在源文件filenamefunction函數的入口處停住。?

·?break?*address

在程序運行的內存地址處停住。?

·?break

break命令沒有參數時,表示在下一條指令處停住。?

·?break?...?if?<condition>

“...”可以是上述的break?<linenum>break?+offset?/?break?–offset中的參數,condition表示條件,在條件成立時停住。比如在循環體中,可以設置break?if?i=100,表示當i100時停住程序。

查看斷點時,可使用info命令,如info?breakpoints?[n]info?break?[n]n表示斷點號)。

4、單步命令

在調試過程中,next命令用于單步執行,類似VC++中的step?overnext的單步不會進入函數的內部,與next對應的step(縮寫s)命令則在單步執行一個函數時,會進入其內部,類似VC++中的step?into。下面演示了step命令的執行情況,在23行的add()函數調用處執行step會進入其內部的“return?a+b;”語句:

[cpp]view?plaincopy

?

59?(gdb)?break?25??

60?Breakpoint?1?at?0x8048362:?file?gdb_example.c,?line?25.??

61?(gdb)?run??

62?Starting?program:?/driver_study/gdb_example???

63???

64?Breakpoint?1,?main?()?at?gdb_example.c:25??

65?25??????????sum[i]?=?add(array1[i],?array2[i]);??

66?(gdb)?step??

67?add?(a=48,?b=85)?at?gdb_example.c:3??

68?3?????????return?a?+?b;??

單步執行的更復雜用法包括:?

·?step?<count>

單步跟蹤,如果有函數調用,則進入該函數(進入函數的前提是,此函數被編譯有debug信息)。step后面不加count表示一條條地執行,加表示執行后面的count條指令,然后再停住。

·?next?<count>

單步跟蹤,如果有函數調用,它不會進入該函數。同樣地,next后面不加count表示一條條地執行,加表示執行后面的count條指令,然后再停住。?

·?set?step-mode

set?step-mode?on用于打開step-mode模式,這樣,在進行單步跟蹤時,程序不會因為沒有debug信息而不停住,這個參數的設置可便于查看機器碼。set?step-mod?off用于關閉step-mode模式。?

·?finish

運行程序,直到當前函數完成返回,并打印函數返回時的堆棧地址和返回值及參數值等信息。?

·?until?(縮寫u

一直在循環體內執行單步,退不出來是一件令人煩惱的事情,until命令可以運行程序直到退出循環體。?

·?stepi(縮寫si)和nexti(縮寫ni

stepinexti用于單步跟蹤一條機器指令,一條程序代碼有可能由數條機器指令完成,stepinexti可以單步執行機器指令。?另外,運行“display/i?$pc”命令后,單步跟蹤會在打出程序代碼的同時打出機器指令,即匯編代碼。?

5continue命令

當程序被停住后,可以使用continue命令(縮寫cfg命令同continue命令)恢復程序的運行直到程序結束,或到達下一個斷點,命令格式為:?

[cpp]view?plaincopy

?

69?continue?[ignore-count]??

70?c?[ignore-count]??

71?fg?[ignore-count]??

ignore-count表示忽略其后多少次斷點。?假設我們設置了函數斷點add(),并watch?i,則在continue過程中,每次遇到add()函數或i發生變化,程序就會停住,如:
?

[cpp]view?plaincopy

?

72?(gdb)?continue??

73?Continuing.??

74?Hardware?watchpoint?3:?i??

75???

76?Old?value?=?2??

77?New?value?=?3??

78?0x0804838d?in?main?()?at?gdb_example.c:23??

79?23????????for?(i?=?0;?i?<?10;?i++)??

80?(gdb)?continue??

81?Continuing.??

82???

83?Breakpoint?1,?main?()?at?gdb_example.c:25??

84?25??????????sum[i]?=?add(array1[i],?array2[i]);??

85?(gdb)?continue??

86?Continuing.??

87?Hardware?watchpoint?3:?i??

88???

89?Old?value?=?3??

90?New?value?=?4??

91?0x0804838d?in?main?()?at?gdb_example.c:23??

92?23????????for?(i?=?0;?i?<?10;?i++)??

6print命令

在調試程序時,當程序被停住時,可以使用print命令(縮寫為p),或是同義命令inspect來查看當前程序的運行數據。print命令的格式是:?

[cpp]view?plaincopy

?

93?print?<expr>??

94?print?/<f>?<expr>??


<expr>是表達式,是被調試的程序中的表達式,<f>是輸出的格式,比如,如果要把表達式按16進制的格式輸出,那么就是/x。在表達式中,有幾種GDB所支持的操作符,它們可以用在任何一種語言中,“@”是一個和數組有關的操作符,“::”指定一個在文件或是函數中的變量,“{<type>}?<addr>”表示一個指向內存地址<addr>的類型為type的一個對象。?

下面演示了查看sum[]數組的值的過程:

[cpp]view?plaincopy

?

95?(gdb)?print?sum??

96?$2?=?{133,?155,?0,?0,?0,?0,?0,?0,?0,?0}??

97?(gdb)?next??

98???

99?Breakpoint?1,?main?()?at?gdb_example.c:25??

100?25??????????sum[i]?=?add(array1[i],?array2[i]);??

101?(gdb)?next??

102?23????????for?(i?=?0;?i?<?10;?i++)??

103?(gdb)?print?sum??

104?$3?=?{133,?155,?143,?0,?0,?0,?0,?0,?0,?0}??

當需要查看一段連續內存空間的值的時間,可以使用GDB“@”操作符,“@”的左邊是第一個內存地址,“@”的右邊則是想查看內存的長度。例如如下動態申請的內存:?

int?*array?=?(int?*)?malloc?(len?*?sizeof?(int));

GDB調試過程中這樣顯示出這個動態數組的值:

p?*array@len

print的輸出格式包括:

·?x?按十六進制格式顯示變量。

·?d?按十進制格式顯示變量。

·?u?按十六進制格式顯示無符號整型。

·?o?按八進制格式顯示變量。

·?t?按二進制格式顯示變量。

·?a?按十六進制格式顯示變量。

·?c?按字符格式顯示變量。

·?f?按浮點數格式顯示變量。

我們可用display命令設置一些自動顯示的變量,當程序停住時,或是單步跟蹤時,這些變量會自動顯示。?如果要修改變量,如x的值,可使用如下命令:?

print?x=4

當用GDBprint查看程序運行時的數據時,每一個print都會被GDB記錄下來。GDB會以$1$2$3?…這樣的方式為每一個print命令編號。我們可以使用這個編號訪問以前的表達式,如$1

7watch命令

watch一般來觀察某個表達式(變量也是一種表達式)的值是否有變化了,如果有變化,馬上停住程序。我們有下面的幾種方法來設置觀察點:?watch?<expr>:為表達式(變量)expr設置一個觀察點。一量表達式值有變化時,馬上停住程序。rwatch?<expr>:當表達式(變量)expr被讀時,停住程序。awatch?<expr>:當表達式(變量)的值被讀或被寫時,停住程序。info?watchpoints:列出當前所設置了的所有觀察點。?下面演示了觀察i并在連續運行next時一旦發現i變化,i值就會顯示出來的過程:

[cpp]view?plaincopy

?

105?(gdb)?watch?i??

106?Hardware?watchpoint?3:?i??

107?(gdb)?next??

108?23????????for?(i?=?0;?i?<?10;?i++)??

109?(gdb)?next??

110?Hardware?watchpoint?3:?i??

111???

112?Old?value?=?0??

113?New?value?=?1??

114?0x0804838d?in?main?()?at?gdb_example.c:23??

115?23????????for?(i?=?0;?i?<?10;?i++)??

116?(gdb)?next??

117???

118?Breakpoint?1,?main?()?at?gdb_example.c:25??

119?25??????????sum[i]?=?add(array1[i],?array2[i]);??

120?(gdb)?next??

121?23????????for?(i?=?0;?i?<?10;?i++)??

122?(gdb)?next??

123?Hardware?watchpoint?3:?i??

124???

125?Old?value?=?1??

126?New?value?=?2??

127?0x0804838d?in?main?()?at?gdb_example.c:23??

128?23????????for?(i?=?0;?i?<?10;?i++)??

8examine命令

我們可以使用examine命令(縮寫為x)來查看內存地址中的值。examine命令的語法如下所示:

x/<n/f/u>?<addr>?

<addr>表示一個內存地址。“x/”后的nfu都是可選的參數,n?是一個正整數,表示顯示內存的長度,也就是說從當前地址向后顯示幾個地址的內容;f?表示顯示的格式,如果地址所指的是字符串,那么格式可以是s,如果地址是指令地址,那么格式可以是iu?表示從當前地址往后請求的字節數,如果不指定的話,GDB默認是4字節。u參數可以被一些字符代替:b表示單字節,h表示雙字節,w表示四字節,g表示八?字節。當我們指定了字節長度后,GDB會從指定的內存地址開始,讀寫指定字節,并把其當作一個值取出來。nfu3個參數可以一起使用,例如命令“x/3uh?0x54320”表示從內存地址0x54320開始以雙字節為1個單位(h)、16進制方式(u)顯示3個單位(3)的內存。?==

譬如下面的例子:

[cpp]view?plaincopy

?

129?main()??

130?{??

131?????????char?*c?=?"hello?world";??

132?????????printf("%s\n",?c);??

133?}??


我們在

[cpp]view?plaincopy

?

134?char?*c?=?"hello?world";??

下一行設置斷點后:

[cpp]view?plaincopy

?

135?(gdb)?l??

136?1????main()??

137?2????{??

138?3????????char?*c?=?"hello?world";??

139?4????????printf("%s\n",?c);??

140?5????}??

141?(gdb)?b?4??

142?Breakpoint?1?at?0x100000f17:?file?main.c,?line?4.??

143?(gdb)?r??

144?Starting?program:?/Users/songbarry/main??

145?Reading?symbols?for?shared?libraries?+.?done??

146???

147?Breakpoint?1,?main?()?at?main.c:4??

148?4????????printf("%s\n",?c);??

可以通過多種方式看C指向的字符串:?

方法1

[cpp]view?plaincopy

?

149?(gdb)?p?c??

150?$1?=?0x100000f2e?"hello?world"??

方法2

[cpp]view?plaincopy

?

151?(gdb)?x/s?0x100000f2e??

152?0x100000f2e:?????"hello?world"??

方法3

[cpp]view?plaincopy

?

153?(gdb)?p?(char?*)0x100000f2e??

154?$3?=?0x100000f2e?"hello?world"??

將第一個字符改為大寫:

[cpp]view?plaincopy

?

155?(gdb)?p?*(char?*)0x100000f2e='H'??

156?$4?=?72?'H'??

再看看C

[cpp]view?plaincopy

?

157?(gdb)?p?c??

158?$5?=?0x100000f2e?"Hello?world"??

9set命令

修改寄存器:

[cpp]view?plaincopy

?

159?(gdb)?set?$v0?=?0x004000000??

160?(gdb)?set?$epc?=?0xbfc00000???

修改內存:

[cpp]view?plaincopy

?

161?(gdb)?set?{unsigned?int}0x8048a51=0x0??

譬如對于第8節的例子:?

[cpp]view?plaincopy

?

162?(gdb)?set?{unsigned?int}0x100000f2e=0x0?????????

163?(gdb)?x/10cb?0x100000f2e??

164?0x100000f2e:????0?'\0'??0?'\0'??0?'\0'??0?'\0'??111?'o'?32?'?'??119?'w'?111?'o'??

165?0x100000f36:????114?'r'?108?'l'??

166?(gdb)?p?c??

167?$10?=?0x100000f2e?""??

10jump命令

一般來說,被調試程序會按照程序代碼的運行順序依次執行,但是GDB也提供了亂序執行的功能,也就是說,GDB可以修改程序的執行順序,從而讓程序隨意跳躍。這個功能可以由GDBjump命令:jump?<linespec>?來指定下一條語句的運行點。<linespec>可以是文件的行號,可以是file:line格式,也可以是+num這種偏移量格式,表示下一條運行語句從哪里開始。jump?<address>?這里的<address>是代碼行的內存地址。?注意,jump命令不會改變當前的程序棧中的內容,所以,如果使用jump從一個函數跳轉到另一個函數,當跳轉到的函數運行完返回,進行出棧操作時必然會發生錯誤,這可能導致意想不到的結果,所以最好只用jump在同一個函數中進行跳轉。

11signal命令

使用singal命令,可以產生一個信號量給被調試的程序,如中斷信號“Ctrl+C”。這非常方便于程序的調試,可以在程序運行的任意位置設置斷點,并在該斷點用GDB產生一個信號量,這種精確地在某處產生信號的方法非常有利于程序的調試。?signal命令的語法是:signal?<signal>UNIX的系統信號量通常從115,所以<signal>取值也在這個范圍。

12return命令

如果在函數中設置了調試斷點,在斷點后還有語句沒有執行完,這時候我們可以使用return命令強制函數忽略還沒有執行的語句并返回。

[cpp]view?plaincopy

?

168?return??

169?return?<expression>??

上述return命令用于取消當前函數的執行,并立即返回,如果指定了<expression>,那么該表達式的值會被作為函數的返回值。?

13call命令

call命令用于強制調用某函數:?call?<expr>?表達式中可以一是函數,以此達到強制調用函數的目的,它會顯示函數的返回值(如果函數返回值不是void)。?其實,前面介紹的print命令也可以完成強制調用函數的功能。

14info命令

info命令可以在調試時用來查看寄存器、斷點、觀察點和信號等信息。要查看寄存器的值,可以使用如下命令:?info?registers?(查看除了浮點寄存器以外的寄存器)info?all-registers?(查看所有寄存器,包括浮點寄存器)info?registers?<regname?...>?(查看所指定的寄存器)?要查看斷點信息,可以使用如下命令:info?break?列出當前所設置的所有觀察點,使用如下命令:info?watchpoints?查看有哪些信號正在被GDB檢測,使用如下命令:info?signals?info?handle?也可以使用info?line命令來查看源代碼在內存中的地址。info?threads可以看多線程。info?line后面可以跟行號、函數名、文件名:行號、文件名:函數名等多種形式,例如下面的命令會打印出所指定的源碼在運行時的內存地址:

[cpp]view?plaincopy

?

170?info?line?tst.c:func??

15set?scheduler-locking?off|on|step

off?不鎖定任何線程,也就是所有線程都執行,這是默認值。
on?只有當前被調試程序會執行。
step?在單步的時候,除了next過一個函數的情況以外,只有當前線程會執行。

與多線程調試相關的命令還包括:

thread?ID
切換當前調試的線程為指定ID的線程。
?
break?thread_test.c:123?thread?all
在所有線程中相應的行上設置斷點
?
thread?apply?ID1?ID2?command
讓一個或者多個線程執行GDB命令command
?
thread?apply?all?command
讓所有被調試線程執行GDB命令command

16disassemble

disassemble命令用于反匯編,它可被用來查看當前執行時的源代碼的機器碼,其實際上只是把目前內存中的指令dump出來。下面的示例用于查看函數func的匯編代碼:

[cpp]view?plaincopy

?

171?(gdb)?disassemble?func??

172?Dump?of?assembler?code?for?function?func:??

173?0x8048450?<func>:???????push???%ebp??

174?0x8048451?<func+1>:?????mov????%esp,%ebp??

175?0x8048453?<func+3>:?????sub????$0x18,%esp??

176?0x8048456?<func+6>:?????movl???$0x0,0xfffffffc(%ebp)??

177?...??

End?of?assembler?dump.?

轉載于:https://www.cnblogs.com/wzheng/archive/2013/04/08/3008347.html

總結

以上是生活随笔為你收集整理的gdb 的使用方法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。