使用GDB調試器

引用:(轉載)gdb中彙編調試

         原名 gdb相關(gdb十分鐘教程)

 

本文寫給主要工作在Windows操作系統下而又需要開發一些跨平臺軟件的程序員朋友,以及程序愛好者。

GDB是一個由GNU開源組織發佈的、UNIX/LINUX操作系統下的、基於命令行的、功能強大的程序調試工具。

GDB中的命令固然很多,但我們只需掌握其中十個左右的命令,就大致可以完成日常的基本的程序調試工作。

命令 解釋 示例
file <文件名> 加載被調試的可執行程序文件。
因爲一般都在被調試程序所在目錄下執行GDB,因而文本名不需要帶路徑。
(gdb) file gdb-sample
r Run的簡寫,運行被調試的程序。
如果此前沒有下過斷點,則執行完整個程序;如果有斷點,則程序暫停在第一個可用斷點處。
(gdb) r
c Continue的簡寫,繼續執行被調試程序,直至下一個斷點或程序結束。 (gdb) c
b <行號>
b <函數名稱>
b *<函數名稱>
b *<代碼地址>

d [編號]

b: Breakpoint的簡寫,設置斷點。兩可以使用“行號”“函數名稱”“執行地址”等方式指定斷點位置。
其中在函數名稱前面加“*”符號表示將斷點設置在“由編譯器生成的prolog代碼處”。如果不瞭解彙編,可以不予理會此用法。

d: Delete breakpoint的簡寫,刪除指定編號的某個斷點,或刪除所有斷點。斷點編號從1開始遞增。

(gdb) b 8
(gdb) b main
(gdb) b *main
(gdb) b *0x804835c

(gdb) d

s, n s: 執行一行源程序代碼,如果此行代碼中有函數調用,則進入該函數;
n: 執行一行源程序代碼,此行代碼中的函數調用也一併執行。

s 相當於其它調試器中的“Step Into (單步跟蹤進入)”;
n 相當於其它調試器中的“Step Over (單步跟蹤)”。

這兩個命令必須在有源代碼調試信息的情況下纔可以使用(GCC編譯時使用“-g”參數)。

(gdb) s
(gdb) n
si, ni si命令類似於s命令,ni命令類似於n命令。所不同的是,這兩個命令(si/ni)所針對的是彙編指令,而s/n針對的是源代碼。 (gdb) si
(gdb) ni
p <變量名稱> Print的簡寫,顯示指定變量(臨時變量或全局變量)的值。 (gdb) p i
(gdb) p nGlobalVar
display ...

undisplay <編號>

display,設置程序中斷後欲顯示的數據及其格式。
例如,如果希望每次程序中斷後可以看到即將被執行的下一條彙編指令,可以使用命令
“display /i $pc”
其中 $pc 代表當前彙編指令,/i 表示以十六進行顯示。當需要關心彙編代碼時,此命令相當有用。

undispaly,取消先前的display設置,編號從1開始遞增。

(gdb) display /i $pc

(gdb) undisplay 1

i Info的簡寫,用於顯示各類信息,詳情請查閱“help i”。 (gdb) i r
q Quit的簡寫,退出GDB調試環境。 (gdb) q
help [命令名稱] GDB幫助命令,提供對GDB名種命令的解釋說明。
如果指定了“命令名稱”參數,則顯示該命令的詳細說明;如果沒有指定參數,則分類顯示所有GDB命令,供用戶進一步瀏覽和查詢。
(gdb) help display

/add************************************/

j命令              回跳

ret               設置返回值        (例ret 0/ret -1)

/add************************************/

廢話不多說,下面開始實踐。

先給出一個示例用的小程序,C語言代碼,簡單的不能再簡單了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

//此程序僅作爲“GDB十分鐘教程”的示例代碼, by liigo
//Email: 
[email protected]
//blog: http://blog.csdn.net/liigo
//WebSite: www.liigo.com
 

#include 
<stdio.h>

int
 nGlobalVar = 0;

int
 tempFunction(int aint b)
{
    printf("tempFunction is called, a = %d, b = %d /n"ab
);
    return (a + b
);
}


int
 main()
{
    int n
;
        n = 1
;
        n
++;
        n
--;

        nGlobalVar += 100
;
        nGlobalVar -= 12
;

    printf("n = %d, nGlobalVar = %d /n"nnGlobalVar
);

        n = tempFunction(12
);
    printf("n = %d"n
);

    return 0
;
}

