「Linux 系统编程」gdb 调试指令

1 gdb 调试工具

1.1 什么是 gdb

gdbGNU Debugger)是 Unix/Linux 系统下的 命令行调试工具,主要用于分析程序运行时的行为、定位崩溃(Segmentation Fault)、内存泄漏、逻辑错误等问题。支持 C、C++、Fortran、Go 等多种语言编译的程序。


1.2 生成可调式文件

使用 -g 选项编译程序,生成调试表:

1
g++ -g test.cpp -o debug_test

加载可执行文件:

1
gdb ./debug_test



2 gdb 调试指令

2.1 显示源码与断点设置

  • list 显示源码

    1
    2
    list  # 显示源码
    l # 显示源码,list 简写为 l

    list <行号> 显示第 <行号> 附近的一部分代码:

    1
    list 10  # 显示第 10 行附近的代码

    list <函数名> 显示对应函数附近的代码:

    1
    list main  # 显示 main 函数附近的代码


    list <起始行号>, <终止行号> 显示指定范围的代码:

    1
    2
    3
    list 1, 3  # 显示 1 ~ 3 行的代码
    list 1, # 以第 1 行为开头
    list , 10 # 以第 10 行为结尾


    另外,可以通过使用 set listsize <行数> 修改单次 list 显示的行数(默认 10 行)。

    1
    set listsize 20  # 改为每次显示 20 行

  • break 设置断点

    1
    2
    break [位置]  # 在当前文件指定位置设置断点
    b [位置] # break 简写为 b 设置断点

    break <行号>指定行 设置断点:

    1
    break 17

    break <函数名>函数入口位置 设置断点:

    1
    break work

    可以通过 info breakpoints 输出当前所有断点的信息。


  • break 设置 条件断点

    1
    break [位置] if [条件]

    例如,设置在第 8 行设置一个断点,当 i == 1 时暂停:

    1
    break 8 if i == 1


  • tbreak 设置 临时断点

    1
    tbreak [位置]

    临时断点在触发之后就会自动删除。


  • 其他断点相关指令

    • info breakpoints:查看所有断点信息
    • disable <断点编号>:禁用断点
    • enable <断点编号>:启用断点
    • delete <断点编号>:删除指定编号的断点
    • clear <位置>:删除指定位置的断点
    • condition <断点编号> <条件>:为已有断点添加条件


2.2 程序运行

  • run 启动程序

    run 命令会从头开始执行程序,直到遇到断点、程序结束 或 发生错误

    如果 main 函数有参数,run 命令可以携带参数执行,形如 run arg1 arg2

    1
    2
    3
    run  # 从头开始执行,遇到断点暂停(无断点直接执行到结束)
    r # run 简写为 r
    run arg1 arg2 # main 带有参数,携带参数执行

  • start 启动程序并在 main 函数的入口处自动暂停

    start 命令相当于执行 break main + run(main 函数入口处设置断点再执行程序)。

    1
    2
    start             # 启动并在 main 开头暂停
    start arg1 arg2 # 带参数启动并在 main 暂停

  • next 执行下一行源代码(不进入函数内部

    next 命令将函数调用视为 单条语句 直接执行,不会进入被调用函数的内部。

    next 命令适合跳过不需要深入分析的库函数(例如 printfscanf 等)或已知正确的函数。

    1
    2
    next  # 执行下一行源代码(不进入函数内部)
    n # next 简写为 n

    例如,示例程序的主函数如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    int main(){
    int a = 3;
    int b = 4;

    cout << "a + b = " << a + b << endl;

    work(a); // next 不进入函数内部

    return 0;
    }

    执行 next 不会进入 work 函数内部,直接将 work(a) 这一行执行。


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

    step 命令遇到函数调用会进入函数内部,并在被调用函数的第一条指令处暂停。

    如果没有遇到函数调用,step 命令和 next 命令的效果是一样的。

    1
    2
    step   # 执行下一行源代码(进入函数内部)
    s # step 命令的简写

    例如,有如下示例程序:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #include <iostream>
    #include <cstring>
    using namespace std;

    void work(int n){
    int sum = 0;
    for(int i = 1; i <= n; i ++ ){
    sum += i;
    }
    cout << sum << endl;
    }

    int main(){
    int a = 3;
    int b = 4;

    cout << "a + b = " << a + b << endl;

    work(a); // s 会进入函数内部

    return 0;
    }

    step 命令在执行到 work(a) 这一行时,会进入函数内部。


  • 其它程序运行相关指令

    • skip 标记需要 step 命令跳过的函数
    1
    2
    skip function [函数名]  # 标记跳过的函数
    step # 后续 step 时会跳过,不进入该函数
    • finish 直接执行完当前函数并返回
    1
    2
    step     # 进入不需要深入分析的函数
    finish # 立即执行完该函数并回到调用点

    如果由于 step 不小心进入了库函数,可以通过 finish 命令退出:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    int main(){
    int a = 3;
    int b = 4;

    printf("printf function\n"); // step 不小心进入 printf 函数

    cout << "a + b = " << a + b << endl;

    work(a);

    return 0;
    }


    • next [次数] / step [次数] 连续执行多次 next / step
    1
    2
    next 5   # 连续执行5次 next
    step 3 # 连续执行3次 step

2.3 变量操作

  • print 打印变量值

    1
    print a

  • display 每次暂停时自动显示值

    1
    display b

    可以通过 undisplay 取消设置跟踪变量:

    1
    undisplay [跟踪变量编号]

  • set var 修改变量值

    1
    set var a = 7  # 将变量 a 修改为 7


  • ptype 查看变量类型

    1
    ptype a  # 查看变量 a 的类型

2.4 函数堆栈操作

当进入函数内部之后,发现无法访问函数外部的变量。此时可以通过 backtrace 查看调用栈(简写 bt),切换到上层的栈帧,从而看到当前栈帧的变量:

1
2
3
4
backtrace              # 查看调用栈
frame 1 # 切换到上层栈帧
info locals # 查看当前帧的局部变量
print a # 打印需要查看的变量



2.5 循环调试

  • until 运行到指定行

    until 运行到当前函数中下一个更高层级的源码行(常用于跳出循环):

    1
    until  

    通常配合断点和 continue 使用:

    1
    2
    3
    until      # 先跳出当前循环
    break 100 # 在循环外设断点
    continue # 运行到新断点

    until [行号] 运行到当前函数内的指定行(必须大于当前行)

    1
    until 10  # 运行到第 10 行

  • continue 继续运行到下一个断点

    1
    2
    continue  # 运行到下一个断点
    continue 2 # 忽略前 2 次触发断点



2.6 退出调试

1
quit  # 退出 gdb 调试

「Linux 系统编程」gdb 调试指令
https://marisamagic.github.io/2025/08/14/20250814/
作者
MarisaMagic
发布于
2025年8月14日
许可协议