黄色片网站免费观看-黄色片网站观看-黄色片网站大全-黄色片视频网-色偷偷网址-色偷偷网站

gdb

功能強大的程序調(diào)試器

補充說明

gdb命令 包含在GNU的gcc開發(fā)套件中,是功能強大的程序調(diào)試器。GDB中的命令固然很多,但我們只需掌握其中十個左右的命令,就大致可以完成日常的基本的程序調(diào)試工作。

語法

gdb(選項)(參數(shù))

選項

-cd:設(shè)置工作目錄;
-q:安靜模式,不打印介紹信息和版本信息;
-d:添加文件查找路徑;
-x:從指定文件中執(zhí)行GDB指令;
-s:設(shè)置讀取的符號表文件。

命令 | 解釋 | 示例 --- | --- | --- file <文件名> | 加載被調(diào)試的可執(zhí)行程序文件。
因為一般都在被調(diào)試程序所在目錄下執(zhí)行GDB,因而文本名不需要帶路徑。 | (gdb) file gdb-sample r | Run的簡寫,運行被調(diào)試的程序。
如果此前沒有下過斷點,則執(zhí)行完整個程序;如果有斷點,則程序暫停在第一個可用斷點處。 | (gdb) r c | Continue的簡寫,繼續(xù)執(zhí)行被調(diào)試程序,直至下一個斷點或程序結(jié)束。 | (gdb) c b <行號>
b <函數(shù)名稱>
b *<函數(shù)名稱>
b <代碼地址> d [編號] | b: Breakpoint的簡寫,設(shè)置斷點。兩可以使用“行號”“函數(shù)名稱”“執(zhí)行地址”等方式指定斷點位置。
其中在函數(shù)名稱前面加“
”符號表示將斷點設(shè)置在“由編譯器生成的prolog代碼處”。如果不了解匯編,可以不予理會此用法。 d: Delete breakpoint的簡寫,刪除指定編號的某個斷點,或刪除所有斷點。斷點編號從1開始遞增。 | (gdb) b 8(gdb) b main
(gdb) b *main
(gdb) b *0x804835c (gdb) d s, n | s: 執(zhí)行一行源程序代碼,如果此行代碼中有函數(shù)調(diào)用,則進入該函數(shù);
n: 執(zhí)行一行源程序代碼,此行代碼中的函數(shù)調(diào)用也一并執(zhí)行。 s 相當(dāng)于其它調(diào)試器中的“Step Into (單步跟蹤進入)”;
n 相當(dāng)于其它調(diào)試器中的“Step Over (單步跟蹤)”。 這兩個命令必須在有源代碼調(diào)試信息的情況下才可以使用(GCC編譯時使用“-g”參數(shù))。 | (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,設(shè)置程序中斷后欲顯示的數(shù)據(jù)及其格式。
例如,如果希望每次程序中斷后可以看到即將被執(zhí)行的下一條匯編指令,可以使用命令
“display /i $pc”
其中 $pc 代表當(dāng)前匯編指令,/i 表示以十六進行顯示。當(dāng)需要關(guān)心匯編代碼時,此命令相當(dāng)有用。 undispaly,取消先前的display設(shè)置,編號從1開始遞增。 | (gdb) display /i $pc (gdb) undisplay 1 i | info的簡寫,用于顯示各類信息,詳情請查閱“help i”。 | (gdb) i r q | Quit的簡寫,退出GDB調(diào)試環(huán)境。 | (gdb) q help [命令名稱] | GDB幫助命令,提供對GDB名種命令的解釋說明。
如果指定了“命令名稱”參數(shù),則顯示該命令的詳細說明;如果沒有指定參數(shù),則分類顯示所有GDB命令,供用戶進一步瀏覽和查詢。 | (gdb) help

參數(shù)

文件:二進制可執(zhí)行程序。

實例

以下是linux下dgb調(diào)試的一個實例,先給出一個示例用的小程序,C語言代碼:

#include <stdio.h>
int nGlobalVar = 0;

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

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

        nGlobalVar += 100;
        nGlobalVar -= 12;

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

        n = tempFunction(1, 2);
    printf("n = %d", n);

    return 0;
}

