linux下的c/c++偵錯程式gdb

lrj2005發表於2009-08-10

linux下的c/c+ + 偵錯程式gdb

gdb
Linux 包含了一個叫 gdb 的 GNU 除錯程式. gdb 是一個用來除錯 C 和 C+ + 程式的強力偵錯程式. 它使你能在程式執行時觀察程式的內部結構和記憶體的使用情況. 以下是 gdb 所提供的一些功能:

* 設定斷點;
* 監視程式變數的值;
* 程式的單步執行;
* 修改變數的值。
       
gdb支援下列語言C, C+ + , FORTRAN, PACAL, Java, Chill, assembly, Modula- 2. 一般來說,GDB會根據除錯的程式來確定的相應的除錯語言,比如說,副檔名為. c, GDB should it is a c programme, extern_name is . c, . cc, . cp, . cxx, . cpp, . c+ + , GDB should they are c+ + programme
    在命令列上鍵入 gdb 並按Enter鍵就可以執行 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 除錯程式之前,必須使用 - g 選項編譯原始檔。也就是說,如果你寫了下面的一個程式,名字命名為test. c+ + , 編譯時使用如下語句:
#g+ + - o test - g test . c+ +
#. / test
test . c+ + 源程式如下:
#include < iostream. h>

static char buff [ 256] ;
static char* string;
int main ( )
{

printf ( "Please input a string: " ) ;
gets ( string) ;

printf ( " Your string is: %s " , string) ;
}
執行後,程式出現了錯誤,這時你就可以使用gdb來查錯了,方法如下:
#gdb test
( gdb) run 執行test(二進位制)程式
如果你在編譯時沒有加上引數- g選項,你也可以通過如下語句來達到相同的效果
#gdb
( gdb) file test
如果你想檢視源程式的部分程式碼,你可以用list命令來實現,如:
(gdb)list

可在 makefile 中如下定義 CFLAGS 變數:
CFLAGS = - g
執行 gdb 除錯程式時通常使用如下的命令:
gdb progname

在 gdb 提示符下按回車健將重複上一個命令.

gdb命 令 描 述
file FILE 裝入想要除錯的可執行檔案.
kill 終止正在除錯的程式.
list 列出產生執行檔案的原始碼的一部分.
next 執行一行原始碼但不進入函式內部.
step 執行一行原始碼而且進入函式內部.
run 執行當前被除錯的程式
q( quit) 終止 gdb
watch expr 使你能監視一個變數的值而不管它何時被改變.
rwatch expr 當expr被程式讀出時,程式被暫停
awatch expr 當expr被程式讀出時然後再被寫入時,程式被暫停
info whatchpoints 顯示所設定的觀測點的列表 the same as info break
make 使你能不退出 gdb 就可以重新產生可執行檔案.
shell 使你能不離開 gdb 就執行 UNIX shell 命令. such as:(gdb)shell gedit

set and unset 分別用來設定和取消引數和環境變數,such as: (gdb)set i=9 (gdb)unset i

whatis 告訴你變數的型別,如(gdb)whatis i

如果你想得到結構體的定義,可用ptype command,  such as: have a structive s, (gdb)ptype s

break NUM 在指定的行上設定斷點。

b( abbreviate of break) + offset
b( abbreviate of break) - offset
以上兩個命令在當前執行到的前幾行或後幾行設定斷點

break filename: linenum
在檔名的的第linenum處設定斷點
break filename: functionname
在函式前設定斷點

info break 顯示當前斷點清單,包括到達斷點處的次數等。

disable make the breakpoint don't execute
enable make the breakpoint can exec

example:

