00. 目录

01. 命令概述

gdb命令包含在GNU的gcc开发套件中,是功能强大的程序调试器。

gdb中的命令很多,但我们只需掌握其中十个左右的命令,就大致可以完成日常的基本的程序调试工作。

命令 解释 示例
file<文件名> 加载被调试的可执行程序文件。 因为一般都在被调试程序所在目录下执行GDB,因而文本名不需要带路径。 (gdb) file test
r Run的简写,运行被调试的程序。 如果此前没有下过断点,则执行完整个程序;如果有断点,则程序暂停在第一个可用断点处。 (gdb) r
c Continue的简写,继续执行被调试程序,直至下一个断点或程序结束。 (gdb) c
b <行号> b <函数名称> b *<函数名称> b *<代码地址> d [编号] b: Breakpoint的简写,设置断点。两可以使用“行号”“函数名称”“执行地址”等方式指定断点位置。 其中在函数名称前面加“*”符号表示将断点设置在“由编译器生成的prolog代码处”。如果不了解汇编,可以不予理会此用法。 d: Delete breakpoint的简写,删除指定编号的某个断点,或删除所有断点。断点编号从1开始递增。 (gdb) b 8 (gdb) b main (gdb) b *main (gdb) b *0x804835c (gdb) d
s, n s: 执行一行源程序代码,如果此行代码中有函数调用,则进入该函数; n: 执行一行源程序代码,此行代码中的函数调用也一并执行。 s 相当于其它调试器中的“Step Into (单步跟踪进入)”; n 相当于其它调试器中的“Step Over (单步跟踪)”。 这两个命令必须在有源代码调试信息的情况下才可以使用(GCC编译时使用“-g”参数)。 (gdb) s (gdb) n
si, ni si命令类似于s命令,ni命令类似于n命令。所不同的是,这两个命令(si/ni)所针对的是汇编指令,而s/n针对的是源代码。 (gdb) si (gdb) ni
p <变量名称> Print的简写,显示指定变量(临时变量或全局变量)的值。 (gdb) p i (gdb) p nGlobalVar
display … undisplay <编号> display,设置程序中断后欲显示的数据及其格式。 例如,如果希望每次程序中断后可以看到即将被执行的下一条汇编指令,可以使用命令 “display /i $pc” 其中 $pc 代表当前汇编指令,/i 表示以十六进行显示。当需要关心汇编代码时,此命令相当有用。 undispaly,取消先前的display设置,编号从1开始递增。 (gdb) display /i $pc (gdb) undisplay 1
i info的简写,用于显示各类信息,详情请查阅“help i”。 (gdb) i r
q Quit的简写,退出GDB调试环境。 (gdb) q
help [命令名称] GDB帮助命令,提供对GDB名种命令的解释说明。 如果指定了“命令名称”参数,则显示该命令的详细说明;如果没有指定参数,则分类显示所有GDB命令,供用户进一步浏览和查询。 (gdb) help

02. 命令格式

用法:gdb [选项] [参数]

03. 常用选项

-cd	设置工作目录
-q	安静模式,不打印介绍信息和版本信息
-d	添加文件查找路径
-x	从指定文件中执行GDB指令
-s	设置读取的符号表文件

常用命令

file <文件名>	加载被调试的可执行程序文件
run	重新开始运行文件
start	单步执行,运行程序,停在第一执行语句
list	查看原代码,简写l
set	设置变量的值
next	单步调试(逐过程,函数直接执行),简写n
step	单步调试(逐语句:跳入自定义函数内部执行),简写s
backtrace	查看函数的调用的栈帧和层级关系,简写bt
frame	切换函数的栈帧,简写f
info	查看函数内部局部变量的数值,简写i
finish	结束当前函数,返回到函数调用点
continue	继续运行,简写c
print	打印值及地址,简写p
quit	退出gdb,简写q

04. 参考示例

4.1 参考程序

#include <stdio.h>
#include <string.h> 
#include <stdlib.h> 

int fun(int number)
{
    printf("fun....number = %d\n", number);
    return 0;
}

int main(int argc, char **argv)
{
    int i = 0;

    //argc: 传递参数的个数
    //argv: 参数列表
    for (i = 0; i < argc; i++)
    {
        printf("argv[%d]: %s\n", i, argv[i]); 
    }

    //循环
    for (i = 0; i < 100; i++)
    {
        printf("i = %d\n", i); 
    }

    //调用函数
    fun(10);

    return 0;
}

4.2 生成包含调试信息的可执行文件

[deng@localhost tmp]$ gcc -g test.c -o test
[deng@localhost tmp]$ 

4.3 启动GDB

[deng@localhost tmp]$ gdb test
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-110.el7
Copyright (C) 2013 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-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/deng/tmp/test...done.
(gdb) 

4.4 载入调试程序

