linux--gdb调试
一.對(duì)于GDB理論的介紹:
1.定義:UNIX及UNIX-like下的調(diào)試工具。
2.功能:
1、啟動(dòng)你的程序,可以按照你的自定義的要求隨心所欲的運(yùn)行程序。
2、可讓被調(diào)試的程序在你所指定的調(diào)置的斷點(diǎn)處停住。(斷點(diǎn)可以是條件表達(dá)式)
3、當(dāng)程序被停住時(shí),可以檢查此時(shí)你的程序中所發(fā)生的事。
4、你可以改變你的程序,將一個(gè)BUG產(chǎn)生的影響修正從而測(cè)試其他BUG。
3.文件清單:
List
(gdb) list line1,line2
查看源代碼
list lineNum 在lineNum的前后源代碼顯示出來
list + 列出當(dāng)前行的后面代碼行
list - 列出當(dāng)前行的前面代碼行
list function
set listsize count
設(shè)置顯示代碼的行數(shù)
show listsize
顯示打印代碼的行數(shù)
list first,last
顯示從first到last的源代碼行
4.執(zhí)行程序:
要想運(yùn)行準(zhǔn)備調(diào)試的程序,可使用run命令,在它后面可以跟隨發(fā)給該程序的任何參數(shù),包括標(biāo)準(zhǔn)輸入和標(biāo)準(zhǔn)輸出說明符(<;和>;)和shell通配符(*、?、[、])在內(nèi)。如果你使用不帶參數(shù)的run命令,gdb就再次使用你給予前一條run命令的參數(shù),這是很有用的。利用set args 命令就可以修改發(fā)送給程序的參數(shù),而使用show args 命令就可以查看其缺省參數(shù)的列表。
(gdb) file a.out //加載被調(diào)試的可執(zhí)行程序文件。
(gdb)set args –b –x
(gdb) show args
(gdb)r //執(zhí)行程序
backtrace命令為堆棧提供向后跟蹤功能。
Backtrace 命令產(chǎn)生一張列表,包含著從最近的過程開始的所有有效過程和調(diào)用這些過程的參數(shù)。
5.顯示數(shù)據(jù):
利用print 命令可以檢查各個(gè)變量的值。
(gdb) print p (p為變量名)
print 是gdb的一個(gè)功能很強(qiáng)的命令,利用它可以顯示被調(diào)試的語言中任何有效的表達(dá)式。表達(dá)式除了包含你程序中的變量外,還可以包含以下內(nèi)容:
對(duì)程序中函數(shù)的調(diào)用
(gdb) print find_entry(1,0)
數(shù)據(jù)結(jié)構(gòu)和其他復(fù)雜對(duì)象
(gdb) print *table_start
={e=reference=’\000’,location=0x0,next=0x0}
值的歷史成分
(gdb)print (為歷史記錄變量,在以后可以直接引用的值)
人為數(shù)組
人為數(shù)組提供了一種去顯示存儲(chǔ)器塊(數(shù)組節(jié)或動(dòng)態(tài)分配的存儲(chǔ)區(qū))內(nèi)容的方法。早期的調(diào)試程序沒有很好的方法將任意的指針換成一個(gè)數(shù)組。就像對(duì)待參數(shù)一樣,讓我們查看內(nèi)存中在變量h后面的10個(gè)整數(shù),一個(gè)動(dòng)態(tài)數(shù)組的語法如下所示:
base@length
因此,要想顯示在h后面的10個(gè)元素,可以使用h@10:
(gdb)print h@10
=(-1,345,23,-234,0,0,0,98,345,10)
whatis命令可以顯示某個(gè)變量的類型
(gdb) whatis p
type = int *
6.斷點(diǎn)
break命令(可以簡寫為b)可以用來在調(diào)試的程序中設(shè)置斷點(diǎn),該命令有如下四種形式:
break line-number 使程序恰好在執(zhí)行給定行之前停止。
break function-name 使程序恰好在進(jìn)入指定的函數(shù)之前停止。
break line-or-function if condition 如果condition(條件)是真,程序到達(dá)指定行或函數(shù)時(shí)停止。
break routine-name 在指定例程的入口處設(shè)置斷點(diǎn)
如果該程序是由很多原文件構(gòu)成的,你可以在各個(gè)原文件中設(shè)置斷點(diǎn),而不是在當(dāng)前的原文件中設(shè)置斷點(diǎn),其方法如下:
(gdb) break filename:line-number
(gdb) break filename:function-name
要想設(shè)置一個(gè)條件斷點(diǎn),可以利用break if命令,如下所示:
(gdb) break line-or-function if expr
例:
(gdb) break 46 if testsize==100
從斷點(diǎn)繼續(xù)運(yùn)行:continue 命令
7.斷點(diǎn)管理
1.顯示當(dāng)前gdb的斷點(diǎn)信息:
(gdb) info break
他會(huì)以如下的形式顯示所有的斷點(diǎn)信息:
Num Type Disp Enb Address What
1 breakpoint keep y 0x000028bc in init_random at qsort2.c:155
2 breakpoint keep y 0x0000291c in init_organ at qsort2.c:168
刪除指定的某個(gè)斷點(diǎn):
(gdb) delete breakpoint 1
該命令將會(huì)刪除編號(hào)為1的斷點(diǎn),如果不帶編號(hào)參數(shù),將刪除所有的斷點(diǎn)
(gdb) delete breakpoint
禁止使用某個(gè)斷點(diǎn)
(gdb) disable breakpoint 1
該命令將禁止斷點(diǎn)1,同時(shí)斷點(diǎn)信息的 (Enb)域?qū)⒆優(yōu)?n
允許使用某個(gè)斷點(diǎn)
(gdb) enable breakpoint 1
該命令將允許斷點(diǎn)1,同時(shí)斷點(diǎn)信息的 (Enb)域?qū)⒆優(yōu)?y
清除源文件中某一代碼行上的所有斷點(diǎn)
(gdb)clear number
注:number 為源文件的某個(gè)代碼行的行號(hào)
2.設(shè)置條件斷點(diǎn)
例子: [1]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
int main(void)
{
int i = 0;
int sum = 0;
}
gdb可以設(shè)置條件斷點(diǎn),也就是只有在條件滿足時(shí),斷點(diǎn)才會(huì)被觸發(fā),命令是“break … if cond”。以上面程序?yàn)槔?#xff1a; [2]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(gdb) start
Temporary breakpoint 1 at 0x4004cc: file a.c, line 5.
Starting program: /data2/home/nanxiao/a
Temporary breakpoint 1, main () at a.c:5
5 int i = 0;
(gdb) b 10 if i==101
Breakpoint 2 at 0x4004e3: file a.c, line 10.
(gdb) r
Starting program: /data2/home/nanxiao/a
Breakpoint 2, main () at a.c:10
10 sum += i;
(gdb) p sum
$1 = 5050
可以看到設(shè)定斷點(diǎn)只在i的值為101時(shí)觸發(fā),此時(shí)打印sum的為5050。
8.變量檢查賦值:
whatis:識(shí)別數(shù)組或變量的類型
ptype:比whatis的功能更強(qiáng),他可以提供一個(gè)結(jié)構(gòu)的定義
set variable = value:將值賦予變量
print variable = value or p variable = value : 除了顯示一個(gè)變量的值外,還可以用來賦值
9.單步執(zhí)行:
next 不進(jìn)入的單步執(zhí)行
step 進(jìn)入的單步執(zhí)行如果已經(jīng)進(jìn)入了某函數(shù),而想退出該函數(shù)返回到它的調(diào)用函數(shù)中,可使用命令finish
10.函數(shù)調(diào)用:
call name 調(diào)用和執(zhí)行一個(gè)函數(shù)
(gdb) call gen_and_sork(1234,1,0)
(gdb) call printf(“abcd”)
=4
finish 結(jié)束執(zhí)行當(dāng)前函數(shù),顯示其返回值(如果有的話)
11.
有一組專用的gdb變量可以用來檢查和修改計(jì)算機(jī)的通用寄存器,gdb提供了目 前每一臺(tái)計(jì)算機(jī)中實(shí)際使用的4個(gè)寄存器的標(biāo)準(zhǔn)名字:
$pc :程序計(jì)數(shù)器
$fp :幀指針(當(dāng)前堆棧幀)
$sp :棧指針
$ps :處理器狀態(tài)
12.信號(hào):機(jī)器語言工具
gdb通常可以捕捉到發(fā)送給它的大多數(shù)信號(hào),通過捕捉信號(hào),它就可決定對(duì)于正在運(yùn)行的進(jìn)程要做些什么工作。例如,按CTRL-C將中斷信號(hào)發(fā)送給gdb,通常就會(huì)終止gdb。但是你或許不想中斷gdb,真正的目的是要中斷gdb正在運(yùn)行的程序,因此,gdb要抓住該信號(hào)并停止它正在運(yùn)行的程序,這樣就可以執(zhí)行某些調(diào)試操作。
Handle命令可控制信號(hào)的處理,他有兩個(gè)參數(shù),一個(gè)是信號(hào)名,另一個(gè)是接受到信號(hào)時(shí)該作什么。幾種可能的參數(shù)是:
nostop 接收到信號(hào)時(shí),不要將它發(fā)送給程序,也不要停止程序。
stop 接受到信號(hào)時(shí)停止程序的執(zhí)行,從而允許程序調(diào)試;顯示一條表示已接受到信號(hào)的消息(禁止使用消息除外)
print 接受到信號(hào)時(shí)顯示一條消息
noprint 接受到信號(hào)時(shí)不要顯示消息(而且隱含著不停止程序運(yùn)行)
pass 將信號(hào)發(fā)送給程序,從而允許你的程序去處理它、停止運(yùn)行或采取別的動(dòng)作。
nopass 停止程序運(yùn)行,但不要將信號(hào)發(fā)送給程序。
例如,假定你截獲SIGPIPE信號(hào),以防止正在調(diào)試的程序接受到該信號(hào),而且只要該信號(hào)一到達(dá),就要求該程序停止,并通知你。要完成這一任務(wù),可利用如下命令:
(gdb) handle SIGPIPE stop print
請(qǐng)注意,UNⅨ的信號(hào)名總是采用大寫字母!你可以用信號(hào)編號(hào)替代信號(hào)名如果你的程序要執(zhí)行任何信號(hào)處理操作,就需要能夠測(cè)試其信號(hào)處理程序,為此,就需要一種能將信號(hào)發(fā)送給程序的簡便方法,這就是signal命令的任務(wù)。該命令的參數(shù)是一個(gè)數(shù)字或者一個(gè)名字,如SIGINT。假定你的程序已將一個(gè)專用的SIGINT(鍵盤輸入,或CTRL-C;信號(hào)2)信號(hào)處理程序設(shè)置成采取某個(gè)清理動(dòng)作,要想測(cè)試該信號(hào)處理程序,你可以設(shè)置一個(gè)斷點(diǎn)并使用如下命令:
(gdb) signal 2
continuing with signal SIGINT⑵
該程序繼續(xù)執(zhí)行,但是立即傳輸該信號(hào),而且處理程序開始運(yùn)行。
13.GDB的使用
GDB是一個(gè)強(qiáng)大的命令行調(diào)試工具。大家知道命令行的強(qiáng)大就是在于,其可以形成執(zhí)行序列,形成腳本。UNⅨ下的軟件全是命令行的,這給程序開發(fā)提代供了極大的便利,命令行軟件的優(yōu)勢(shì)在于,它們可以非常容易的集成在一起,使用幾個(gè)簡單的已有工具的命令,就可以做出一個(gè)非常強(qiáng)大的功能。
于是UNⅨ下的軟件比Windows下的軟件更能有機(jī)地結(jié)合,各自發(fā)揮各自的長處,組合成更為強(qiáng)勁的功能。而Windows下的圖形軟件基本上是各自為營,互相不能調(diào)用,很不利于各種軟件的相互集成。在這里并不是要和Windows做個(gè)什么比較,所謂“寸有所長,尺有所短”,圖形化工具還有時(shí)不如命令行的地方。
二.LINUX下對(duì)于GDB的使用
1.對(duì)于最初的源文件.c文件使用使用命令:gcc –g gdb_example.c –o gdb_example編譯上述程序,得到包含調(diào)試信息的二進(jìn)制文件example,執(zhí)行g(shù)db gdb_example命令進(jìn)入調(diào)試狀態(tài):
[root@localhost driver_study]# gdb gdb_example//之后執(zhí)行這個(gè)命令。
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)
然后你就會(huì)看到出現(xiàn)好多信息在屏幕上,大致說的是gdb的一些版本信息說明之類的,但是它對(duì)你調(diào)試程序沒用呀,所以,你可以加上-q選項(xiàng),不輸出它們。
即是:gdb -q gdb_example
//gdb 還支持字符串查找,search str,從當(dāng)前行開始,向前查找含str的字符串;
reverse-search str,從當(dāng)前行開始,向后查找含str的字符串。
執(zhí)行許多命令后:
現(xiàn)在你的屏幕應(yīng)該被占滿了吧?想清空屏幕,可是還在gdb里面呀,怎么辦?其實(shí),gdb也支持運(yùn)行l(wèi)inux命令的,可以在gdb的提示符中,輸入shell,然后在輸入你需要的命令就可以了
(gdb) shell clear
這樣也能達(dá)到清屏的效果。
1、list命令
在gdb中運(yùn)行l(wèi)ist命令(縮寫l)可以列出代碼,list的具體形式包括:
list 顯示程序第linenum行周圍的源程序,如:
復(fù)制代碼
(gdb) list 15
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
復(fù)制代碼
list 顯示函數(shù)名為function的函數(shù)的源程序,如:
復(fù)制代碼
(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] =
復(fù)制代碼
list 顯示當(dāng)前行后面的源程序。
list - 顯示當(dāng)前行前面的源程序。
下面演示了使用gdb中的run(縮寫r)、break(縮寫b)、next(縮寫n)命令控制程序的運(yùn)行,并使用print(縮寫p)命令打印程序中的變量sum的過程:
復(fù)制代碼
(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}
復(fù)制代碼
2、run命令
在gdb中,運(yùn)行程序使用run命令。在程序運(yùn)行前,我們可以設(shè)置如下4方面的工作環(huán)境:
程序運(yùn)行參數(shù)
set args 可指定運(yùn)行時(shí)參數(shù),如:set args 10 20 30 40 50;
show args 命令可以查看設(shè)置好的運(yùn)行參數(shù)。
運(yùn)行環(huán)境
path
可設(shè)定程序的運(yùn)行路徑;how paths可查看程序的運(yùn)行路徑;
set environment varname [=value]用于設(shè)置環(huán)境變量,如set env USER=baohua;
show environment [varname]則用于查看環(huán)境變量。
工作目錄
cd
相當(dāng)于shell的cd命令;pwd 顯示當(dāng)前所在的目錄。
程序的輸入輸出
info terminal 用于顯示程序用到的終端的模式;
gdb中也可以使用重定向控制程序輸出,如run > outfile;
tty命令可以指定輸入輸出的終端設(shè)備,如:tty /dev/ttyS1。
3、break命令
在gdb中用break命令來設(shè)置斷點(diǎn),設(shè)置斷點(diǎn)的方法包括:
break
在進(jìn)入指定函數(shù)時(shí)停住,C++中可以使用class::function或function(type, type)格式來指定函數(shù)名。
break
在指定行號(hào)停住。
break +offset / break -offset
在當(dāng)前行號(hào)的前面或后面的offset行停住,offiset為自然數(shù)。
break filename:linenum
在源文件filename的linenum行處停住。
break filename:function
在源文件filename的function函數(shù)的入口處停住。
break *address
在程序運(yùn)行的內(nèi)存地址處停住。
break
break命令沒有參數(shù)時(shí),表示在下一條指令處停住。
break … if
“…”可以是上述的break 、break +offset / break –offset中的參數(shù),condition表示條件,在條件成立時(shí)停住。比如在循環(huán)體中,可以設(shè)置break if i=100,表示當(dāng)i為100時(shí)停住程序。
info
查看斷點(diǎn)時(shí),可使用info命令,如info breakpoints [n]、info break [n](n表示斷點(diǎn)號(hào))。
斷點(diǎn)的進(jìn)一步介紹//看了程序的代碼,感覺第6行代碼可能有點(diǎn)問題,現(xiàn)在就需要我就需要設(shè)置一個(gè)斷點(diǎn),讓程序停在第6行之前。
(gdb) break 6
Breakpoint 1 at 0x80484c8: file test.c, line 6.
(gdb)
下面一行的 信息,1說明我設(shè)置的這個(gè)斷點(diǎn)是第一個(gè)斷點(diǎn),斷點(diǎn)所在內(nèi)存地址為0x80484c8,它在文件test.c的第6行。
gdb還可以以條件表達(dá)式設(shè)置斷點(diǎn)。
(gdb) break 7 if n==6
Breakpoint 2 at 0x80484d1: file test.c, line 7.
(gdb)
這個(gè)斷點(diǎn)的含義是,如果n的值為6,則程序運(yùn)行到第7行停止。
當(dāng)然,還可以直接在某個(gè)函數(shù)處設(shè)置斷點(diǎn);直接break 函數(shù)名就可以了,
然后我們想看下設(shè)置的斷點(diǎn)信息,可以使用info breakpoints命令。
復(fù)制代碼
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x080484c8 in func at test.c:6
2 breakpoint keep y 0x080484d1 in func at test.c:7
stop only if n==6
4 breakpoint keep y 0x080484c1 in func at test.c:5
(gdb)
復(fù)制代碼
Num表示斷點(diǎn)的編號(hào);Type表示斷點(diǎn)的斷點(diǎn)的類型,第二個(gè)斷點(diǎn)類型還加上了條件;Disp表示中斷點(diǎn)在執(zhí)行一次之后是否失去作用,dis為是,keep為不是;Enb表示當(dāng)前中斷點(diǎn)是否有效,y為是,n為否;Address表示中斷點(diǎn)所處的內(nèi)存地址;What指出斷點(diǎn)所處的位置。
如果不需要程序在該斷點(diǎn)暫停時(shí),有兩種方法,一種是使該斷點(diǎn)失效,一種是直接刪除該斷點(diǎn)。
復(fù)制代碼
(gdb) disable 1
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep n 0x080484c8 in func at test.c:6
2 breakpoint keep y 0x080484d1 in func at test.c:7
stop only if n==6
3 breakpoint keep y 0x080484c1 in func at test.c:5
(gdb)
復(fù)制代碼
可以看到,第一個(gè)斷點(diǎn)的Enb變?yōu)閚了,表示該斷點(diǎn)已經(jīng)無效了,如果需要恢復(fù),可以使用enable命令。這里需要注意的是,disable后面的參數(shù)為斷點(diǎn)的編號(hào)。而不是行號(hào)。
直接刪除該斷點(diǎn),可以使用clear命令和delete命令。
(gdb) clear 6
已刪除的斷點(diǎn) 1
(gdb)
clear命令后面的參數(shù)為設(shè)置斷點(diǎn)的行號(hào),clear后面參數(shù)還可以加設(shè)置斷點(diǎn)的函數(shù)名。
delete命令后面的參數(shù)為斷點(diǎn)的編號(hào);可以一次刪除多個(gè)斷點(diǎn),斷點(diǎn)編號(hào)之間用空格隔開;如果delete后沒有參數(shù),默認(rèn)刪除所以斷點(diǎn),會(huì)給出提示選擇是否操作。
(gdb) delete
刪除所有斷點(diǎn)嗎? (y or n)
斷點(diǎn)設(shè)置好了,現(xiàn)在就可以調(diào)試了//
4、單步命令
在調(diào)試過程中,next命令用于單步執(zhí)行,類似VC++中的step over。next的單步不會(huì)進(jìn)入函數(shù)的內(nèi)部,與next對(duì)應(yīng)的step(縮寫s)命令則在單步執(zhí)行一個(gè)函數(shù)時(shí),會(huì)進(jìn)入其內(nèi)部,類似VC++中的step into。下面演示了step命令的執(zhí)行情況,在23行的add()函數(shù)調(diào)用處執(zhí)行step會(huì)進(jìn)入其內(nèi)部的“return a+b;”語句:
復(fù)制代碼
(gdb) break 25
Breakpoint 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;
復(fù)制代碼
單步執(zhí)行的更復(fù)雜用法包括:
step
單步跟蹤,如果有函數(shù)調(diào)用,則進(jìn)入該函數(shù)(進(jìn)入函數(shù)的前提是,此函數(shù)被編譯有debug信息)。step后面不加count表示一條條地執(zhí)行,加表示執(zhí)行后面的count條指令,然后再停住。
next
單步跟蹤,如果有函數(shù)調(diào)用,它不會(huì)進(jìn)入該函數(shù)。同樣地,next后面不加count表示一條條地執(zhí)行,加表示執(zhí)行后面的count條指令,然后再停住。
set step-mode
set step-mode on用于打開step-mode模式,這樣,在進(jìn)行單步跟蹤時(shí),程序不會(huì)因?yàn)闆]有debug信息而不停住,這個(gè)參數(shù)的設(shè)置可便于查看機(jī)器碼。set step-mod off用于關(guān)閉step-mode模式。
finish
運(yùn)行程序,直到當(dāng)前函數(shù)完成返回,并打印函數(shù)返回時(shí)的堆棧地址和返回值及參數(shù)值等信息。
until (縮寫u)
一直在循環(huán)體內(nèi)執(zhí)行單步,退不出來是一件令人煩惱的事情,until命令可以運(yùn)行程序直到退出循環(huán)體。
stepi(縮寫si)和nexti(縮寫ni)
stepi和nexti用于單步跟蹤一條機(jī)器指令,一條程序代碼有可能由數(shù)條機(jī)器指令完成,stepi和nexti可以單步執(zhí)行機(jī)器指令。 另外,運(yùn)行“display/i $pc”命令后,單步跟蹤會(huì)在打出程序代碼的同時(shí)打出機(jī)器指令,即匯編代碼。
5、continue命令
當(dāng)程序被停住后,可以使用continue命令(縮寫c,fg命令同continue命令)恢復(fù)程序的運(yùn)行直到程序結(jié)束,或到達(dá)下一個(gè)斷點(diǎn),命令格式為:
continue [ignore-count]
c [ignore-count]
fg [ignore-count]
ignore-count表示忽略其后多少次斷點(diǎn)。 假設(shè)我們?cè)O(shè)置了函數(shù)斷點(diǎn)add(),并watch i,則在continue過程中,每次遇到add()函數(shù)或i發(fā)生變化,程序就會(huì)停住,如:
復(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++)
復(fù)制代碼
6、print命令
在調(diào)試程序時(shí),當(dāng)程序被停住時(shí),可以使用print命令(縮寫為p),或是同義命令inspect來查看當(dāng)前程序的運(yùn)行數(shù)據(jù)。print命令的格式是:
print
print /
是表達(dá)式,是被調(diào)試的程序中的表達(dá)式,
是輸出的格式,比如,如果要把表達(dá)式按16進(jìn)制的格式輸出,那么就是/x。在表達(dá)式中,有幾種GDB所支持的操作符,它們可以用在任何一種語言中,“@”是一個(gè)和數(shù)組有關(guān)的操作符,“::”指定一個(gè)在文件或是函數(shù)中的變量,“{} ”表示一個(gè)指向內(nèi)存地址的類型為type的一個(gè)對(duì)象。
下面演示了查看sum[]數(shù)組的值的過程:
復(fù)制代碼
(gdb) print sum
$2 = {133, 155, 0, 0, 0, 0, 0, 0, 0, 0}
(gdb) next
復(fù)制代碼
當(dāng)需要查看一段連續(xù)內(nèi)存空間的值的時(shí)間,可以使用GDB的“@”操作符,“@”的左邊是第一個(gè)內(nèi)存地址,“@”的右邊則是想查看內(nèi)存的長度。例如如下動(dòng)態(tài)申請(qǐng)的內(nèi)存:
int *array = (int *) malloc (len * sizeof (int));
在GDB調(diào)試過程中這樣顯示出這個(gè)動(dòng)態(tài)數(shù)組的值:
p *array@len
print的輸出格式包括:
x 按十六進(jìn)制格式顯示變量。
d 按十進(jìn)制格式顯示變量。
u 按十六進(jìn)制格式顯示無符號(hào)整型。
o 按八進(jìn)制格式顯示變量。
t 按二進(jìn)制格式顯示變量。
a 按十六進(jìn)制格式顯示變量。
c 按字符格式顯示變量。
f 按浮點(diǎn)數(shù)格式顯示變量。
我們可用display命令設(shè)置一些自動(dòng)顯示的變量,當(dāng)程序停住時(shí),或是單步跟蹤時(shí),這些變量會(huì)自動(dòng)顯示。 如果要修改變量,如x的值,可使用如下命令:
print x=4
當(dāng)用GDB的print查看程序運(yùn)行時(shí)的數(shù)據(jù)時(shí),每一個(gè)print都會(huì)被GDB記錄下來。GDB會(huì)以$1,$2,$3 …這樣的方式為每一個(gè)print命令編號(hào)。我們可以使用這個(gè)編號(hào)訪問以前的表達(dá)式,如$1。
7、watch命令
watch一般來觀察某個(gè)表達(dá)式(變量也是一種表達(dá)式)的值是否有變化了,如果有變化,馬上停住程序。
我們有下面的幾種方法來設(shè)置觀察點(diǎn):
watch :為表達(dá)式(變量)expr設(shè)置一個(gè)觀察點(diǎn)。一旦表達(dá)式值有變化時(shí),馬上停住程序。
rwatch :當(dāng)表達(dá)式(變量)expr被讀時(shí),停住程序。
awatch :當(dāng)表達(dá)式(變量)的值被讀或被寫時(shí),停住程序。
info watchpoints:列出當(dāng)前所設(shè)置了的所有觀察點(diǎn)。 下面演示了觀察i并在連續(xù)運(yùn)行next時(shí)一旦發(fā)現(xiàn)i變化,i值就會(huì)顯示出來的過程:
復(fù)制代碼
(gdb) watch i
Hardware 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++)
復(fù)制代碼
8、examine命令
我們可以使用examine命令(縮寫為x)來查看內(nèi)存地址中的值。examine命令的語法如下所示:
x/<n/f/u>
表示一個(gè)內(nèi)存地址。“x/”后的n、f、u都是可選的參數(shù),n 是一個(gè)正整數(shù),表示顯示內(nèi)存的長度,也就是說從當(dāng)前地址向后顯示幾個(gè)地址的內(nèi)容;f 表示顯示的格式,如果地址所指的是字符串,那么格式可以是s,如果地址是指令地址,那么格式可以是i;u 表示從當(dāng)前地址往后請(qǐng)求的字節(jié)數(shù),如果不指定的話,GDB默認(rèn)是4字節(jié)。u參數(shù)可以被一些字符代替:b表示單字節(jié),h表示雙字節(jié),w表示四字節(jié),g表示八 字節(jié)。當(dāng)我們指定了字節(jié)長度后,GDB會(huì)從指定的內(nèi)存地址開始,讀寫指定字節(jié),并把其當(dāng)作一個(gè)值取出來。n、f、u這3個(gè)參數(shù)可以一起使用,例如命令“x/3uh 0x54320”表示從內(nèi)存地址0x54320開始以雙字節(jié)為1個(gè)單位(h)、16進(jìn)制方式(u)顯示3個(gè)單位(3)的內(nèi)存。 ==
譬如下面的例子:
main()
{
char *c = “hello world”;
printf("%s\n", c);
}
我們?cè)?/p>
char *c = “hello world”;
下一行設(shè)置斷點(diǎn)后:
復(fù)制代碼
(gdb) l
1 main()
2 {
3 char *c = “hello world”;
4 printf("%s\n", c);
5 }
(gdb) b 4
Breakpoint 1 at 0x100000f17: file main.c, line 4.
(gdb) r
Starting program: /Users/songbarry/main
Reading symbols for shared libraries +. done
Breakpoint 1, main () at main.c:4
4 printf("%s\n", c);
復(fù)制代碼
可以通過多種方式看C指向的字符串:
方法1:
(gdb) p c
$1 = 0x100000f2e “hello world”
方法2:
(gdb) x/s 0x100000f2e
0x100000f2e: “hello world”
方法3:
(gdb) p (char *)0x100000f2e
$3 = 0x100000f2e “hello world”
將第一個(gè)字符改為大寫:
(gdb) p *(char *)0x100000f2e=‘H’
$4 = 72 ‘H’
再看看C:
(gdb) p c
$5 = 0x100000f2e “Hello world”
9、set命令
修改寄存器:
(gdb) set $v0 = 0x004000000
(gdb) set $epc = 0xbfc00000
修改內(nèi)存:
(gdb) set {unsigned int}0x8048a51=0x0
譬如對(duì)于第8節(jié)的例子:
(gdb) set {unsigned int}0x100000f2e=0x0
(gdb) x/10cb 0x100000f2e
0x100000f2e: 0 ‘\0’ 0 ‘\0’ 0 ‘\0’ 0 ‘\0’ 111 ‘o’ 32 ’ ’ 119 ‘w’ 111 ‘o’
0x100000f36: 114 ‘r’ 108 ‘l’
(gdb) p c
$10 = 0x100000f2e “”
10、jump命令
一般來說,被調(diào)試程序會(huì)按照程序代碼的運(yùn)行順序依次執(zhí)行,但是GDB也提供了亂序執(zhí)行的功能,也就是說,GDB可以修改程序的執(zhí)行順序,從而讓程序隨意跳躍。這個(gè)功能可以由GDB的jump命令:jump 來指定下一條語句的運(yùn)行點(diǎn)。可以是文件的行號(hào),可以是file:line格式,也可以是+num這種偏移量格式,表示下一條運(yùn)行語句從哪里開始。jump
11、signal命令
使用singal命令,可以產(chǎn)生一個(gè)信號(hào)量給被調(diào)試的程序,如中斷信號(hào)“Ctrl+C”。這非常方便于程序的調(diào)試,可以在程序運(yùn)行的任意位置設(shè)置斷點(diǎn),并在該斷點(diǎn)用GDB產(chǎn)生一個(gè)信號(hào)量,這種精確地在某處產(chǎn)生信號(hào)的方法非常有利于程序的調(diào)試。 signal命令的語法是:signal ,UNIX的系統(tǒng)信號(hào)量通常從1到15,所以取值也在這個(gè)范圍。
12、return命令
如果在函數(shù)中設(shè)置了調(diào)試斷點(diǎn),在斷點(diǎn)后還有語句沒有執(zhí)行完,這時(shí)候我們可以使用return命令強(qiáng)制函數(shù)忽略還沒有執(zhí)行的語句并返回。
return
return
上述return命令用于取消當(dāng)前函數(shù)的執(zhí)行,并立即返回,如果指定了,那么該表達(dá)式的值會(huì)被作為函數(shù)的返回值。
13、call命令
call命令用于強(qiáng)制調(diào)用某函數(shù): call 表達(dá)式中可以一是函數(shù),以此達(dá)到強(qiáng)制調(diào)用函數(shù)的目的,它會(huì)顯示函數(shù)的返回值(如果函數(shù)返回值不是void)。 其實(shí),前面介紹的print命令也可以完成強(qiáng)制調(diào)用函數(shù)的功能。
14、info命令
info命令可以在調(diào)試時(shí)用來查看寄存器、斷點(diǎn)、觀察點(diǎn)和信號(hào)等信息。
要查看寄存器的值,可以使用如下命令:
info registers (查看除了浮點(diǎn)寄存器以外的寄存器)
info all-registers (查看所有寄存器,包括浮點(diǎn)寄存器)
info registers <regname …> (查看所指定的寄存器)
info break 查看斷點(diǎn)信息
info watchpoints 列出當(dāng)前所設(shè)置的所有觀察點(diǎn),
info signals info handle 查看有哪些信號(hào)正在被GDB檢測(cè),
info line命令來查看源代碼在內(nèi)存中的地址。
info threads可以看多線程。
info line后面可以跟行號(hào)、函數(shù)名、文件名:行號(hào)、文件名:函數(shù)名等多種形式,例如下面的命令會(huì)打印出所指定的源碼在運(yùn)行時(shí)的內(nèi)存地址:
info line tst.c:func
15、set scheduler-locking off|on|step
off 不鎖定任何線程,也就是所有線程都執(zhí)行,這是默認(rèn)值。
on 只有當(dāng)前被調(diào)試程序會(huì)執(zhí)行。
step 在單步的時(shí)候,除了next過一個(gè)函數(shù)的情況以外,只有當(dāng)前線程會(huì)執(zhí)行。
與多線程調(diào)試相關(guān)的命令還包括:
thread ID
切換當(dāng)前調(diào)試的線程為指定ID的線程。
break thread_test.c:123 thread all
在所有線程中相應(yīng)的行上設(shè)置斷點(diǎn)
thread apply ID1 ID2 command
讓一個(gè)或者多個(gè)線程執(zhí)行GDB命令command。
thread apply all command
讓所有被調(diào)試線程執(zhí)行GDB命令command。
16、disassemble
disassemble命令用于反匯編,它可被用來查看當(dāng)前執(zhí)行時(shí)的源代碼的機(jī)器碼,其實(shí)際上只是把目前內(nèi)存中的指令dump出來。下面的示例用于查看函數(shù)func的匯編代碼:
復(fù)制代碼
(gdb) disassemble func
Dump of assembler code for function func:
0x8048450 : 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.
今天先寫這些命令,還有其他的命令之后在更新。
總結(jié)
以上是生活随笔為你收集整理的linux--gdb调试的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux下输出不同颜色的字体详解
- 下一篇: Linux--网络编程