請將此代碼復(fù)制出來并保存到文件 gdb-sample.c 中,然后切換到此文件所在目錄,用GCC編譯之:

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

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

下面“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內(nèi)部命令引導(dǎo)符,等待用戶輸入GDB命令。

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

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

上面最后一行提示已經(jīng)加載成功。

下面使用“r”命令執(zhí)行(Run)被調(diào)試文件,因為尚未設(shè)置任何斷點,將直接執(zhí)行到程序結(jié)束:

(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 函數(shù)開頭設(shè)置一個斷點(Breakpoint):

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

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

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

(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函數(shù)是第一個可執(zhí)行語句處。

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

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

(gdb) s
20 n++;

上面的信息表示已經(jīng)執(zhí)行完“n = 1;”,并顯示下一條要執(zhí)行的代碼為第20行的“n++;”。

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

(gdb) p n
$1 = 1

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

下面我們分別在第26行、tempFunction 函數(shù)開頭各設(shè)置一個斷點(分別使用命令“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”命令繼續(xù)(Continue)執(zhí)行被調(diào)試程序,程序?qū)⒅袛嘣诘诙?個斷點(26行),此時全局變量 nGlobalVar 的值應(yīng)該是 88;再一次執(zhí)行“c”命令,程序?qū)⒅袛嘤诘谌齻€斷點(12行,tempFunction 函數(shù)開頭處),此時tempFunction 函數(shù)的兩個參數(shù) a、b 的值應(yīng)分別是 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

上面反饋的信息一切都在我們預(yù)料之中~~

再一次執(zhí)行“c”命令(Continue),因為后面再也沒有其它斷點,程序?qū)⒁恢眻?zhí)行到結(jié)束:

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

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

這就要用到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;”對應(yīng)的匯編代碼是“movl $0x1,0xfffffffc(%ebp)”。

并且以后程序每次中斷都將顯示下一條匯編指定(“si”命令用于執(zhí)行一條匯編代碼——區(qū)別于“s”執(zhí)行一行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 *<函數(shù)名稱>”。

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

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

當(dāng)被詢問是否刪除所有斷點時,輸入“y”并按回車鍵即可。

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

(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”命令顯示寄存器中的當(dāng)前值———“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

當(dāng)然也可以顯示任意一個指定的寄存器值:

(gdb) i r eax
eax 0xbffff6a4 -1073744220

最后一個要介紹的命令是“q”,退出(Quit)GDB調(diào)試環(huán)境:

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

補充內(nèi)容

gdb 教程:慕課網(wǎng)-Linux C語言指針與內(nèi)存-第三章

如果刪除源代碼, 就無法顯示行號等輔助信息了

gcc -g gdb.c -o gdb.out # -g 支持gdb調(diào)試; -o 輸出, 默認為 a.out

gdb gdb.out # 進入 gdb 調(diào)試環(huán)境
enter # 繼續(xù)執(zhí)行上條命令
l # 列出源代碼, 默認 10 行, 按 l 繼續(xù)

start # 開始單步調(diào)試, 默認 main() 第一行
p a # 查看 a 變量的值
n # 繼續(xù)到下一行
s # 進入子函數(shù)
bt # 查看函數(shù)棧
f 1 # 切換函數(shù)棧

q 退出調(diào)試

測試用代碼

#include <stdio.h>

void change(int a, int b){
    int tmp=a;
    a=b; b=tmp;
}

void change2(int *a, int *b){
    int tmp=*a;
    *a=*b; *b=tmp;
}

int main(){
    int a=5,b=3;
    change(a,b);
    printf("change:\na=%d\nb=%d\n", a,b);
    change2(&a,&b);
    printf("change2:\na=%d\nb=%d\n", a,b);
}