GDB调试器用法
wiki頁:http://code.google.com/p/ldd6410/wiki/GDBDebug
gdb調(diào)試器用法
GDB是GNU開源組織發(fā)布的一個強大的UNIX下的程序調(diào)試工具,GDB主要可幫助工程師完成下面4個方面的功能:- 啟動程序,可以按照工程師自定義的要求隨心所欲的運行程序。
- 讓被調(diào)試的程序在工程師指定的斷點處停住,斷點可以是條件表達式。
- 當程序被停住時,可以檢查此時程序中所發(fā)生的事,并追索上文。
- 動態(tài)地改變程序的執(zhí)行環(huán)境。
2 ?{
3 ? ?return a + b;
4 ?}
5 ?
6 ?main()
7 ?{
8 ? ?int sum[10] =
9 ? ?{
10 ? ? 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ? ?
11 ? } ?;
12 ? int i;
13 ?
14 ? int array1[10] =
15 ? {
16 ? ? 48, 56, 77, 33, 33, 11, 226, 544, 78, 90
17 ? };
18 ? int array2[10] =
19 ? {
20 ? ? 85, 99, 66, 0x199, 393, 11, 1, 2, 3, 4
21 ? };
22
23 ? for (i = 0; i < 10; i++)
24 ? {
25 ? ? sum[i] = add(array1[i], array2[i]);
26 ? }
27 } 使用命令gcc –g gdb_example.c –o gdb_example編譯上述程序,得到包含調(diào)試信息的二進制文件example,執(zhí)行gdb gdb_example命令進入調(diào)試狀態(tài): [root@localhost driver_study]# gdb gdb_example
GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
Copyright 2003 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. ?Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...
(gdb)
1、list命令
在gdb中運行l(wèi)ist命令(縮寫l)可以列出代碼,list的具體形式包括:- list <linenum>?,顯示程序第linenum行周圍的源程序,如:
10 ? ? ? ?
11 ? ? ? ?int array1[10] =
12 ? ? ? ?{
13 ? ? ? ? ?48, 56, 77, 33, 33, 11, 226, 544, 78, 90
14 ? ? ? ?};
15 ? ? ? ?int array2[10] =
16 ? ? ? ?{
17 ? ? ? ? ?85, 99, 66, 0x199, 393, 11, 1, 2, 3, 4
18 ? ? ? ?};
19 list <function>?,顯示函數(shù)名為function的函數(shù)的源程序,如:(gdb) list main
2 ? ? ? {
3 ? ? ? ? return a + b;
4 ? ? ? }
5
6 ? ? ? main()
7 ? ? ? {
8 ? ? ? ? int sum[10];
9 ? ? ? ? int i;
10 ? ? ? ?
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:3
warning: Source file is more recent than executable.
3 ? ? ? ? return a + b;
(gdb) next
4 ? ? ? }
(gdb) next
main () at gdb_example.c:23
23 ? ? ? ?for (i = 0; i < 10; i++)
(gdb) next
25 ? ? ? ? ?sum[i] = add(array1[i], array2[i]);
(gdb) print sum
$1 = {133, 0, 0, 0, 0, 0, 0, 0, 0, 0}
2、run命令
在gdb中,運行程序使用run命令。在程序運行前,我們可以設置如下4方面的工作環(huán)境:- 程序運行參數(shù)
- 運行環(huán)境
- 工作目錄
- 程序的輸入輸出
3、break命令
在gdb中用break命令來設置斷點,設置斷點的方法包括:- break <function>
- break <linenum>
- break +offset / break -offset
- break filename:linenum
- break filename:function
- break *address
- break
- break ... if <condition>
4、單步命令
在 調(diào)試過程中,next命令用于單步執(zhí)行,類似VC++中的step over。next的單步不會進入函數(shù)的內(nèi)部,與next對應的step(縮寫s)命令則在單步執(zhí)行一個函數(shù)時,會進入其內(nèi)部,類似VC++中的step into。下面演示了step命令的執(zhí)行情況,在23行的add()函數(shù)調(diào)用處執(zhí)行step會進入其內(nèi)部的“return a+b;”語句: (gdb) break 25Breakpoint 1 at 0x8048362: file gdb_example.c, line 25.
(gdb) run
Starting program: /driver_study/gdb_example
Breakpoint 1, main () at gdb_example.c:25
25 ? ? ? ? ?sum[i] = add(array1[i], array2[i]);
(gdb) step
add (a=48, b=85) at gdb_example.c:3
3 ? ? ? ? return a + b;
單步執(zhí)行的更復雜用法包括:
- step <count>
- next <count>
- set step-mode
- finish
- until (縮寫u)
- stepi(縮寫si)和nexti(縮寫ni)
5、continue命令
當程序被停住后,可以使用continue命令(縮寫c,fg命令同continue命令)恢復程序的運行直到程序結束,或到達下一個斷點,命令格式為: continue [ignore-count]c [ignore-count]
fg [ignore-count] ignore-count表示忽略其后多少次斷點。 假設我們設置了函數(shù)斷點add(),并watch i,則在continue過程中,每次遇到add()函數(shù)或i發(fā)生變化,程序就會停住,如: (gdb) continue
Continuing.
Hardware watchpoint 3: i
Old value = 2
New value = 3
0x0804838d in main () at gdb_example.c:23
23 ? ? ? ?for (i = 0; i < 10; i++)
(gdb) continue
Continuing.
Breakpoint 1, main () at gdb_example.c:25
25 ? ? ? ? ?sum[i] = add(array1[i], array2[i]);
(gdb) continue
Continuing.
Hardware watchpoint 3: i
Old value = 3
New value = 4
0x0804838d in main () at gdb_example.c:23
23 ? ? ? ?for (i = 0; i < 10; i++)
6、print命令
在調(diào)試程序時,當程序被停住時,可以使用print命令(縮寫為p),或是同義命令inspect來查看當前程序的運行數(shù)據(jù)。print命令的格式是: ?print <expr>print /<f> <expr> <expr>是表達式,是被調(diào)試的程序中的表達式,<f>是輸出的格式,比如,如果要把表達式按16進制的格式輸出,那么就是/x。在表達式中,有幾種GDB所支持的操作符,它們可以用在任何一種語言中,“@”是一個和數(shù)組有關的操作符,“::”指定一個在文件或是函數(shù)中的變量,“{<type>} <addr>”表示一個指向內(nèi)存地址<addr>的類型為type的一個對象。 下面演示了查看sum[]數(shù)組的值的過程: (gdb) print sum
$2 = {133, 155, 0, 0, 0, 0, 0, 0, 0, 0}
(gdb) next
Breakpoint 1, main () at gdb_example.c:25
25 ? ? ? ? ?sum[i] = add(array1[i], array2[i]);
(gdb) next
23 ? ? ? ?for (i = 0; i < 10; i++)
(gdb) print sum
$3 = {133, 155, 143, 0, 0, 0, 0, 0, 0, 0} 當需要查看一段連續(xù)內(nèi)存空間的值的時間,可以使用GDB的“@”操作符,“@”的左邊是第一個內(nèi)存地址,“@”的右邊則是想查看內(nèi)存的長度。例如如下動態(tài)申請的內(nèi)存: int *array = (int *) malloc (len * sizeof (int)); 在GDB調(diào)試過程中這樣顯示出這個動態(tài)數(shù)組的值: p *array@len print的輸出格式包括:
- x 按十六進制格式顯示變量。
- d 按十進制格式顯示變量。
- u 按十六進制格式顯示無符號整型。
- o 按八進制格式顯示變量。
- t 按二進制格式顯示變量。
- a 按十六進制格式顯示變量。
- c 按字符格式顯示變量。
- f 按浮點數(shù)格式顯示變量。
7、watch命令
watch一般來觀察某個表達式(變量也是一種表達式)的值是否有變化了,如果有變化,馬上停住程序。我們有下面的幾種方法來設置觀察點:?watch <expr>:為表達式(變量)expr設置一個觀察點。一量表達式值有變化時,馬上停住程序。?rwatch <expr>:當表達式(變量)expr被讀時,停住程序。?awatch <expr>:當表達式(變量)的值被讀或被寫時,停住程序。?info watchpoints:列出當前所設置了的所有觀察點。 下面演示了觀察i并在連續(xù)運行next時一旦發(fā)現(xiàn)i變化,i值就會顯示出來的過程: (gdb) watch iHardware watchpoint 3: i
(gdb) next
23 ? ? ? ?for (i = 0; i < 10; i++)
(gdb) next
Hardware watchpoint 3: i
Old value = 0
New value = 1
0x0804838d in main () at gdb_example.c:23
23 ? ? ? ?for (i = 0; i < 10; i++)
(gdb) next
Breakpoint 1, main () at gdb_example.c:25
25 ? ? ? ? ?sum[i] = add(array1[i], array2[i]);
(gdb) next
23 ? ? ? ?for (i = 0; i < 10; i++)
(gdb) next
Hardware watchpoint 3: i
Old value = 1
New value = 2
0x0804838d in main () at gdb_example.c:23
23 ? ? ? ?for (i = 0; i < 10; i++)
8、examine命令
我們可以使用examine命令(縮寫為x)來查看內(nèi)存地址中的值。examine命令的語法如下所示: x/<n/f/u> <addr> <addr>表示一個內(nèi)存地址。“x/”后 的n、f、u都是可選的參數(shù),n 是一個正整數(shù),表示顯示內(nèi)存的長度,也就是說從當前地址向后顯示幾個地址的內(nèi)容;f 表示顯示的格式,如果地址所指的是字符串,那么格式可以是s,如果地址是指令地址,那么格式可以是i;u 表示從當前地址往后請求的字節(jié)數(shù),如果不指定的話,GDB默認是4字節(jié)。u參數(shù)可以被一些字符代替:b表示單字節(jié),h表示雙字節(jié),w表示四字節(jié),g表示八 字節(jié)。當我們指定了字節(jié)長度后,GDB會從指定的內(nèi)存地址開始,讀寫指定字節(jié),并把其當作一個值取出來。n、f、u這3個參數(shù)可以一起使用,例如命令“x/3uh 0x54320”表示從內(nèi)存地址0x54320開始以雙字節(jié)為1個單位(h)、16進制方式(u)顯示3個單位(3)的內(nèi)存。9、jump命令
一般來說,被調(diào)試程序會按照程序代碼的運行順序依次執(zhí)行,但是GDB也提供了亂序執(zhí)行的功能,也就是說,GDB可以修改程序的執(zhí)行順序,從而讓程序隨意跳躍。這個功能可以由GDB的jump命令:?jump <linespec>?來指定下一條語句的運行點。<linespec>可以是文件的行號,可以是file:line格式,也可以是+num這種偏移量格式,表示下一條運行語句從哪里開始。?jump <address>?這里的<address>是代碼行的內(nèi)存地址。 注意,jump命令不會改變當前的程序棧中的內(nèi)容,所以,如果使用jump從一個函數(shù)跳轉(zhuǎn)到另一個函數(shù),當跳轉(zhuǎn)到的函數(shù)運行完返回,進行出棧操作時必然會發(fā)生錯誤,這可能導致意想不到的結果,所以最好只用jump在同一個函數(shù)中進行跳轉(zhuǎn)。10、signal命令
使用singal命令,可以產(chǎn)生一個信號量給被調(diào)試的程序,如中斷信號“Ctrl+C”。這非常方便于程序的調(diào)試,可以在程序運行的任意位置設置斷點,并在該斷點用GDB產(chǎn)生一個信號量,這種精確地在某處產(chǎn)生信號的方法非常有利于程序的調(diào)試。 signal命令的語法是:signal <signal>,UNIX的系統(tǒng)信號量通常從1到15,所以<signal>取值也在這個范圍。11、return命令
如果在函數(shù)中設置了調(diào)試斷點,在斷點后還有語句沒有執(zhí)行完,這時候我們可以使用return命令強制函數(shù)忽略還沒有執(zhí)行的語句并返回。 returnreturn <expression> 上述return命令用于取消當前函數(shù)的執(zhí)行,并立即返回,如果指定了<expression>,那么該表達式的值會被作為函數(shù)的返回值。
12、call命令
call命令用于強制調(diào)用某函數(shù):?call <expr>?表達式中可以一是函數(shù),以此達到強制調(diào)用函數(shù)的目的,它會顯示函數(shù)的返回值(如果函數(shù)返回值不是void)。 其實,前面介紹的print命令也可以完成強制調(diào)用函數(shù)的功能。13、info命令
info命令可以在調(diào)試時用來查看寄存器、斷點、觀察點和信號等信息。要查看寄存器的值,可以使用如下命令:?info registers?(查看除了浮點寄存器以外的寄存器)?info all-registers?(查看所有寄存器,包括浮點寄存器)?info registers <regname ...>?(查看所指定的寄存器) 要查看斷點信息,可以使用如下命令:?info break?列出當前所設置的所有觀察點,使用如下命令:?info watchpoints?查看有哪些信號正在被GDB檢測,使用如下命令:?info signals?info handle?也可以使用info line命令來查看源代碼在內(nèi)存中的地址。info line后面可以跟行號、函數(shù)名、文件名:行號、文件名:函數(shù)名等多種形式,例如下面的命令會打印出所指定的源碼在運行時的內(nèi)存地址: info line tst.c:func14、disassemble
disassemble命令用于反匯編,它可被用來查看當前執(zhí)行時的源代碼的機器碼,其實際上只是把目前內(nèi)存中的指令dump出來。下面的示例用于查看函數(shù)func的匯編代碼: (gdb) disassemble funcDump of assembler code for function func:
0x8048450 <func>: ? ? ? push ? %ebp
0x8048451 <func+1>: ? ? mov ? ?%esp,%ebp
0x8048453 <func+3>: ? ? sub ? ?$0x18,%esp
0x8048456 <func+6>: ? ? movl ? $0x0,0xfffffffc(%ebp)
...
End of assembler dump.
本文轉(zhuǎn)自 21cnbao 51CTO博客,原文鏈接:http://blog.51cto.com/21cnbao/223565,如需轉(zhuǎn)載請自行聯(lián)系原作者
總結
- 上一篇: ASP.NET Core实现类库项目读取
- 下一篇: 根据生日获取年龄