gdb调试详解

是 GNU 调试器(GNU Debugger)的缩写,它是一个功能强大的 Unix-like 系统下的源代码调试器。使用 gdb,程序员可以查看程序在运行时的状态,设置断点,单步执行代码,检查变量的值,以及执行其他调试任务。(在命令行终端中进行)

gdb启动流程

  1. 编译相关:编译链接的时候-g表示可以调试,如果要使用gdb调试记得加上

    1
    gcc -g test.cpp -o test
  2. 启动gdb,示例如下:

    1
    2
    gdb test 
    gbd -q test //表示不打印gbd版本信息,界面比较干净
  3. gdb下查看源码:list

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    (gdb) list 
    9 #define MAX_SIZE
    10
    11 int main()
    12 {
    13 int i,fd,size1 ,size2 ,len;
    14 char *buf = "helo!I'm liujiangyong ";
    15 char buf_r[15];
    16 len = strlen(buf);
    17 fd = open("/home/hello.txt",O_CREAT | O_TRUNC | O_RDWR,0666);
    18 if (fd<0)
    (gdb)
    19 {
    20 perror("open :");
    21 exit(1);
    22 }
    23 else
    24 {
    25 printf("open file:hello.txt %d\n",fd);
    26 }
    27 size1 = write(fd,buf,len);
    28 if (fd<0)
    (gdb)
    29 {
    30 printf("writre erro;");
    31
    32 }
    33 else
    34 {
    35 printf("写入的长度:%d\n写入文本内容:%s\n",size1,buf);
    36
    37 }
    38 lseek(fd,0,SEEK_SET);
    (gdb)
    39 size2 = read(fd,buf_r,12);
    40 if (size2 <0)
    41 {
    42 printf("read erro\n");
    43 }
    44 else
    45 {
    46 printf("读取长度:%d\n 文本内容是:%s\n",size2,buf_r);
    47 }
    48 close(fd);
    (gdb)
    49
    50
    51 }
    (gdb)
    Line number 52 out of range; write.c has 51 lines.
    (gdb)

  4. gbd下运行程序:run

    该命令会运行程序直到结束或者遇到断点等待下一个命令

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    (gdb) r
    The program being debugged has been started already.
    Start it from the beginning? (y or n) y
    Starting program: /home/eit/c_test/test
    open file:hello.txt 3
    写入的长度:22
    写入文本内容:helo!I'm liujiangyong
    读取长度:12
    文本内容是:helo!I'm liu
    [Inferior 1 (process 19987) exited normally]
    (gdb)

  5. gdb下设置断点:break+行号

    该命令会在某一行设置一个断点,info breakpoints会显示所有断点信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    (gdb) b 5
    Breakpoint 3 at 0x400836: file write.c, line 5.
    (gdb) b 26
    Breakpoint 4 at 0x4008a6: file write.c, line 26.
    (gdb) b 30
    Breakpoint 5 at 0x4008c6: file write.c, line 30.
    (gdb) info breakpoints
    Num Type Disp Enb Address What
    3 breakpoint keep y 0x0000000000400836 in main at write.c:5
    4 breakpoint keep y 0x00000000004008a6 in main at write.c:26
    5 breakpoint keep y 0x00000000004008c6 in main at write.c:30
    (gdb)

    num type disp enb address what
    断点编号 类型 断点执行一次后是否有效,keep(有) 当前断点是否有效,y(有) 内存地址 在函数中的位置
  6. gdb下单步执行:continuestepnextfinish

    • continue:在断点处继续执行程序

    • next:执行下一行代码(跳过函数内部)

    • step:执行下一行代码(进入函数内部)

    • finish:执行完当前函数并返回到父函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    (gdb) r
    Starting program: /home/eit/c_test/test

    Breakpoint 3, main () at write.c:12
    12 {
    (gdb) n
    14 char *buf = "helo!I'm liujiangyong ";
    (gdb)
    16 len = strlen(buf);
    (gdb)
    17 fd = open("/home/hello.txt",O_CREAT | O_TRUNC | O_RDWR,0666);
    (gdb) s
    open64 () at ../sysdeps/unix/syscall-template.S:81
    81 ../sysdeps/unix/syscall-template.S: No such file or directory.
    (gdb)
    main () at write.c:18
    18 if (fd<0)
    (gdb)
    25 printf("open file:hello.txt %d\n",fd);
    (gdb)
    __printf (format=0x400a26 "open file:hello.txt %d\n") at printf.c:28
    28 printf.c: No such file or directory.
    (gdb) c
    Continuing.
    open file:hello.txt 3

    Breakpoint 4, main () at write.c:27
    27 size1 = write(fd,buf,len);
    (gdb)
    Continuing.
    写入的长度:22
    写入文本内容:helo!I'm liujiangyong
    读取长度:12
    文本内容是:helo!I'm liu
    [Inferior 1 (process 20737) exited normally]
    (gdb)

  7. gdb下查看变量:printwhatis

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    main () at write.c:28
    28 if (fd<0)
    (gdb)
    35 printf("写入的长度:%d\n写入文本内容:%s\n",size1,buf);
    (gdb) print fd
    $10 = 3
    (gdb) whatis fd
    type = int
    (gdb)

  8. gdb下退出gdb:quit

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    (gdb) r
    Starting program: /home/eit/c_test/test
    open file:hello.txt 3
    写入的长度:22
    写入文本内容:helo!I'm liujiangyong
    读取长度:12
    文本内容是:helo!I'm liu
    [Inferior 1 (process 20815) exited normally]
    (gdb) q
    root@ubuntu:/home/eit/c_test#

常用命令

当使用表格来表示 gdb 的常用命令时,可以如下所示:

命令分类 命令 描述
启动和退出 gdb your_program 启动 GDB 并加载指定的程序
quitq 退出 GDB
调试控制 run [arguments]r [arguments] 运行程序并传递参数
continuec 继续执行,直到遇到下一个断点或程序结束
nextn 执行下一行代码(不进入函数)
steps 执行下一行代码(进入函数)
finish 执行完当前函数并返回到父函数
断点管理 break [location]b [location] 在指定位置设置断点
info breakpointsinfo b 显示所有断点信息
disable [breakpoint_number] 禁用指定编号的断点
enable [breakpoint_number] 启用指定编号的断点
delete [breakpoint_number]d [breakpoint_number] 删除指定编号的断点
变量和内存查看 print [variable_name]p [variable_name] 显示变量的值
ptype [variable_name] 显示变量的类型
set var [variable_name]=[newValue] 修改变量的值
x/NFU [address] 显示内存内容,N是数量,F是格式,U是单位,address是地址
其他常用命令 list [location]l [location] 显示源代码
backtracebt 显示堆栈跟踪
watch [expression] 设置观察点,当表达式值改变时停止
catch [event] 捕获特定事件(如异常)
show path 显示GDB搜索源代码的路径
setargs [arguments] 设置传递给程序的命令行参数
show args 显示设置好的运行时参数
attach [process_id] 连接到正在运行的进程
detach 断开与已连接进程的连接
shell [command] 执行shell命令
自定义命令和脚本 define [cmd_name] [command_list] 定义自定义命令
脚本文件 使用脚本文件来自动化调试任务
多线程和多进程调试 info threads 显示所有线程信息
thread [tid] 切换到指定编号的线程
`set follow-fork-mode [child parent]`

请注意,这个表格只是提供了 gdb 的一些常用命令的概览,每个命令还有更多的选项和用法可以探索。