(gdb) l
39 pro1=pro2;
40 pro2.display();
41 pro1.display();
42 return 0;
43 }
(gdb) b 39
Breakpoint 3 at 0x8048862: file debug.c++, line 39.
(gdb) b -6
Breakpoint 4 at 0x804883f: file debug.c++, line 38.
(gdb) info bre
Num Type Disp Enb Address What
3 breakpoint keep y 0x08048862 in main at debug.c++:39
4 breakpoint keep y 0x0804883f in main at debug.c++:38
(gdb) disable 4
(gdb) info bre
Num Type Disp Enb Address What
3 breakpoint keep y 0x08048862 in main at debug.c++:39
4 breakpoint keep n 0x0804883f in main at debug.c++:38
(gdb) enable 4
(gdb) info bre
Num Type Disp Enb Address What
3 breakpoint keep y 0x08048862 in main at debug.c++:39
4 breakpoint keep y 0x0804883f in main at debug.c++:38
(gdb) disable 3 4
(gdb) info bre
Num Type Disp Enb Address What
3 breakpoint keep n 0x08048862 in main at debug.c++:39
4 breakpoint keep n 0x0804883f in main at debug.c++:38

tbreak 設定的斷點,當使用一次後就不能再使用了


bt 顯示所有的呼叫棧幀。該命令可用來顯示函式的呼叫順序。
clear 刪除設定在特定原始檔、特定行上的斷點。其用法為:clear FILENAME:NUM。
delete 刪除所有設定的斷點
continue 繼續執行正在除錯的程式。該命令用在程式由於處理訊號或斷點而
導致停止執行時。
display EXPR 每次程式停止後顯示錶達式的值。表示式由程式定義的變數組成。
help NAME 顯示指定命令的幫助資訊。

info files 顯示被除錯檔案的詳細資訊。
info func 顯示所有的函式名稱。
info local 顯示當函式中的區域性變數資訊。
info prog 顯示被除錯程式的執行狀態。
info var 顯示所有的全域性和靜態變數名稱。
make 在不退出 gdb 的情況下執行 make 工具。
print EXPR 顯示錶達式 EXPR 的值。

使用where命令檢視程式出錯的地方

顯示當前路徑變數的設定情況
(gdb)show path
顯示當前環境變數的設定情況
(gdb)show envir(abbreviate of environment)

也可以用cd and pwd commands

terminate a child thread use kill command

如果想檢視命令的列表或選項,可以在命令列下輸入:
(gdb)M-?(就是ESC+?)
不過這種方式在遠端除錯下不起作用。

break [file:]function(types) (函式過載時,就需加上型別)

用於函式的命令

call, finish, return

call name(flags)  呼叫並執行名為name,引數為args的函式

finish  如果可以則中止當前函式並列印它的返回值

return value  停止執行當前函式,並將value返回給呼叫者

such as:(gdb)call max(max1,mini1)

使用return函式退出函式,你也可以使用return命令返回一個隨意的值來測試邊界條件


要指定一個或多個其他的目錄,可以用一個或多個-d <路徑名>選項啟動GDB,如

$gdb -d /source/project test


要定位一個特定字串在當前檔案中的下一次出現可以使用search<字串> 命令。使用反向查詢命令reverse-search<字串>來查詢字串上一次出現的地方


附加一個正在執行的程式將會自動將其停止以便你能使用常規的GDB命令來檢查它的狀態,such as:

(gdb)attach 1158(PID)

使用detach命令以允許該程式繼續執行,或者使用quit命令分離並退出GDB

GDB有能力在除錯程式時處理任何一種訊號,可以告訴GDB需要處理哪一種訊號。可以要求GDB收到所指定的訊號後立刻停止正大執行的程式,以便進行除錯,你可以用GDB的handle命令來完成這一功能,如下如示:
(gdb)handle <signal><keywords....>

gdb下的多執行緒除錯(摘錄)

gdb對於多執行緒程式的除錯有如下的支援:

    * 執行緒產生通知:在產生新的執行緒時, gdb會給出提示資訊

(gdb) r
Starting program: /root/thread
[New Thread 1073951360 (LWP 12900)]
[New Thread 1082342592 (LWP 12907)]---以下三個為新產生的執行緒
[New Thread 1090731072 (LWP 12908)]
[New Thread 1099119552 (LWP 12909)]

    * 檢視執行緒:使用info threads可以檢視執行的執行緒。