請將此代碼複製出來並保存到文件 gdb-sample.c 中,然後切換到此文件所在目錄,用GCC編譯之:

gcc gdb-sample.c -o gdb-sample -g

在上面的命令行中,使用 -o 參數指定了編譯生成的可執行文件名爲 gdb-sample,使用參數 -g 表示將源代碼信息編譯到可執行文件中。如果不使用參數 -g,會給後面的GDB調試造成不便。當然,如果我們沒有程序的源代碼,自然也無從使用 -g 參數,調試/跟蹤時也只能是彙編代碼級別的調試/跟蹤。

下面“gdb”命令啓動GDB,將首先顯示GDB說明,不管它:

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)

上面最後一行“(gdb) ”爲GDB內部命令引導符,等待用戶輸入GDB命令。

下面使用“file”命令載入被調試程序 gdb-sample(這裏的 gdb-sample 即前面 GCC 編譯輸出的可執行文件):

(gdb) file gdb-sample
Reading symbols from gdb-sample...done.

上面最後一行提示已經加載成功。

下面使用“r”命令執行(Run)被調試文件,因爲尚未設置任何斷點,將直接執行到程序結束:

(gdb) r
Starting program: /home/liigo/temp/test_jmp/test_jmp/gdb-sample
n = 1, nGlobalVar = 88
tempFunction is called, a = 1, b = 2
n = 3
Program exited normally.

下面使用“b”命令在 main 函數開頭設置一個斷點(Breakpoint):

(gdb) b main
Breakpoint 1 at 0x804835c: file gdb-sample.c, line 19.

上面最後一行提示已經成功設置斷點,並給出了該斷點信息:在源文件 gdb-sample.c 第19行處設置斷點;這是本程序的第一個斷點(序號爲1);斷點處的代碼地址爲 0x804835c(此值可能僅在本次調試過程中有效)。回過頭去看源代碼,第19行中的代碼爲“n = 1”,恰好是 main 函數中的第一個可執行語句(前面的“int n;”爲變量定義語句,並非可執行語句)。

再次使用“r”命令執行(Run)被調試程序:

(gdb) r
Starting program: /home/liigo/temp/gdb-sample

Breakpoint 1, main () at gdb-sample.c:19
19 n = 1;

程序中斷在gdb-sample.c第19行處,即main函數是第一個可執行語句處。

上面最後一行信息爲:下一條將要執行的源代碼爲“n = 1;”,它是源代碼文件gdb-sample.c中的第19行。

下面使用“s”命令(Step)執行下一行代碼(即第19行“n = 1;”):

(gdb) s
20 n++;

上面的信息表示已經執行完“n = 1;”,並顯示下一條要執行的代碼爲第20行的“n++;”。

既然已經執行了“n = 1;”,即給變量 n 賦值爲 1,那我們用“p”命令(Print)看一下變量 n 的值是不是 1 :

(gdb) p n
$1 = 1

果然是 1。($1大致是表示這是第一次使用“p”命令——再次執行“p n”將顯示“$2 = 1”——此信息應該沒有什麼用處。)

下面我們分別在第26行、tempFunction 函數開頭各設置一個斷點(分別使用命令“b 26”“b tempFunction”):

(gdb) b 26
Breakpoint 2 at 0x804837b: file gdb-sample.c, line 26.
(gdb) b tempFunction
Breakpoint 3 at 0x804832e: file gdb-sample.c, line 12.

使用“c”命令繼續(Continue)執行被調試程序,程序將中斷在第二 個斷點(26行),此時全局變量 nGlobalVar 的值應該是 88;再一次執行“c”命令,程序將中斷於第三個斷點(12行,tempFunction 函數開頭處),此時tempFunction 函數的兩個參數 a、b 的值應分別是 1 和 2:

(gdb) c
Continuing.

Breakpoint 2, main () at gdb-sample.c:26
26 printf("n = %d, nGlobalVar = %d /n", n, nGlobalVar);
(gdb) p nGlobalVar
$2 = 88
(gdb) c
Continuing.
n = 1, nGlobalVar = 88

