linux下調試基礎知識 GDB

調試是所有程序員都會面臨的問題. 如何提高程序員的調試效率, 更好更快地定位程序中的問題從而加快程序開發的進度, 是大家共同面對的問題. 就如讀者熟知的Windwos下的一些調試工具, 如VC自帶的設置斷點, 單步跟蹤等, 都受到了廣大用戶的讚賞. 那麼, 在Liunx下有什麼好的調試工具呢?

    Gdb是一款GNU開發組織併發布的Linux下的程序調試工具. 雖然它沒有圖形化的友好界面, 但是它強大的功能也足以與微軟的VC工具相媲美.

下面舉一個例子, 演示一下Gdb的使用流程:


測試文件 test.c 的代碼如下:
#include <stdio.h>
int sum(int m);
int main()
{
  int i, n=0;
  sum(50);
  for(i=1; i<=50; i++)
  {
    n += i;
  }
  printf("The sum of 1-50 is %d \n", n);
}

int sum(int m)
{
  int i, n=0;
  for(i=1; i<=m; i++)
    n += i;
  printf("The sum of 1-m is %d\n", n);
}

編譯源代碼文件, 生成可執行文件. 
注意:一定要加上選項"-g", 這樣編譯出的可執行代碼中才包含調試信息, 否則Gdb無法載入該可執行文件.
$ gcc -g test.c -o test
雖然這段程序沒有錯誤, 但調試完全正確的程序可以更加了解Gdb的使用流程. 接下來就啓動Gdb進行調試. 注意, Gdb進行調試的是可執行文件, 而不是".c"源文件, 因此, 需要先通過Gcc編譯生成可執行文件才能用Gdb進行調試.

啓動Gdb
$gdb test
GNU gdb (GDB) 7.0-debian
Copyright (C) 2009 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".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/wangsheng/tmp/demo/gdb/test...done.

可以看出, 在Gdb的啓動畫面中指出了Gdb的版本號, 使用的庫文件等頭信息, 接下來就進入了由"(gdb)"開頭的命令行界面了.

(1) 查看源文件
在Gdb中鍵入"l"(list的縮寫)可以查看所載入的文件, 如下所示:
(gdb) l
1       #include <stdio.h>
2       int sum(int m);
3       int main()
4       {
5         int i, n=0;
6         sum(50);
7         for(i=1; i<=50; i++)
8         {
9           n += i;
10        }
(gdb) l
11        printf("The sum of 1-50 is %d \n", n);
12      }
13
14      int sum(int m)
15      {
16        int i, n=0;
17        for(i=1; i<=m; i++)
18          n += i;
19        printf("The sum of 1-m is %d\n", n);
20      }
(gdb) l
Line number 21 out of range; test.c has 20 lines.
可以看出, Gdb列出的源代碼中明確地給出了對應的行號, 這樣就可以大大地方便代碼的定位.

(2) 設置斷點
    設置斷點是調試程序中一個非常重要的手段, 它可以使程序到一定位置暫停運行. 因此,可以在該位置方便地查看變量的值, 堆棧情況等, 從而找出代碼的癥結所在.

    在Gdb中設置斷點非常簡單, 只需在"b"後加入對應的行號即可(這時最常用的方式). 如下所示:
(gdb) b 6
Breakpoint 1 at 0x4004fb: file test.c, line 6.

注意: 該斷點的作用是當程序運行到第6行時暫停(第5行執行完畢, 第6行未執行)

(3) 查看斷點情況
    在設置完斷點之後, 用戶可以鍵入"info b" 來查看設置斷點情況, 在Gdb中可以設置多個斷點.
(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000004004fb in main at test.c:6

(4) 運行代碼
    接下來就可運行代碼了, Gdb默認從首行開始運行代碼, 可鍵入"r"(run的縮寫)即可. 若想從程序中指定的行開始運行, 可在r後面加上行號.
(gdb) r
Starting program: /home/wangsheng/tmp/demo/gdb/test

Breakpoint 1, main () at test.c:6
6         sum(50);

可以看到程序運行到斷點處就停止了.

(5) 查看變量值
    在程序停止運行之後, 程序員所要做的工作是查看斷點處的相關變量值. 在Gdb中只需鍵入"p"(print的縮寫) +變量名稱 即可.
(gdb) p n
$1 = 0
(gdb) p i
$2 = 0

(6) 單步運行
    單步運行可以使用n(next的縮寫)或者s(step的縮寫), 它們之間的區別在於: 若有函數調用的時候, s會進入該函數而n不會. 因此, s就類似於VC等工具中的"step in", n就類似於VC等工具中的"step over". 

下面是使用n命令的輸出
(gdb) n
The sum of 1-m is 1275
7         for(i=1; i<=50; i++)

下面是使用s命令的輸出
(gdb) s
sum (m=50) at test.c:16
16        int i, n=0;

可以看出執行s命令時進入了sum函數內部, 而n命令則跳過函數的調用部分

(7) 恢復程序運行
    在查看變量值以及堆棧之後, 就可以使用命令c(continue)恢復程序的正常運行了. 這時, 它會把剩餘還未執行的程序執行完, 並顯示剩餘程序的執行結果. 
(gdb) c
Continuing.
The sum of 1-m is 1275
The sum of 1-50 is 1275

Program exited with co
de 031.

可以看出, 程序在運行完後退出, 之後程序處於"停止狀態".
說明: 在Gdb中, 程序的運行狀態有"運行","暫停"和"停止"3種. 其中"暫停"狀態是程序遇到了斷點或者觀察點, 程序暫時停止運行, 而此時函數的地址, 函數參數, 函數內的局部變量都會被壓入"棧(Stack)中. 故在這種狀態下可以查看函數的變量值等各種屬性. 但在函數處於"停止"狀態之後, "棧"就會自動撤銷, 它也就無法查看各種信息了.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章