1. 程式人生 > >Linux程式設計——gdb除錯

Linux程式設計——gdb除錯

    上一篇文章中,我們學習了gcc編譯器的使用。本文,我們就講解 gdb 偵錯程式(Debug)的使用,它可以幫助我們找出程式之中的錯誤和漏洞等等。

    當程式編譯完成後,它可能無法正常執行;或許程式會徹底崩潰;或許只是不能正常地執行某些功能;或許它的輸出會被掛起;或許不會提示要求正常的輸入。無論在何種情況下,跟蹤這些問題,特別是在大的工程中,將是開發中最困難的部分,我們將學習gdb(GNU debugger)除錯程式的方法,該程式是一個偵錯程式,是用來幫助程式設計師尋找程式中的錯誤的軟體。

    gdb是GNU開發組織釋出的一個強大的UNIX/Linux下的程式除錯工具。或許,有人比較習慣圖形介面方式的,像VC、BCB等IDE環境,但是在UNIX/Linux平臺下做軟體,gdb這個除錯工具有比VC、BCB的圖形化偵錯程式更強大的功能。所謂“寸有所長,尺有所短”就是這個道理。 一般來說,gdb主要幫忙使用者完成下面4個方面的功能

  1.     啟動程式,可以按照使用者自定義的要求隨心所欲的執行程式。
  2.     可讓被除錯的程式在使用者所指定的除錯的斷點處停住 (斷點可以是條件表示式)。
  3.     當程式停住時,可以檢查此時程式中所發生的事。
  4.     動態地改變程式的執行環境。
  5.     從上面來看,gdb和一般的除錯工具區別不大,基本上也是完成這些功能,不過在細節上,會發現gdb這個除錯工具的強大。大家可能習慣了圖形化的除錯工具,但有時候,命令列的除錯工具卻有著圖形化工具所不能完成的功能。

   

    gdb.c 

#include <stdio.h>
int func(int n)
{
    int sum=0,i;
    for(i=0; i<n; i++) {
        sum+=i;
    }
    return sum;
}

int main(void)
{
    int i;
    long result = 0;
    for(i=1; i<=100; i++) {
        result += i;
    }
    printf("result[1-100] = %ld \n", result );
    printf("result[1-250] = %d \n", func(250) );
 }

    編譯生成執行檔案(Linux下):  

$ gcc –g gdb.c -o testgdb
使用gdb除錯:
$ gdb testgdb <---------- 啟動gdb
.......此處省略一萬行

鍵入 l命令相當於list命令,從第一行開始列出原始碼:
$ gdb testgdb
.......此處省略一萬行

(gdb) l
7       {
8           sum+=i;
9       }
10      return sum;
11 }
12
13 int main(void)
14 {
15      int i;
16      long result = 0;
(gdb)
17      for(i=1; i<=100; i++)
18      {
19          result += i;
20      }
21      printf("result[1-100] = %ld \n", result );
22      printf("result[1-250] = %d \n", func(250) );
23 }
(gdb) break 16 <-------------------- 設定斷點,在源程式第16行處。
Breakpoint 1 at 0x804836a: file test.c, line 16.
(gdb) break func <-------------------- 設定斷點,在函式func()入口處。
Breakpoint 2 at 0x804832e: file test.c, line 5.
(gdb) info break <-------------------- 檢視斷點資訊。
Num Type           Disp Enb Address    What
1   breakpoint     keep y   0x0804836a in main at test.c:16
2   breakpoint     keep y   0x0804832e in func at test.c:5
(gdb) r <--------------------- 執行程式,run命令簡寫
Starting program: /home/shiyanlou/testgdb

Breakpoint 1, main () at test.c:16 <---------- 在斷點處停住。
16                   long result = 0;
(gdb) n <--------------------- 單條語句執行,next命令簡寫。
17                   for(i=1; i<=100; i++)
(gdb) n
19                           result += i;
(gdb) n
17                   for(i=1; i<=100; i++)
(gdb) n
19                           result += i;
(gdb) n
17                   for(i=1; i<=100; i++)
(gdb) c     <--------------------- 繼續執行程式,continue命令簡寫。
Continuing.
result[1-100] = 5050  <----------程式輸出。

Breakpoint 2, func (n=250) at test.c:5
5                   int sum=0,i;
(gdb) n
6                    for(i=0; i<n; i++)
(gdb) p I    <--------------------- 列印變數i的值,print命令簡寫。
$1 = 1107620064
(gdb) n
8                           sum+=i;
(gdb) n
6                    for(i=0; i<n; i++)
(gdb) p sum
$2 = 0
(gdb) bt     <--------------------- 檢視函式堆疊。
#0 func (n=250) at test.c:6
#1 0x080483b2 in main () at test.c:22
#2 0x42015574 in __libc_start_main () from /lib/tls/libc.so.6
(gdb) finish <--------------------- 退出函式。
Run till exit from #0 func (n=250) at test.c:6
0x080483b2 in main () at test.c:22
22   printf("result[1-250] = %d /n", func(250) );
Value returned is $3 = 31125
(gdb) c <--------------------- 繼續執行。
Continuing.
result[1-250] = 31125

Program exited with code 027. <--------程式退出,除錯結束。
(gdb) q     <--------------------- 退出gdb。

    有了以上的感性認識,下面來系統地學習一下gdb。

   

    gdb主要除錯的是C/C++的程式。要除錯C/C++的程式,首先在編譯時,必須要把除錯資訊加到可執行檔案中。使用編譯器(cc/gcc/g++)的 -g 引數即可。如:

$ gcc -g hello.c -o hello
$ g++ -g hello.cpp -o hello

    如果沒有-g,將看不見程式的函式名和變數名,代替它們的全是執行時的記憶體地址。當用-g把除錯資訊加入,併成功編譯目的碼以後,看看如何用gdb來除錯。 啟動gdb的方法有以下幾種:

  1.     gdb <program> program也就是執行檔案,一般在當前目錄下。
  2.     gdb <program> core 用gdb同時除錯一個執行程式和core檔案,core是程式非法執行後,core dump後產生的檔案。
  3.     gdb <program> <PID> 如果程式是一個服務程式,那麼可以指定這個服務程式執行時的程序ID。gdb會自動attach上去,並除錯它。program應該在PATH環境變數中搜索得到。 gdb啟動時,可以加上一些gdb的啟動開關,詳細的開關可以用gdb -help檢視。下面只列舉一些比較常用的引數: -symbols <file> -s <file> 從指定檔案中讀取符號表。 -se file 從指定檔案中讀取符號表資訊,並把它用在可執行檔案中。 -core <file> -c <file> 除錯時core dump的core檔案。 -directory <directory> -d <directory> 加入一個原始檔的搜尋路徑。預設搜尋路徑是環境變數中PATH所定義的路徑。