Breakpoint 3, tempFunction (a=1, b=2) at gdb-sample.c:12
12 printf("tempFunction is called, a = %d, b = %d /n", a, b);
(gdb) p a
$3 = 1
(gdb) p b
$4 = 2

上面反饋的信息一切都在我們預料之中,哈哈~~~

再一次執行“c”命令(Continue),因爲後面再也沒有其它斷點,程序將一直執行到結束:

(gdb) c
Continuing.
tempFunction is called, a = 1, b = 2
n = 3
Program exited normally.

 

有時候需要看到編譯器生成的彙編代碼,以進行彙編級的調試或跟蹤,又該如何操作呢?

這就要用到display命令“display /i $pc”了(此命令前面已有詳細解釋):

(gdb) display /i $pc
(gdb)

此後程序再中斷時,就可以顯示出彙編代碼了:

(gdb) r
Starting program: /home/liigo/temp/test_jmp/test_jmp/gdb-sample

Breakpoint 1, main () at gdb-sample.c:19
19 n = 1;
1: x/i $pc 0x804835c <main+16>: movl $0x1,0xfffffffc(%ebp)

看到了彙編代碼,“n = 1;”對應的彙編代碼是“movl $0x1,0xfffffffc(%ebp)”。

並且以後程序每次中斷都將顯示下一條彙編指定(“si”命令用於執行一條彙編代碼——區別於“s”執行一行C代碼):

(gdb) si
20 n++;
1: x/i $pc 0x8048363 <main+23>: lea 0xfffffffc(%ebp),%eax
(gdb) si
0x08048366 20 n++;
1: x/i $pc 0x8048366 <main+26>: incl (%eax)
(gdb) si
21 n--;
1: x/i $pc 0x8048368 <main+28>: lea 0xfffffffc(%ebp),%eax
(gdb) si
0x0804836b 21 n--;
1: x/i $pc 0x804836b <main+31>: decl (%eax)
(gdb) si
23 nGlobalVar += 100;
1: x/i $pc 0x804836d <main+33>: addl $0x64,0x80494fc

 

接下來我們試一下命令“b *<函數名稱>”。

爲了更簡明,有必要先刪除目前所有斷點(使用“d”命令——Delete breakpoint):

(gdb) d
Delete all breakpoints? (y or n) y
(gdb)

當被詢問是否刪除所有斷點時,輸入“y”並按回車鍵即可。

下面使用命令“b *main”在 main 函數的 prolog 代碼處設置斷點(prolog、epilog,分別表示編譯器在每個函數的開頭和結尾自行插入的代碼):

(gdb) b *main
Breakpoint 4 at 0x804834c: file gdb-sample.c, line 17.
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/liigo/temp/test_jmp/test_jmp/gdb-sample

