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