Linux下C++的編程——GDB進行程序調試

GDB簡介

我們在Linux下C++的編程——開偏介紹一文中已經簡單介紹了GDB的功能,是類Unix系統的主要調試工具,可進行斷點調試,跟蹤程序,動態改變執行環境等功能。

從一個程序開始調試

下面我們就從一個程序開始講解一下GDB的簡單用法。假設我們有如下的程序:
GDBTest1.cpp

#include <iostream>

int Accumulation(int n)
{
        int result = 0;
        for(int i = 0; i < n; i ++) 
        {
                result += i;
        }
        return result;
}

int main()
{
        int value = 0;
        int v1 = 0, v2 = 0;
        std::cout << "Please inupt two number" << std::endl;
        std::cin >> v1 >> v2; 
        std::cout << "the sum of " << v1 << " and " << v2 << "is" << value << std::endl;
        std::cout << "the sum bettween 1 to 5 is " << Accumulation(5) << std::endl;
        return 0;
}

對它進行編譯並執行:
[luowf@luoweifu GDBTest1]vimGDBTest1.cpp[luowf@luoweifuGDBTest1] g++ -o GDBTest1 GDBTest1.cpp
[luowf@luoweifu GDBTest1]lsGDBTest1GDBTest1.cpp[luowf@luoweifuGDBTest1] ./GDBTest1
Please inupt two number
4 5
the sum of 4 and 5 is: 0
the sum bettween 1 to 5 is: 10
[luowf@luoweifu GDBTest1]$

可見這並不是我們想要的結果。我們這個程序中Accumulation(int n)的功能是想求1到n之間所有數的和,而main函數是要求輸入兩個數並求這兩個數的和,上面的例子中就也就是希望得到4+5 = 9,1到5所有整數的和爲15。

接下來我們就要對這個程序進行調試,怎麼調試呢?就要用到GDB。

[luowf@luoweifu GDBTest1]$ gdb GDBTest1
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-83.el6)
...
Reading symbols from /home/luowf/workspace/Cplusplus/GDBTest1/GDBTest1...(no debugging symbols found)...done.
(gdb) l----------------------------->查看源碼
No symbol table is loaded.  Use the "file" command.
(gdb) 

正常情況下,我們在上面輸入l(list)是希望查看源代碼的,但上面並沒有顯示源碼。這是因爲我們編譯時沒有保存調試信息。我們可以通過參數-g把調試信息加到可執行文件中。

Ok,我們重新編譯並調試。如下:

[luowf@luoweifu GDBTest1]$ g++ -g -o GDBTest1 GDBTest1.cpp 
[luowf@luoweifu GDBTest1]$ gdb GDBTest1

Reading symbols from /home/luowf/workspace/Cplusplus/GDBTest1/GDBTest1...done.
(gdb) l--------------------------------------->查看源代碼
6       for(int i = 0; i < n; i ++)
7       {
8           result += i;
9       }
10      return result;
11  }
12  
13  int main()
14  {
15      int value = 0;
(gdb) l 0------------------------------------>查看第0行的源代碼
1   #include <iostream>
2   
3   int Accumulation(int n)
4   {
5       int result = 0;
6       for(int i = 0; i < n; i ++)
7       {
8           result += i;
9       }
10      return result;
(gdb) b 8------------------------------------->在第8行加判斷
Breakpoint 1 at 0x804871a: file GDBTest1.cpp, line 8.
(gdb) l--------------------------------------->查看源代碼
11  }
12  
13  int main()
14  {
15      int value = 0;
16      int v1 = 0, v2 = 0;
17      std::cout << "Please inupt two number" << std::endl;
18      std::cin >> v1 >> v2;
19      std::cout << "the sum of " << v1 << " and " << v2 << " is: " << value << std::endl;
20      std::cout << "the sum bettween 1 to 5 is: " << Accumulation(5) << std::endl;
(gdb) b 10------------------------------------->在第10行加判斷
Breakpoint 2 at 0x8048731: file GDBTest1.cpp, line 10.
(gdb) r---------------------------------------->開始執行程序
Starting program: /home/luowf/workspace/Cplusplus/GDBTest1/GDBTest1 
Please inupt two number
4 5
the sum of 4 and 5 is: 0

Breakpoint 1, Accumulation (n=5) at GDBTest1.cpp:8
8           result += i;
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.166.el6_7.1.i686 libgcc-4.4.7-16.el6.i686 libstdc++-4.4.7-16.el6.i686
(gdb) p result--------------------------------->打印result變量的值(print)
$1 = 0
(gdb) c---------------------------------------->執行到下一次斷點(continue)
Continuing.

Breakpoint 1, Accumulation (n=5) at GDBTest1.cpp:8
8           result += i;
(gdb) c---------------------------------------->執行到下一次斷點(continue)
Continuing.

Breakpoint 1, Accumulation (n=5) at GDBTest1.cpp:8
8           result += i;
(gdb) p result
$2 = 1
(gdb) c
Continuing.

Breakpoint 1, Accumulation (n=5) at GDBTest1.cpp:8
8           result += i;
(gdb) c
Continuing.

Breakpoint 1, Accumulation (n=5) at GDBTest1.cpp:8
8           result += i;
(gdb) p result
$3 = 6
(gdb) p i-------------------------------------->打印i變量的值
$4 = 4
(gdb) n---------------------------------------->執行一行代碼(next)
6       for(int i = 0; i < n; i ++)
(gdb) n---------------------------------------->執行一行代碼(next)

Breakpoint 2, Accumulation (n=5) at GDBTest1.cpp:10
10      return result;

從上面我們可以看到當執行到i=4時不再執行循環內的代碼,再查看一下我們的代碼會發現是我們的循環條件寫錯,應該是i <= n。

OK,我們用vim修改程序

#include <iostream>

int Accumulation(int n)
{
        int result = 0;
        for(int i = 0; i <= n; i ++) 
        {
                result += i;
        }
        return result;
}

int main()
{
        int value = 0;
        int v1 = 0, v2 = 0;
        std::cout << "Please inupt two number" << std::endl;
        std::cin >> v1 >> v2; 
        value = v1 + v2; 
        std::cout << "the sum of " << v1 << " and " << v2 << " is: " << value << std::endl;
        std::cout << "the sum bettween 1 to 5 is: " << Accumulation(5) << std::endl;
        return 0;
}

再次執行

[luowf@luoweifu GDBTest1]$ g++ -g -o GDBTest1 GDBTest1.cpp 
[luowf@luoweifu GDBTest1]$ ls
GDBTest1  GDBTest1.cpp
[luowf@luoweifu GDBTest1]$ ./GDBTest1 
Please inupt two number
4 5
the sum of 4 and 5 is: 9
the sum bettween 1 to 5 is: 15

Ok,這已經是我們需要的結果了。

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

以上表格來自: http://man.linuxde.net/gdb



上一篇文章:
Linux下C++的編程——開發環境搭建與第一個程序

下一篇要講述的內容:
Linux下C++的編程——Makefile的簡單用法

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