(gdb) info threads
  4 Thread 1099119552 (LWP 12940) 0xffffe002 in ?? ()
  3 Thread 1090731072 (LWP 12939) 0xffffe002 in ?? ()
  2 Thread 1082342592 (LWP 12938) 0xffffe002 in ?? ()
* 1 Thread 1073951360 (LWP 12931) main (argc=1, argv=0xbfffda04) at thread.c:21
(gdb)

注意,行首的藍色文字為gdb分配的執行緒號,對執行緒進行切換時,使用該該號碼,而不是上文標出的綠色數字。

另外,行首的紅色星號標識了當前活動的執行緒

    * 切換執行緒:使用 thread THREADNUMBER 進行切換,THREADNUMBER 為上文提到的執行緒號。下例顯示將活動執行緒從 1 切換至 4。

(gdb) info threads
  4 Thread 1099119552 (LWP 12940) 0xffffe002 in ?? ()
  3 Thread 1090731072 (LWP 12939) 0xffffe002 in ?? ()
  2 Thread 1082342592 (LWP 12938) 0xffffe002 in ?? ()
* 1 Thread 1073951360 (LWP 12931) main (argc=1, argv=0xbfffda04) at thread.c:21
(gdb) thread 4
[Switching to thread 4 (Thread 1099119552 (LWP 12940))]#0 0xffffe002 in ?? ()
(gdb) info threads
* 4 Thread 1099119552 (LWP 12940) 0xffffe002 in ?? ()
  3 Thread 1090731072 (LWP 12939) 0xffffe002 in ?? ()
  2 Thread 1082342592 (LWP 12938) 0xffffe002 in ?? ()
  1 Thread 1073951360 (LWP 12931) main (argc=1, argv=0xbfffda04) at thread.c:21
(gdb)

     以上即為使用gdb提供的對多執行緒進行除錯的一些基本命令。另外,gdb也提供對執行緒的斷點設定以及對指定或所有執行緒釋出命令的命令。

     初次接觸gdb下多執行緒的除錯,往往會忽視gdb中活動執行緒的概念。一般來講,在使用gdb除錯的時候,只有一個執行緒為活動執行緒,如果希望得到其他的執行緒的輸出結果,必須使用thread命令切換至指定的執行緒,才能對該執行緒進行除錯或觀察輸出結果。
     



以下這部分是轉載的
gdb 應用舉例
    本節用一個例項教你一步步的用 gdb 除錯程式. 被除錯的程式相當的簡單, 但它展示了 gdb 的典型應用.
 
    下面列出了將被除錯的程式. 這個程式被稱為 greeting , 它顯示一個簡單的問候, 再用反序將它列出.

#include <stdio.h>
main ()

{
  char my_string[] = "hello there";
  my_print (my_string);

  my_print2 (my_string);

}

void my_print (char *string)

{
  printf ("The string is %s/n", string);
}


void my_print2 (char *string)

