gdb 基本知識

一 單步執行和跟蹤函數調用函數

先給出一段代碼,能夠用下面介紹的例子。
#include <stdio.h>
int add_range(int low, int high)
{
    int i, sum;
    for (i = low; i <= high; i++)
    sum = sum + i;
    return sum;
}
 
int main(void)
{
    int result[100];
    result[0] = add_range(1, 10);
    result[1] = add_range(1, 100);
    printf("result[0]=%d\nresult[1]=%d\n", result[0],
    result[1]);
    return 0;
}

 

1.  在編譯時要加上-g選項,生成的可執行文件才能用gdb進行源碼級調試。
    $ gcc -g main.c -o main
    $ gdb main
 
    固然在加 -tui 在格式上會比較直觀好看一些
    $ gcc -g main.c -o main
    $ gdb -tui main
 
  gdb加-g編譯時並非把整個源文件嵌入到可執行文件中,因此在調試時必須保證gdb能找到源文件。
2. 幫助命令
    (gdb) help
    
    進一步查看某一類別中有哪些命令,例如查看files類別下有哪些命令可用:
    (gdb) help files
    
3.  list命令
    (gdb) list
   
     一次只列10行。
     gdb的不少經常使用命令有簡寫形式,例如list命令能夠寫成l,要列一個函數的源代碼也能夠用函數名作參數:
    (gdb) l add_range
    
4. 退出gdb的環境
    (gdb) quit 或 q
 
5. start命令開始執行程序
    (gdb) start    
    Breakpoint 1 at 0x80483ad: file main.c, line 14.
    Starting program: /home/akaedu/main 
    main () at main.c:14
    14 result[0] = add_range(1, 10);
    (gdb)
 
6. next命令(簡寫爲n)控制這些語句一條一條地執行。
    (gdb) n
    15 result[1] = add_range(1, 100);
    (gdb) (直接回車)    
    16 printf("result[0]=%d\nresult[1]=%d\n", result[0], 
    result[1]);
    (gdb) (直接回車)
    result[0]=55
    result[1]=5105
    17 return 0;
 
7. 用step命令(簡寫爲s) 進入某一個模塊。鑽進add_range函數中去跟蹤執行
    (gdb) s    
    add_range (low=1, high=10) at main.c:6
    6 for (i = low; i <= high; i++)
 
8. backtrace命令(簡寫爲bt)能夠查看函數調用的棧幀
    (gdb) bt    
    #0 add_range (low=1, high=10) at main.c:6
    #1 0x080483c1 in main () at main.c:14
 
9. info命令(簡寫爲i)查看add_range函數局部變量的值:
    (gdb) i locals
    i = 0
    sum = 0
    
10. frame命令(簡寫爲f)選擇1號棧幀而後再查看局部變量:
    (gdb) f 1
    #1 0x080483c1 in main () at main.c:14
    14 result[0] = add_range(1, 10);
    (gdb) i locals 
    result = {0, 0, 0, 0, 0, 0, 134513196, 225011984, -1208685768, -1081160480, 
    ...
    -1208623680}
 
11. 用print命令(簡寫爲p)打印出變量sum的值:
    gdb) (直接回車)
    6 for (i = low; i <= high; i++)
    (gdb) p sum
    $1 = 3
 
12. finish命令讓程序一直運行到從當前函數返回爲止:
    (gdb) finish
    Run till exit from #0 add_range (low=1, high=10) at main.c:6
    0x080483c1 in main () at main.c:14
    14 result[0] = add_range(1, 10);
    Value returned is $2 = 55
 
 
二  斷點
實際運用中用的比較最多,可能就是斷點了。在程序某一個地方設置一個斷點,當程序運行到這人一行時,就會在此中止,此時你能夠查看一些變量的狀況 。
例子源碼:
#include <stdio.h>
int main(void)
{
    int sum = 0, i = 0;
    char input[5];
    while (1)
    {
        scanf("%s", input);
        for (i = 0; input[i] != '\0'; i++)
            sum = sum*10 + input[i] - '0';
       printf("input=%d\n", sum);
    }
    return 0;
}
1. display命令使得每次停下來的時候都顯示當前sum的值,而後繼續往下走。
2. undisplay命令能夠取消跟蹤顯示,變量sum的編號是1,能夠用undisplay 1命令取消它的跟蹤顯示
    (gdb) display sum
    1: sum = -1208103488
    (gdb) n
    9 scanf("%s", input);
    1: sum = 0
    (gdb) 
    123
    10 for (i = 0; input[i] != '\0'; i++)
    1: sum = 0
 
