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]
[luowf@luoweifu 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 |
(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的簡單用法