用一个例子告诉你gdb调试工具如何使用
????????????????????????????????????用GDB調(diào)試程序
GDB概述
GDB是GNU開(kāi)源組織發(fā)布的一個(gè)強(qiáng)大的UNIX下的程序調(diào)試工具。或許,各位比較喜歡那種圖形界面方式的,像VC、BCB等IDE的調(diào)試,但如果你是在UNIX平臺(tái)下做軟件,你會(huì)發(fā)現(xiàn)GDB這個(gè)調(diào)試工具有比VC、BCB的圖形化調(diào)試器更強(qiáng)大的功能。所謂“寸有所長(zhǎng),尺有所短”就是這個(gè)道理。
一般來(lái)說(shuō),GDB主要幫忙你完成下面四個(gè)方面的功能:
??? 1、啟動(dòng)你的程序,可以按照你的自定義的要求隨心所欲的運(yùn)行程序。
??? 2、可讓被調(diào)試的程序在你所指定的調(diào)置的斷點(diǎn)處停住。(斷點(diǎn)可以是條件表達(dá)式)
??? 3、當(dāng)程序被停住時(shí),可以檢查此時(shí)你的程序中所發(fā)生的事。
??? 4、動(dòng)態(tài)的改變你程序的執(zhí)行環(huán)境。
從上面看來(lái),GDB和一般的調(diào)試工具沒(méi)有什么兩樣,基本上也是完成這些功能,不過(guò)在細(xì)節(jié)上,你會(huì)發(fā)現(xiàn)GDB這個(gè)調(diào)試工具的強(qiáng)大,大家可能比較習(xí)慣了圖形化的調(diào)試工具,但有時(shí)候,命令行的調(diào)試工具卻有著圖形化工具所不能完成的功能。讓我們一一看來(lái)。
用一個(gè)例子告訴你gdb調(diào)試工具如何使用
步驟:(1)在工作目錄上新建文件greet.c,并用vi啟動(dòng):vi great.c
(2)在vi中輸入相應(yīng)代碼。(這里就不具體給出了)
(3)在vi中保存并推出:使用:wq命令
(4)用gcc編譯:gcc -g greet.c -o greet
(5)運(yùn)行g(shù)reet,使用命令./greet,輸出如下結(jié)果:
????????The original string is Embedded Linux
????????The original string is
????????可見(jiàn),該程序沒(méi)有能夠倒序輸出。
(6)啟動(dòng)gdb調(diào)試:gdb greet
(7)查看源代碼,使用命令:l
(8)在30行設(shè)置斷點(diǎn)(for循環(huán)),使用命令:b 30
(9)在33行設(shè)置斷點(diǎn)(printf函數(shù)),使用命令:b 33
(10)查看斷點(diǎn)設(shè)置情況,使用命令:info b
(11)運(yùn)行代碼,使用:r
(12)單步運(yùn)行代碼,使用:n
(13)查看暫停點(diǎn)變量值,使用:p string2[size-i]
(14)繼續(xù)單步運(yùn)行代碼數(shù)次,并查看string2[size-1]的值是否正確
(15)繼續(xù)程序的運(yùn)行,使用:c
(16)程序在printf函數(shù)前停止運(yùn)行,此時(shí)依次查看string2[0]、string2[1]......,發(fā)現(xiàn)string[0]沒(méi)有被正確賦值,而后面的賦值都是正確的,這時(shí),定位程序第31行,發(fā)現(xiàn)程序運(yùn)行結(jié)果錯(cuò)誤的原因在于size-1。由于i只能增到size-1,這樣string2[0]就永遠(yuǎn)不能被賦值而保持NULL,故不能輸出任何結(jié)果。
(17)退出gdb用:q
(18)重新編譯greet.c,把其中的string2[size-i]=string1[i]改為string2[size-i-1]=string[i]即可。
(19)使用gcc重新編譯:gcc -g greet.c -o greet
(20)產(chǎn)看運(yùn)行結(jié)果:./greet
????????The original string is Embedded Linux
????????The original string is xuniL deddebmE
????????這時(shí),輸出正確結(jié)果。
/
另一個(gè)調(diào)試示例
源程序:tst.c
1 #include <stdio.h>23 int func(int n)4 {5 int sum=0,i;6 for(i=0; i<n; i++)7 {8 sum+=i;9 }10 return sum;11 }121314 main()15 {16 int i;17 long result = 0;18 for(i=1; i<=100; i++)19 {20 result += i;21 }2223 printf("result[1-100] = %d /n", result );24 printf("result[1-250] = %d /n", func(250) );25 }編譯生成執(zhí)行文件:(Linux下)
??? hchen/test> cc -g tst.c -o tst
使用GDB調(diào)試:
hchen/test> gdb tst? <---------- 啟動(dòng)GDB
GNU gdb 5.1.1
Copyright 2002 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-suse-linux"...
(gdb) l???? <-------------------- l命令相當(dāng)于list,從第一行開(kāi)始例出原碼。
1??????? #include <stdio.h>
2
3??????? int func(int n)
4??????? {
5??????????????? int sum=0,i;
6??????????????? for(i=0; i<n; i++)
7??????????????? {
8??????????????????????? sum+=i;
9??????????????? }
10?????????????? return sum;
(gdb)?????? <-------------------- 直接回車(chē)表示,重復(fù)上一次命令
11?????? }
12
13
14?????? main()
15?????? {
16?????????????? int i;
17?????????????? long result = 0;
18?????????????? for(i=1; i<=100; i++)
19?????????????? {
20?????????????????????? result += i;????
(gdb) break 16??? <-------------------- 設(shè)置斷點(diǎn),在源程序第16行處。
Breakpoint 1 at 0x8048496: file tst.c, line 16.
(gdb) break func? <-------------------- 設(shè)置斷點(diǎn),在函數(shù)func()入口處。
Breakpoint 2 at 0x8048456: file tst.c, line 5.
(gdb) info break? <-------------------- 查看斷點(diǎn)信息。
Num Type?????????? Disp Enb Address??? What
1?? breakpoint???? keep y?? 0x08048496 in main at tst.c:16
2?? breakpoint???? keep y?? 0x08048456 in func at tst.c:5
(gdb) r?????????? <--------------------- 運(yùn)行程序,run命令簡(jiǎn)寫(xiě)
Starting program: /home/hchen/test/tst
Breakpoint 1, main () at tst.c:17??? <---------- 在斷點(diǎn)處停住。
17?????????????? long result = 0;
(gdb) n????????? <--------------------- 單條語(yǔ)句執(zhí)行,next命令簡(jiǎn)寫(xiě)。
18?????????????? for(i=1; i<=100; i++)
(gdb) n
20?????????????????????? result += i;
(gdb) n
18?????????????? for(i=1; i<=100; i++)
(gdb) n
20?????????????????????? result += i;
(gdb) c????????? <--------------------- 繼續(xù)運(yùn)行程序,continue命令簡(jiǎn)寫(xiě)。
Continuing.
result[1-100] = 5050?????? <----------程序輸出。
Breakpoint 2, func (n=250) at tst.c:5
5??????????????? int sum=0,i;
(gdb) n
6??????????????? for(i=1; i<=n; i++)
(gdb) p i??????? <--------------------- 打印變量i的值,print命令簡(jiǎn)寫(xiě)。
$1 = 134513808
(gdb) n
8??????????????????????? sum+=i;
(gdb) n
6??????????????? for(i=1; i<=n; i++)
(gdb) p sum
$2 = 1
(gdb) n
8??????????????????????? sum+=i;
(gdb) p i
$3 = 2
(gdb) n
6??????????????? for(i=1; i<=n; i++)
(gdb) p sum
$4 = 3
(gdb) bt??????? <--------------------- 查看函數(shù)堆棧。
#0? func (n=250) at tst.c:5
#1? 0x080484e4 in main () at tst.c:24
#2? 0x400409ed in __libc_start_main () from /lib/libc.so.6
(gdb) finish??? <--------------------- 退出函數(shù)。
Run till exit from #0? func (n=250) at tst.c:5
0x080484e4 in main () at tst.c:24
24????????????? printf("result[1-250] = %d /n", func(250) );
Value returned is $6 = 31375
(gdb) c???? <--------------------- 繼續(xù)運(yùn)行。
Continuing.
result[1-250] = 31375??? <----------程序輸出。
Program exited with code 027. <--------程序退出,調(diào)試結(jié)束。
(gdb) q???? <--------------------- 退出gdb。
hchen/test>
好了,有了以上的感性認(rèn)識(shí),還是讓我們來(lái)系統(tǒng)地認(rèn)識(shí)一下gdb吧。
?
使用GDB
————
一般來(lái)說(shuō)GDB主要調(diào)試的是C/C++的程序。要調(diào)試C/C++的程序,首先在編譯時(shí),我們必須要把調(diào)試信息加到可執(zhí)行文件中。使用編譯器(cc/gcc/g++)的 -g 參數(shù)可以做到這一點(diǎn)。如:
??? > cc -g hello.c -o hello
??? > g++ -g hello.cpp -o hello
如果沒(méi)有-g,你將看不見(jiàn)程序的函數(shù)名、變量名,所代替的全是運(yùn)行時(shí)的內(nèi)存地址。當(dāng)你用-g把調(diào)試信息加入之后,并成功編譯目標(biāo)代碼以后,讓我們來(lái)看看如何用gdb來(lái)調(diào)試他。
啟動(dòng)GDB的方法有以下幾種:
??? 1、gdb <program>?
?????? program也就是你的執(zhí)行文件,一般在當(dāng)然目錄下。
??? 2、gdb <program> core
?????? 用gdb同時(shí)調(diào)試一個(gè)運(yùn)行程序和core文件,core是程序非法執(zhí)行后core dump后產(chǎn)生的文件。
??? 3、gdb <program> <PID>
?????? 如果你的程序是一個(gè)服務(wù)程序,那么你可以指定這個(gè)服務(wù)程序運(yùn)行時(shí)的進(jìn)程ID。gdb會(huì)自動(dòng)attach上去,并調(diào)試他。program應(yīng)該在PATH環(huán)境變量中搜索得到。
?
GDB啟動(dòng)時(shí),可以加上一些GDB的啟動(dòng)開(kāi)關(guān),詳細(xì)的開(kāi)關(guān)可以用gdb -help查看。我在下面只例舉一些比較常用的參數(shù):
??? -symbols <file>?
??? -s <file>?
??? 從指定文件中讀取符號(hào)表。
??? -se file?
??? 從指定文件中讀取符號(hào)表信息,并把他用在可執(zhí)行文件中。
??? -core <file>
??? -c <file>?
??? 調(diào)試時(shí)core dump的core文件。
??? -directory <directory>
??? -d <directory>
??? 加入一個(gè)源文件的搜索路徑。默認(rèn)搜索路徑是環(huán)境變量中PATH所定義的路徑。
總結(jié)
以上是生活随笔為你收集整理的用一个例子告诉你gdb调试工具如何使用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 树莓派wiringPi常用的函数介绍
- 下一篇: Linux dd 命令具体用法