1. 程式人生 > 實用技巧 >gdb除錯相關(轉載)

gdb除錯相關(轉載)

https://blog.csdn.net/niyaozuozuihao/article/details/91802994

https://blog.csdn.net/suxinpingtao51/article/details/12072559

目錄

一、gdb簡介

GDB是一個由GNU開源組織釋出的、UNIX/LINUX作業系統下的、基於命令列的、功能強大的程式除錯工具。 對於一名Linux下工作的c/c++程式設計師,gdb是必不可少的工具;

二、gdb使用流程

這裡用c程式做基本演示,c++程式也是一樣的;

1、啟動gdb

編譯一個測試程式,-g表示可以除錯,命令如下:

gcc -g test.c -o test

啟動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。

四、總結

總的來說在Linux下開發程式gdb/cgdb是必須學會使用的,他的強大之處遠不止於此,在程式的除錯中用它會提高的我們的除錯效率,當然gdb的功能與使用技巧還不止於此,多多探索,多多學習使用。

參考連結:https://blog.csdn.net/horotororensu/article/details/82256832