Breakpoint 4, main () at gdb-sample.c:17
17 {
1: x/i $pc 0x804834c <main>: push %ebp
(gdb) si
0x0804834d 17 {
1: x/i $pc 0x804834d <main+1>: mov %esp,%ebp
(gdb) si
0x0804834f in main () at gdb-sample.c:17
17 {
1: x/i $pc 0x804834f <main+3>: sub $0x8,%esp
(gdb) si
0x08048352 17 {
1: x/i $pc 0x8048352 <main+6>: and $0xfffffff0,%esp
(gdb) si
0x08048355 17 {
1: x/i $pc 0x8048355 <main+9>: mov $0x0,%eax
(gdb) si
0x0804835a 17 {
1: x/i $pc 0x804835a <main+14>: sub %eax,%esp
(gdb) si
19 n = 1;
1: x/i $pc 0x804835c <main+16>: movl $0x1,0xfffffffc(%ebp)

此時可以使用“i r”命令顯示寄存器中的當前值———“i r”即“Infomation Register”:

(gdb) i r
eax 0xbffff6a4 -1073744220
ecx 0x42015554 1107383636
edx 0x40016bc8 1073834952
ebx 0x42130a14 1108544020
esp 0xbffff6a0 0xbffff6a0
ebp 0xbffff6a8 0xbffff6a8
esi 0x40015360 1073828704
edi 0x80483f0 134513648
eip 0x8048366 0x8048366
eflags 0x386 902
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x33 51

當然也可以顯示任意一個指定的寄存器值:

(gdb) i r eax
eax 0xbffff6a4 -1073744220

 

最後一個要介紹的命令是“q”,退出(Quit)GDB調試環境:

(gdb) q
The program is running. Exit anyway? (y or n)

 

 

 

GDB調試精粹及使用實例

來源:不詳

一:列文件清單 
1. List 
(gdb) list line1,line2 

二:執行程序 
要想運行準備調試的程序,可使用run命令,在它後面可以跟隨發給該程序的任何參數,包括標準輸入和標準輸出說明符(<和>)和外殼通配符(*、?、[、])在內。 
如果你使用不帶參數的run命令,gdb就再次使用你給予前一條run命令的參數,這是很有用的。 
利用set args 命令就可以修改發送給程序的參數,而使用show args 命令就可以查看其缺省參數的列表。 
(gdb)set args –b –x 
(gdb) show args 
backtrace命令爲堆棧提供向後跟蹤功能。 
Backtrace 命令產生一張列表,包含着從最近的過程開始的所以有效過程和調用這些過程的參數。 

三:顯示數據 
利用print 命令可以檢查各個變量的值。 
(gdb) print p (p爲變量名) 
whatis 命令可以顯示某個變量的類型 
(gdb) whatis p 
type = int * 

print 是gdb的一個功能很強的命令,利用它可以顯示被調試的語言中任何有效的表達式。表達式除了包含你程序中的變量外,還可以包含以下內容: 
l 對程序中函數的調用 
(gdb) print find_entry(1,0) 
l 數據結構和其他複雜對象 
(gdb) print *table_start 
$8={e=reference=’/000’,location=0x0,next=0x0} 
l 值的歷史成分 
(gdb)print $1 ($1爲歷史記錄變量,在以後可以直接引用 $1 的值) 
l 人爲數組 
人爲數組提供了一種去顯示存儲器塊(數組節或動態分配的存儲區)內容的方法。早期的調試程序沒有很好的方法將任意的指針換成一個數組。就像對待參數一樣,讓我們查看內存中在變量h後面的10個整數,一個動態數組的語法如下所示: 
base@length 
因此,要想顯示在h後面的10個元素,可以使用h@10: 
(gdb)print h@10 
$13=(-1,345,23,-234,0,0,0,98,345,10) 

四:斷點(breakpoint) 
break命令(可以簡寫爲b)可以用來在調試的程序中設置斷點,該命令有如下四種形式: 
l break line-number 使程序恰好在執行給定行之前停止。 
l break function-name 使程序恰好在進入指定的函數之前停止。 
l break line-or-function if condition 如果condition(條件)是真,程序到達指定行或函數時停止。 
l break routine-name 在指定例程的入口處設置斷點 

如果該程序是由很多原文件構成的,你可以在各個原文件中設置斷點,而不是在當前的原文件中設置斷點,其方法如下: 
(gdb) break filename:line-number 
(gdb) break filename:function-name 

要想設置一個條件斷點,可以利用break if命令,如下所示: 
(gdb) break line-or-function if expr 
例: 
(gdb) break 46 if testsize==100 

從斷點繼續運行:countinue 命令 
五.斷點的管理 

1. 顯示當前gdb的斷點信息: 
(gdb) info break 
他會以如下的形式顯示所有的斷點信息: 
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 
(gdb) 
2.刪除指定的某個斷點: 
(gdb) delete breakpoint 1 
該命令將會刪除編號爲1的斷點,如果不帶編號參數,將刪除所有的斷點 
(gdb) delete breakpoint 
3.禁止使用某個斷點 
(gdb) disable breakpoint 1 
該命令將禁止斷點 1,同時斷點信息的 (Enb)域將變爲 n 
4.允許使用某個斷點 
(gdb) enable breakpoint 1 
該命令將允許斷點 1,同時斷點信息的 (Enb)域將變爲 y 
5.清除原文件中某一代碼行上的所有斷點 
(gdb)clean number 
注:number 爲原文件的某個代碼行的行號 
六.變量的檢查和賦值 
l whatis:識別數組或變量的類型 
l ptype:比whatis的功能更強,他可以提供一個結構的定義 
l set variable:將值賦予變量 
l print 除了顯示一個變量的值外,還可以用來賦值 

七.單步執行 
l next 
不進入的單步執行 
l step 
進入的單步執行 
如果已經進入了某函數,而想退出該函數返回到它的調用函數中,可使用命令finish 
八.函數的調用 
l call name 調用和執行一個函數 
(gdb) call gen_and_sork( 1234,1,0 ) 
(gdb) call printf(“abcd”) 
$1=4 
l finish 結束執行當前函數,顯示其返回值(如果有的話) 

九.機器語言工具 
有一組專用的gdb變量可以用來檢查和修改計算機的通用寄存器,gdb提供了目前每一臺計算機中實際使用的4個寄存器的標準名字: 
l $pc : 程序計數器 
l $fp : 幀指針(當前堆棧幀) 
l $sp : 棧指針 
l $ps : 處理器狀態 

十.信號 
gdb通常可以捕捉到發送給它的大多數信號,通過捕捉信號,它就可決定對於正在運行的進程要做些什麼工作。例如,按CTRL-C將中斷信號發送給gdb,通常就會終止gdb。但是你或許不想中斷gdb,真正的目的是要中斷gdb正在運行的程序,因此,gdb要抓住該信號並停止它正在運行的程序,這樣就可以執行某些調試操作。 

Handle命令可控制信號的處理,他有兩個參數,一個是信號名,另一個是接受到信號時該作什麼。幾種可能的參數是: 
l nostop 接收到信號時,不要將它發送給程序,也不要停止程序。 
l stop 接受到信號時停止程序的執行,從而允許程序調試;顯示一條表示已接受到信號的消息(禁止使用消息除外) 
l print 接受到信號時顯示一條消息 
l noprint 接受到信號時不要顯示消息(而且隱含着不停止程序運行) 
l pass 將信號發送給程序,從而允許你的程序去處理它、停止運行或採取別的動作。 
l nopass 停止程序運行,但不要將信號發送給程序。 
例如,假定你截獲SIGPIPE信號,以防止正在調試的程序接受到該信號,而且只要該信號一到達,就要求該程序停止,並通知你。要完成這一任務,可利用如下命令: 
(gdb) handle SIGPIPE stop print 
請注意,UNIX的信號名總是採用大寫字母!你可以用信號編號替代信號名 
如果你的程序要執行任何信號處理操作,就需要能夠測試其信號處理程序,爲此,就需要一種能將信號發送給程序的簡便方法,這就是signal命令的任務。該 命令的參數是一個數字或者一個名字,如SIGINT。假定你的程序已將一個專用的SIGINT(鍵盤輸入,或CTRL-C;信號2)信號處理程序設置成採 取某個清理動作,要想測試該信號處理程序,你可以設置一個斷點並使用如下命令: 
(gdb) signal 2 
continuing with signal SIGINT(2) 
該程序繼續執行,但是立即傳輸該信號,而且處理程序開始運行. 

十一. 原文件的搜索 
search text:該命令可顯示在當前文件中包含text串的下一行。 
Reverse-search text:該命令可以顯示包含text 的前一行。 

十二.UNIX接口 
shell 命令可啓動UNIX外殼,CTRL-D退出外殼,返回到 gdb. 

十三.命令的歷史 
爲了允許使用歷史命令,可使用 set history expansion on 命令 
(gdb) set history expansion on 

小結:常用的gdb命令 
backtrace 顯示程序中的當前位置和表示如何到達當前位置的棧跟蹤(同義詞:where) 
breakpoint 在程序中設置一個斷點 
cd 改變當前工作目錄 
clear 刪除剛纔停止處的斷點 
commands 命中斷點時,列出將要執行的命令 
continue 從斷點開始繼續執行 
delete 刪除一個斷點或監測點;也可與其他命令一起使用 
display 程序停止時顯示變量和表達時 
down 下移棧幀,使得另一個函數成爲當前函數 
frame 選擇下一條continue命令的幀 
info 顯示與該程序有關的各種信息 
jump 在源程序中的另一點開始運行 
kill 異常終止在gdb 控制下運行的程序 
list 列出相應於正在執行的程序的原文件內容 
next 執行下一個源程序行,從而執行其整體中的一個函數 
print 顯示變量或表達式的值 
pwd 顯示當前工作目錄 
pype 顯示一個數據結構(如一個結構或C++類)的內容 
quit 退出gdb 
reverse-search 在源文件中反向搜索正規表達式 
run 執行該程序 
search 在源文件中搜索正規表達式 
set variable 給變量賦值 
signal 將一個信號發送到正在運行的進程 
step 執行下一個源程序行,必要時進入下一個函數 
undisplay display命令的反命令,不要顯示錶達式 
until 結束當前循環 
up 上移棧幀,使另一函數成爲當前函數 
watch 在程序中設置一個監測點(即數據斷點) 
whatis 顯示變量或函數類型 
**************************************************** 
 GNU的調試器稱爲gdb,該程序是一個交互式工具,工作在字符模式。在 X Window 系統中,有一個gdb的前端圖形工具,稱爲xxgdb。gdb 是功能強大的調試程序,可完成如下的調試任務: 
  * 設置斷點; 
  * 監視程序變量的值; 
  * 程序的單步執行; 
  * 修改變量的值。 
  在可以使用 gdb 調試程序之前,必須使用 -g 選項編譯源文件。可在 makefile 中如下定義 CFLAGS 變量: 
   CFLAGS = -g 
   運行 gdb 調試程序時通常使用如下的命令: 
   gdb progname 

  在 gdb 提示符處鍵入help,將列出命令的分類,主要的分類有: 
  * aliases:命令別名 
  * breakpoints:斷點定義; 
  * data:數據查看; 
  * files:指定並查看文件; 
  * internals:維護命令; 
  * running:程序執行; 
  * stack:調用棧查看; 
  * statu:狀態查看; 
  * tracepoints:跟蹤程序執行。 
  鍵入 help 後跟命令的分類名,可獲得該類命令的詳細清單。 


gdb 的常用命令 
命令 解釋 
  break NUM 在指定的行上設置斷點。 
  bt 顯示所有的調用棧幀。該命令可用來顯示函數的調用順序。 
  clear 刪除設置在特定源文件、特定行上的斷點。其用法爲clear FILENAME:NUM 
  continue 繼續執行正在調試的程序。該命令用在程序由於處理信號或斷點而 導致停止運行時。 
  display EXPR 每次程序停止後顯示錶達式的值。表達式由程序定義的變量組成。 
  file FILE 裝載指定的可執行文件進行調試。 
  help NAME 顯示指定命令的幫助信息。 
  info break 顯示當前斷點清單,包括到達斷點處的次數等。 
  info files 顯示被調試文件的詳細信息。 
  info func 顯示所有的函數名稱。 
  info local 顯示當函數中的局部變量信息。 
  info prog 顯示被調試程序的執行狀態。 
  info var 顯示所有的全局和靜態變量名稱。 
  kill 終止正被調試的程序。 
  list 顯示源代碼段。 
  make 在不退出 gdb 的情況下運行 make 工具。 
  next 在不單步執行進入其他函數的情況下,向前執行一行源代碼。 
  print EXPR 顯示錶達式 EXPR 的值。 

******gdb 使用範例************************ 
----------------- 
清單 一個有錯誤的 C 源程序 bugging.c 
代碼: 

----------------- 
1 #i nclude 

3 static char buff [256]; 
4 static char* string; 
5 int main () 
6 { 
7   printf ("Please input a string: "); 
8   gets (string);   
9   printf ("/nYour string is: %s/n", string); 
10 } 


----------------- 
  上面這個程序非常簡單,其目的是接受用戶的輸入,然後將用戶的輸入打印出來。該程序使用了一個未經過初始化的字符串地址 string,因此,編譯並運行之後,將出現 Segment Fault 錯誤: 
$ gcc -o bugging -g bugging.c 
$ ./bugging 
Please input a string: asfd 
Segmentation fault (core dumped) 
爲了查找該程序中出現的問題,我們利用 gdb,並按如下的步驟進行: 
1.運行 gdb bugging 命令,裝入 bugging 可執行文件; 
2.執行裝入的 bugging 命令 run; 
3.使用 where 命令查看程序出錯的地方; 
4.利用 list 命令查看調用 gets 函數附近的代碼; 
5.唯一能夠導致 gets 函數出錯的因素就是變量 string。用print命令查看 string 的值; 
6.在 gdb 中,我們可以直接修改變量的值,只要將 string 取一個合法的指針值就可以了,爲此,我們在第8行處設置斷點 break 8; 
7.程序重新運行到第 8行處停止,這時,我們可以用 set variable 命令修改 string 的取值; 
8.然後繼續運行,將看到正確的程序運行結果。


發佈了26 篇原創文章 · 獲贊 8 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章