{
  char *string2;
  int size, i;
  size = strlen (string);
  string2 = (char *) malloc (size + 1);
  for (i = 0; i < size; i++)
    string2[size - i] = string[i];
  string2[size+1] = `/0'
;
  printf ( "The string printed backward is %s/n" , string2) ;

}

    用下面的命令編譯它:
 

gcc - o test test . c

    這個程式執行時顯示如下結果:

The string is hello there

The string printed backward is

    輸出的第一行是正確的, 但第二行列印出的東西並不是我們所期望的. 我們所設想的輸出應該是:

The string printed backward is ereht olleh

    由於某些原因, my_print2 函式沒有正常工作. 讓我們用 gdb 看看問題究竟出在哪兒, 先鍵入如下命令:
 

gdb greeting

    注意: 記得在編譯 greeting 程式時把除錯選項開啟.

    如果你在輸入命令時忘了把要除錯的程式作為引數傳給 gdb , 你可以在 gdb 提示符下用 file 命令來載入它:
 

( gdb) file greeting

    這個命令將載入 greeting 可執行檔案就象你在 gdb 命令列裡裝入它一樣.

    這時你能用 gdb 的 run 命令來執行 greeting 了. 當它在 gdb 裡被執行後結果大約會象這樣:

( gdb) run

Starting program: /root/greeting

The string is hello there

The string printed backward is

Program exited with code 041

    這個輸出和在 gdb 外面執行的結果一樣. 問題是, 為什麼反序列印沒有工作? 為了找出癥結所在, 我們可以在 my_print2 函式的 for 語句後設一個斷點, 具體的做法是在 gdb 提示符下鍵入 list 命令三次, 列出原始碼:

( gdb) list

( gdb) list

( gdb) list

    技巧: 在 gdb 提示符下按回車健將重複上一個命令.

    第一次鍵入 list 命令的輸出如下:
 

1 #include < stdio. h>

2

3 main ( )

4 {

5 char my_string[ ] = "hello there" ;

6

7 my_print ( my_string) ;

8 my_print2 ( my_string) ;

9 }

10

    如果按下回車, gdb 將再執行一次 list 命令, 給出下列輸出:
 

11 my_print ( char * string)

12 {

13 printf ( "The string is %s/n" , string) ;

14 }

15

16 my_print2 ( char * string)

17 {

18 char * string2;

19 int size , i;

20

    再按一次回車將列出 greeting 程式的剩餘部分:

21 size = strlen ( string) ;

22 string2 = ( char * ) malloc ( size + 1) ;

23 for ( i = 0; i < size ; i+ + )

24 string2[ size - i] = string[ i] ;

25 string2[ size + 1] = `/0';

26 printf ("The string printed backward is %s/n", string2);

27 }

    根據列出的源程式, 你能看到要設斷點的地方在第24行, 在 gdb 命令列提示符下鍵入如下命令設定斷點:

(gdb) break 24

    gdb 將作出如下的響應:

Breakpoint 1 at 0x139: file greeting.c, line 24

(gdb)

 
    現在再鍵入 run 命令, 將產生如下的輸出:
 

Starting program: /root/greeting

The string is hello there



Breakpoint 1, my_print2 (string = 0xbfffdc4 "hello there") at greeting.c :24

24 string2[size-i]=string[i]

    你能通過設定一個觀察 string2[size - i] 變數的值的觀察點來看出錯誤是怎樣產生的, 做法是鍵入:
 

(gdb) watch string2[size - i]

    gdb 將作出如下回應:

Watchpoint 2: string2[size - i]

    現在可以用 next 命令來一步步的執行 for 迴圈了:
 

(gdb) next

    經過第一次迴圈後, gdb 告訴我們 string2[size - i] 的值是 `h`. gdb 用如下的顯示來告訴你這個資訊:
 

Watchpoint 2, string2[size - i]

Old value = 0 `/000'


New value = 104 `h'

my_print2(string = 0xbfffdc4 "hello there") at greeting.c:23

23 for (i=0; i<size; i++)

    這個值正是期望的. 後來的數次迴圈的結果都是正確的. 當 i=10 時, 表示式 string2[size - i] 的值等於 `e`, size - i 的值等於 1, 最後一個字元已經拷到新串裡了.

    如果你再把迴圈執行下去, 你會看到已經沒有值分配給 string2[0] 了, 而它是新串的第一個字元, 因為 malloc 函式在分配記憶體時把它們初始化為空(null)字元. 所以 string2 的第一個字元是空字元. 這解釋了為什麼在列印 string2 時沒有任何輸出了.

    現在找出了問題出在哪裡, 修正這個錯誤是很容易的. 你得把程式碼裡寫入 string2 的第一個字元的的偏移量改為 size - 1 而不是 size. 這是因為 string2 的大小為 12, 但起始偏移量是 0, 串內的字元從偏移量 0 到 偏移量 10, 偏移量 11 為空字元保留.

    為了使程式碼正常工作有很多種修改辦法. 一種是另設一個比串的實際大小小 1 的變數. 這是這種解決辦法的程式碼:

