GDB是一個由GNU開源組織發布的、UNIX/LINUX操作系統下的、基於命令行的、功能強大的程序調試工具。 對於一名Linux下工作的c/c++程序員,gdb是必不可少的工具;
二、gdb使用流程
這里用c程序做基本演示,c++程序也是一樣的;
1、啟動gdb
編譯一個測試程序,-g表示可以調試,命令如下:
gcc -g test.c -o test
1
啟動gdb,命令如下:
gdb test
gdb -q test //表示不打印gdb版本信息,界面較為干凈;
測試如下:
root@ubuntu:/home/eit/c_test# gdb test
GNU gdb (Ubuntu 7.7-0ubuntu3) 7.7
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from test...done.
(gdb) q
root@ubuntu:/home/eit/c_test# gdb -q test
Reading symbols from test...done.
(gdb)
到此gdb啟動完成!
2、查看源碼
list(簡寫 l): 查看源程序代碼,默認顯示10行,按回車鍵繼續看余下的。
測試如下:
(gdb) list
9 #define MAX_SIZE
10
11 int main()
12 {
13 int i,fd,size1 ,size2 ,len;
14 char *buf = "helo!I'm liujiangyong ";
15 char buf_r[15];
16 len = strlen(buf);
17 fd = open("/home/hello.txt",O_CREAT | O_TRUNC | O_RDWR,0666);
18 if (fd<0)
(gdb)
19 {
20 perror("open :");
21 exit(1);
22 }
23 else
24 {
25 printf("open file:hello.txt %d\n",fd);
26 }
27 size1 = write(fd,buf,len);
28 if (fd<0)
(gdb)
29 {
30 printf("writre erro;");
31
32 }
33 else
34 {
35 printf("寫入的長度:%d\n寫入文本內容:%s\n",size1,buf);
36
37 }
38 lseek(fd,0,SEEK_SET);
(gdb)
39 size2 = read(fd,buf_r,12);
40 if (size2 <0)
41 {
42 printf("read erro\n");
43 }
44 else
45 {
46 printf("讀取長度:%d\n 文本內容是:%s\n",size2,buf_r);
47 }
48 close(fd);
(gdb)
49
50
51 }
(gdb)
Line number 52 out of range; write.c has 51 lines.
(gdb)
3、運行程序
run(簡寫 r) :運行程序直到遇到 結束或者遇到斷點等待下一個命令;
測試如下:
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/eit/c_test/test
open file:hello.txt 3
寫入的長度:22
寫入文本內容:helo!I'm liujiangyong
讀取長度:12
文本內容是:helo!I'm liu
[Inferior 1 (process 19987) exited normally]
(gdb)
4、設置斷點
break(簡寫 b) :格式 b 行號,在某行設置斷點;
info breakpoints :顯示斷點信息
Num: 斷點編號
Disp:斷點執行一次之后是否有效 kep:有效 dis:無效
Enb: 當前斷點是否有效 y:有效 n:無效
Address:內存地址
What:位置
(gdb) b 5
Breakpoint 3 at 0x400836: file write.c, line 5.
(gdb) b 26
Breakpoint 4 at 0x4008a6: file write.c, line 26.
(gdb) b 30
Breakpoint 5 at 0x4008c6: file write.c, line 30.
(gdb) info breakpoints
Num Type Disp Enb Address What
3 breakpoint keep y 0x0000000000400836 in main at write.c:5
4 breakpoint keep y 0x00000000004008a6 in main at write.c:26
5 breakpoint keep y 0x00000000004008c6 in main at write.c:30
(gdb)
5、單步執行
使用 continue、step、next命令
測試如下:
(gdb) r
Starting program: /home/eit/c_test/test
Breakpoint 3, main () at write.c:12
12 {
(gdb) n
14 char *buf = "helo!I'm liujiangyong ";
(gdb)
16 len = strlen(buf);
(gdb)
17 fd = open("/home/hello.txt",O_CREAT | O_TRUNC | O_RDWR,0666);
(gdb) s
open64 () at ../sysdeps/unix/syscall-template.S:81
81 ../sysdeps/unix/syscall-template.S: No such file or directory.
(gdb)
main () at write.c:18
18 if (fd<0)
(gdb)
25 printf("open file:hello.txt %d\n",fd);
(gdb)
__printf (format=0x400a26 "open file:hello.txt %d\n") at printf.c:28
28 printf.c: No such file or directory.
(gdb) c
Continuing.
open file:hello.txt 3
Breakpoint 4, main () at write.c:27
27 size1 = write(fd,buf,len);
(gdb)
Continuing.
寫入的長度:22
寫入文本內容:helo!I'm liujiangyong
讀取長度:12
文本內容是:helo!I'm liu
[Inferior 1 (process 20737) exited normally]
(gdb)
6、查看變量
使用print、whatis命令
測試如下:
main () at write.c:28
28 if (fd<0)
(gdb)
35 printf("寫入的長度:%d\n寫入文本內容:%s\n",size1,buf);
(gdb) print fd
$10 = 3
(gdb) whatis fd
type = int
(gdb)
7、退出gdb
用quit命令退出gdb:
(gdb) r
Starting program: /home/eit/c_test/test
open file:hello.txt 3
寫入的長度:22
寫入文本內容:helo!I'm liujiangyong
讀取長度:12
文本內容是:helo!I'm liu
[Inferior 1 (process 20815) exited normally]
(gdb) q
root@ubuntu:/home/eit/c_test#
continue(簡寫 c): 繼續執行程序,直到下一個斷點或者結束;
next(簡寫 n ):單步執行程序,但是遇到函數時會直接跳過函數,不進入函數;
step(簡寫 s) :單步執行程序,但是遇到函數會進入函數;
until:當你厭倦了在一個循環體內單步跟蹤時,這個命令可以運行程序直到退出循環體;
until+行號: 運行至某行,不僅僅用來跳出循環;
finish: 運行程序,直到當前函數完成返回,並打印函數返回時的堆棧地址和返回值及參數值等信息;
call 函數(參數):調用程序中可見的函數,並傳遞“參數”,如:call gdb_test(55);
quit:簡記為 q ,退出gdb;
三、gdb基本使用命令
1、運行命令
run:簡記為 r ,其作用是運行程序,當遇到斷點后,程序會在斷點處停止運行,等待用戶輸入下一步的命令。
continue (簡寫c ):繼續執行,到下一個斷點處(或運行結束)
next:(簡寫 n),單步跟蹤程序,當遇到函數調用時,也不進入此函數體;此命令同 step 的主要區別是,step 遇到用戶自定義的函數,將步進到函數中去運行,而 next 則直接調用函數,不會進入到函數體內。
step (簡寫s):單步調試如果有函數調用,則進入函數;與命令n不同,n是不進入調用的函數的
until:當你厭倦了在一個循環體內單步跟蹤時,這個命令可以運行程序直到退出循環體。
until+行號: 運行至某行,不僅僅用來跳出循環
finish: 運行程序,直到當前函數完成返回,並打印函數返回時的堆棧地址和返回值及參數值等信息。
call 函數(參數):調用程序中可見的函數,並傳遞“參數”,如:call gdb_test(55)
quit:簡記為 q ,退出gdb
2、設置斷點
break n (簡寫b n):在第n行處設置斷點
(可以帶上代碼路徑和代碼名稱: b OAGUPDATE.cpp:578)
b fn1 if a>b:條件斷點設置
break func(break縮寫為b):在函數func()的入口處設置斷點,如:break cb_button
delete 斷點號n:刪除第n個斷點
disable 斷點號n:暫停第n個斷點
enable 斷點號n:開啟第n個斷點
clear 行號n:清除第n行的斷點
info b (info breakpoints) :顯示當前程序的斷點設置情況
delete breakpoints:清除所有斷點:
3、查看源碼
list :簡記為 l ,其作用就是列出程序的源代碼,默認每次顯示10行。
list 行號:將顯示當前文件以“行號”為中心的前后10行代碼,如:list 12
list 函數名:將顯示“函數名”所在函數的源代碼,如:list main
list :不帶參數,將接着上一次 list 命令的,輸出下邊的內容。
4、打印表達式
print 表達式:簡記為 p ,其中“表達式”可以是任何當前正在被測試程序的有效表達式,比如當前正在調試C語言的程序,那么“表達式”可以是任何C語言的有效表達式,包括數字,變量甚至是函數調用。
print a:將顯示整數 a 的值
print ++a:將把 a 中的值加1,並顯示出來
print name:將顯示字符串 name 的值
print gdb_test(22):將以整數22作為參數調用 gdb_test() 函數
print gdb_test(a):將以變量 a 作為參數調用 gdb_test() 函數
display 表達式:在單步運行時將非常有用,使用display命令設置一個表達式后,它將在每次單步進行指令后,緊接着輸出被設置的表達式及值。如: display a
watch 表達式:設置一個監視點,一旦被監視的“表達式”的值改變,gdb將強行終止正在被調試的程序。如: watch a
whatis :查詢變量或函數
info function: 查詢函數
擴展info locals: 顯示當前堆棧頁的所有變量
5、查看運行信息
where/bt :當前運行的堆棧列表;
bt backtrace 顯示當前調用堆棧
up/down 改變堆棧顯示的深度
set args 參數:指定運行時的參數
show args:查看設置好的參數
info program: 來查看程序的是否在運行,進程號,被暫停的原因。
6、分割窗口
layout:用於分割窗口,可以一邊查看代碼,一邊測試:
layout src:顯示源代碼窗口
layout asm:顯示反匯編窗口
layout regs:顯示源代碼/反匯編和CPU寄存器窗口
layout split:顯示源代碼和反匯編窗口
Ctrl + L:刷新窗口
7、cgdb強大工具
cgdb主要功能是在調試時進行代碼的同步顯示,這無疑增加了調試的方便性,提高了調試效率。界面類似vi,符合unix/linux下開發人員習慣;如果熟悉gdb和vi,幾乎可以立即使用cgdb。
windows下配置 GNU的gdb調試功能
1、配置
修改環境變量(前提電腦中存在gdb.exe) 1. 我的電腦->屬性->環境......在path那一項后面添加你DEV-C++ Bin目錄的路徑(gdb.exe所在目錄),如: E:\Program Files\DEV-CPP\Bin (你自己的路徑) 2. CMD命令行,輸入: set path=%path%;E:\Program Files\DEV-CPP\Bin 這樣之后,命令行就可以直接調用gdb命令了
2、使用gdb調試程序
GDB概述 ————
GDB是GNU開源組織發布的一個強大的UNIX下的程序調試工具。或許,各位比較喜歡那種圖形界面方式的,像VC、BCB等IDE的調試,但如果你是在UNIX平台下做軟件,你會發現GDB這個調試工具有比VC、BCB的圖形化調試器更強大的功能。所謂“寸有所長,尺有所短”就是這個道理。
一般來說,GDB主要幫忙你完成下面四個方面的功能:
1、啟動你的程序,可以按照你的自定義的要求隨心所欲的運行程序。 2、可讓被調試的程序在你所指定的調置的斷點處停住。(斷點可以是條件表達式) 3、當程序被停住時,可以檢查此時你的程序中所發生的事。 4、動態的改變你程序的執行環境。
從上面看來,GDB和一般的調試工具沒有什么兩樣,基本上也是完成這些功能,不過在細節上,你會發現GDB這個調試工具的強大,大家可能比較習慣了圖形化的調試工具,但有時候,命令行的調試工具卻有着圖形化工具所不能完成的功能。讓我們一一看來。
為調試編譯代碼(Compiling Code for Debugging)
為了使 gdb 正常工作, 你必須使你的程序在編譯時包含調試信息. 調試信息包含你程序里的每個變量的類型和在可執行文件里的地址映射以及源代碼的行號. gdb 利用這些信息使源代碼和機器碼相關聯.
在編譯時用 -g 選項打開調試選項.
gdb 基本命令
gdb 支持很多的命令使你能實現不同的功能. 這些命令從簡單的文件裝入到允許你檢查所調用的堆棧內容的復雜命令, 表27.1列出了你在用 gdb 調試時會用到的一些命令. 想了解 gdb 的詳細使用請參考 gdb 的指南頁.
表 27.1. 基本 gdb 命令.
cd | 改變工作目錄 |
pwd | 顯示當前工作目錄 |
Tbreak | 設置臨時斷點。它的語法與break相同。區別在於用tbreak設置的斷點執行一次之后立即消失 |
awatch | 設置讀寫監視點。當要監視的表達式被讀或寫時將應用程序掛起。它的語法與watch命令相同 |
rwatch | 設置讀監視點,當監視表達式被讀時將程序掛起,等侍調試。此命令的語法與watch相同 |
display:在應用程序每次停止運行時顯示表達式的值。 info break:顯示當前斷點列表,包括每個斷點到達的次數。 info files:顯示調試文件的信息。 info func:顯示所有的函數名。 info local:顯示當前函數的所有局部變量的信息。
info prog: 顯示調試程序的執行狀態。 print: 顯示表達式的值。 delete命令: 刪除斷點。指定一個斷點號碼,則刪除指定斷點。
一個調試示例 ——————
1 新建一個源文件vi swap.cc
源文件內容如下:
#include<iostream>
using namespace std;
void swap(int &a,int &b)
{
int tmp;
tmp=a;
a=b;
b=tmp;
}
int main()
{
int i,j;
cout<<endl<<"Input two int number:"<<endl;
cin>>i>>j;
cout<<"Before swap(),i="<<i<<" j="<<j<<endl;
swap(i,j);
cout<<"After swap(),i="<<i<<" j="<<j<<endl<<endl;
return 0;
}
直接復制粘貼生成源文件
2.生成可執行文件 g++ -g -o swap swap.cc,注意必須使用-g參數,編譯會加入調試信息,否則無法調試執行文件
3.啟動調試 gdb swap
3.1 查看源文件 list 1,回車重復上一次指令
3.2設置調試斷點 break 16,在第16行設置斷點,info break查看斷點信息(亦可使用縮寫i b )
3.3 調試 運行 輸入run 或者r
3.3 單步調試,step 或者 s進入函數內部
3.4查看變量 print b 或者 p b
3.5查看函數堆棧bt,退出函數finish
3.6 繼續運行直到下一個斷點或主函數結束continue或者c
3.7 退出調試 輸入q