2. break命令的參數也能夠是函數名,表示在某個函數開頭設斷點。如今用continue命令(簡寫爲c)連續運行而非單步運行,程序到達斷點會自動停下來,這樣就能夠停在下一次循環的開頭。
    (gdb) l
    5 int sum = 0, i;
    6 char input[5];
    7 
    8 while (1) {
    9 scanf("%s", input);
    10 for (i = 0; input[i] != '\0'; i++)
    11 sum = sum*10 + input[i] - '0';
    12 printf("input=%d\n", sum);
    13 }
    14 return 0;
    (gdb) b 9
    Breakpoint 2 at 0x80483bc: file main.c, line 9.
    (gdb) c
    Continuing.
    input=123
    Breakpoint 2, main () at main.c:9
    9 scanf("%s", input);
    1: sum = 123
 
3. 用info命令能夠查看已經設置的斷點
    Breakpoint 3 at 0x8048411: file main.c, line 12.
    (gdb) i breakpoints
    Num Type Disp Enb Address What
    2 breakpoint keep y 0x080483c3 in main at main.c:9
    breakpoint already hit 1 time
    3 breakpoint keep y 0x08048411 in main at main.c:12
  
4. 每一個斷點都有一個編號,能夠用編號指定刪除某個斷點:  
    (gdb) delete breakpoints 2
    (gdb) i breakpoints 
    Num Type Disp Enb Address What
    3 breakpoint keep y 0x08048411 in main at main.c:12
 
5. 有時候一個斷點暫時不用能夠禁用掉而沒必要刪除,這樣之後想用的時候能夠直接啓用,而沒必要從新
   從代碼裏找應該在哪一行設斷點:
    (gdb) disable breakpoints 3
    (gdb) i breakpoints     
    Num Type Disp Enb Address What
    3 breakpoint keep n 0x08048411 in main at main.c:12
    (gdb) enable 3
    (gdb) i breakpoints     
    Num Type Disp Enb Address What
    3 breakpoint keep y 0x08048411 in main at main.c:12
    (gdb) delete breakpoints     
    Delete all breakpoints? (y or n) y
    (gdb) i breakpoints    
    No breakpoints or watchpoints.
 
6. gdb的斷點功能很是靈活,還能夠設置斷點在知足某個條件時才激活。
  條件斷點是語法是:break  [where] if [condition],
  這種斷點真是很是管用尤爲是在一個循環或遞歸中,或是要監視某個變量。
  注意,這個設置是在gdb中的,只不過每通過那個斷點時gdb會幫你檢查一下條件是否知足。
  例如咱們仍然在循環開頭設置斷點,可是僅當sum不等於0時才中斷,而後用run命令(簡寫爲r)從新從程序開頭連續運行:
    (gdb) break 9 if sum != 0    
    Breakpoint 5 at 0x80483c3: file main.c, line 9.
    (gdb) i breakpoints 
    Num Type Disp Enb Address What
    5 breakpoint keep y 0x080483c3 in main at main.c:9
    stop only if sum != 0
    (gdb) r
    The program being debugged has been started already.
    Start it from the beginning? (y or n) y
    Starting program: /home/akaedu/main 
    123
    input=123
    Breakpoint 5, main () at main.c:9
    9 
 
 三 觀察點
(gdb) watch input[5]
Hardware watchpoint 2: input[5]
(gdb) i watchpoints 
Num Type Disp Enb Address What
2 hw watchpoint keep y input[5]
 
 四 段錯誤
若是程序運行時出現段錯誤,用gdb能夠很容易定位到到底是哪一行引起的段錯誤,例如這個小程
序:
 
#include <stdio.h>
int main(void)
{
    int man = 0;
    scanf("%d", man);
    return 0;
}
調試過程以下:
$ gdb main
...
(gdb) r
Starting program: /home/akaedu/main 
123
Program received signal SIGSEGV, Segmentation fault.
0xb7e1404b in _IO_vfscanf () from /lib/tls/i686/cmov/libc.so.6
(gdb) bt
#0 0xb7e1404b in _IO_vfscanf () from /lib/tls/i686/cmov/libc.so.6
#1 0xb7e1dd2b in scanf () from /lib/tls/i686/cmov/libc.so.6
#2 0x0804839f in main () at main.c:6
 
# 五 調試宏
在gdb下,咱們沒法print宏定義,由於宏是預編譯的.因此要在gcc編譯程序的時候,加上-ggdb3參數 就能夠了。
另外,你可使用下述的gdb的宏調試命令 來查看相關的宏。
info macro – 你能夠查看這個宏在哪些文件裏被引用了,以及宏定義是什麼樣的。
macro – 你能夠查看宏展開的樣子。
相關文章
相關標籤/搜索