#include <stdio.h>

main ()

{

  char my_string[] = "hello there";



  my_print (my_string);

  my_print2 (my_string);

}



my_print (char *string)

{

  printf ("The string is %s/n", string);

}



my_print2 (char *string)

{

  char *string2;

  int size, size2, i;



  size = strlen (string);

  size2 = size -1;

  string2 = (char *) malloc (size + 1);

  for (i = 0; i < size; i++)

    string2[size2 - i] = string[i];

  string2[size] = `/0'
;

  printf ( "The string printed backward is %s/n" , string2) ;

}


 



以下是英文解釋,用man gdb就可以了
You can run gdb with no arguments or options; but the most usual way to
       start GDB is with one argument or two, specifying an executable program
       as the argument:
                                                                                
       gdb program
                                                                                
       You can also start with both an executable program and a core file
       specified:
                                                                                
       gdb program core
                                                                                
       You can, instead, specify a process ID as a second argument, if you
       want to debug a running process:
                                                                                
       gdb program 1234
                                                                                
       would attach GDB to process 1234 ( unless you also have a file named
       `1234'; GDB does check for a core file first).
                                                                                
       Here are some of the most frequently needed GDB commands:
                                                                                
       break [file:]function(types) (函式過載時,就需加上型別)

You can, instead, specify a process ID as a second argument, if you
       want to debug a running process:
                                                                                
       gdb program 1234
                                                                                
       would attach GDB to process 1234 (unless you also have a file named
       `1234'
; GDB does check for a core file first) .
                                                                                
       Here are some of the most frequently needed GDB commands:
                                                                                
       break [ file: ] function

You can, instead, specify a process ID as a second argument, if you
       want to debug a running process:
                                                                                
       gdb program 1234
                                                                                
       would attach GDB to process 1234 ( unless you also have a file named
       `1234'; GDB does check for a core file first).
                                                                                
       Here are some of the most frequently needed GDB commands:
                                                                                
       break [file:]function

You can, instead, specify a process ID as a  second  argument,  if  you
       want to debug a running process:
                                                                                
       gdb program 1234
                                                                                
       would  attach  GDB  to  process 1234 (unless you also have a file named
       `1234'; GDB does check for a core file first).
                                                                                
       Here are some of the most frequently needed GDB commands:
                                                                                
       break [file:]function
               Set a breakpoint at function (in file).
 
       run [arglist]
              Start your program (with arglist, if specified).
 
       bt     Backtrace: display the program stack.
 
       print expr
               Display the value of an expression.
 
       c      Continue running your program (after stopping, e.g. at a  break-
              point).
              run [arglist]
              Start your program (with arglist, if specified).
 
       bt     Backtrace: display the program stack.
 
       print expr
               Display the value of an expression.
 
       c      Continue running your program (after stopping, e.g. at a  break-
              point).
                                                                                
       next   Execute  next program line (after stopping); step over any func-
              tion calls in the line.
 
       edit [file:]function
              look at the program line where it is presently stopped.
 
       list [file:]function
              type the text of the program in the  vicinity  of  where  it  is
              presently stopped.
 
       step   Execute  next program line (after stopping); step into any func-
       next   Execute  next program line (after stopping); step over any func-
              tion calls in the line.
 
       edit [file:]function
              look at the program line where it is presently stopped.
 
       list [file:]function
              type the text of the program in the  vicinity  of  where  it  is
              presently stopped.
 
       step   Execute  next program line (after stopping); step into any func-
              tion calls in the line.
 
       help [name]
              Show information about GDB command name, or general  information
              about using GDB.
 
       quit   Exit from GDB.
 
       For full details on GDB, see Using GDB: A Guide to the GNU Source-Level
       Debugger, by Richard M. Stallman and Roland H. Pesch.  The same text is
       available online as the gdb entry in the info program.

相關文章