(gdb) file test
Load new symbol table from "/home/deng/tmp/test"? (y or n) y
Reading symbols from /home/deng/tmp/test...done.
(gdb) 

4.5 直接执行到程序结束

(gdb) r
Starting program: /home/deng/tmp/test 
argv[0]: /home/deng/tmp/test
i = 0
i = 1
i = 2
i = 3
i = 4
i = 5

下面使用“r”命令执行(Run)被调试文件,因为尚未设置任何断点,将直接执行到程序结束

4.6 设置断点

[deng@localhost tmp]$ gdb test
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-110.el7
Copyright (C) 2013 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-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/deng/tmp/test...done.
(gdb) b main 
Breakpoint 1 at 0x400552: file test.c, line 13.
(gdb) 

使用“b”命令在 main 函数开头设置一个断点(Breakpoint)

上面最后一行提示已经成功设置断点,并给出了该断点信息:在源文件 test.c 第13行处设置断点;这是本程序的第一个断点(序号为1);断点处的代码地址为 0x400552(此值可能仅在本次调试过程中有效)。回过头去看源代码,第13行中的代码为“int i = 0”,恰好是 main 函数中的第一个可执行语句(前面的“int n;”为变量定义语句,并非可执行语句)。

再次使用“r”命令执行(Run)被调试程序

(gdb) r
Starting program: /home/deng/tmp/test 

Breakpoint 1, main (argc=1, argv=0x7fffffffe408) at test.c:13
13          int i = 0;
Missing separate debuginfos, use: debuginfo-install glibc-2.17-222.el7.x86_64
(gdb) 

4.7 单步执行语句

(gdb) n
17          for (i = 0; i < argc; i++)
(gdb) 

4.8 查看变量的值

(gdb) p i
$1 = 0
(gdb) 

4.9 设置断点行号或者函数名

(gdb) b 25
Breakpoint 2 at 0x4005a2: file test.c, line 25.
(gdb) b fun
Breakpoint 3 at 0x400528: file test.c, line 7.
(gdb) 

4.10 执行到下一个断点处

(gdb) c
Continuing.
argv[0]: /home/deng/tmp/test

Breakpoint 2, main (argc=1, argv=0x7fffffffe408) at test.c:25
25              printf("i = %d\n", i); 
(gdb) 

4.11 设置显示变量的值

(gdb) display i
1: i = 1
(gdb) n
i = 1
23          for (i = 0; i < 100; i++)
1: i = 1
(gdb) 

4.12 每次中断都将显示下一条汇编指令

(gdb) si
0x00000000004005a5      25              printf("i = %d\n", i); 
1: i = 2
(gdb) si
0x00000000004005a7      25              printf("i = %d\n", i); 
1: i = 2
(gdb) 

并且以后程序每次中断都将显示下一条汇编指定(“si”命令用于执行一条汇编代码——区别于“s”执行一行C代码)

4.13 查看断点信息

(gdb) info break
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000000400552 in main at test.c:13
        breakpoint already hit 1 time
2       breakpoint     keep y   0x00000000004005a2 in main at test.c:25
        breakpoint already hit 3 times
3       breakpoint     keep y   0x0000000000400528 in fun at test.c:7
(gdb) 

4.14 删除断点

(gdb) info break
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000000400552 in main at test.c:13
        breakpoint already hit 1 time
2       breakpoint     keep y   0x00000000004005a2 in main at test.c:25
        breakpoint already hit 3 times
3       breakpoint     keep y   0x0000000000400528 in fun at test.c:7
(gdb) d 1
(gdb) info break
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x00000000004005a2 in main at test.c:25
        breakpoint already hit 3 times
3       breakpoint     keep y   0x0000000000400528 in fun at test.c:7
(gdb) 

4.15 显示寄存器的值

(gdb) i r
rax            0x2      2
rbx            0x0      0
rcx            0x5      5
rdx            0x7ffff7dd6a00   140737351870976
rsi            0x2      2
rdi            0x0      0
rbp            0x7fffffffe320   0x7fffffffe320
rsp            0x7fffffffe300   0x7fffffffe300
r8             0x0      0
r9             0x7ffff7a5b16d   140737348219245
r10            0x22     34
r11            0x246    582
r12            0x400430 4195376
r13            0x7fffffffe400   140737488348160
r14            0x0      0
r15            0x0      0
rip            0x4005a7 0x4005a7 <main+100>
eflags         0x297    [ CF PF AF SF IF ]
cs             0x33     51
ss             0x2b     43
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0x0      0
(gdb) 

4.16 显示具体寄存器的值

(gdb) i r rax
rax            0x2      2
(gdb) 

4.17 退出GDB

(gdb) quit
A debugging session is active.

        Inferior 1 [process 77076] will be killed.

Quit anyway? (y or n) y
[deng@localhost tmp]$ 

05. 附录

参考:【Linux】一步一步学Linux系列教程汇总