CppCon 2015 学习:Give me fifteen minutes and I’ll change your view of GDB

GDB - 超出你认知的工具

GDB(GNU 调试器)是一个功能强大的调试工具,但它的学习曲线相对较陡,许多人可能会觉得它 不太直观。不过,一旦掌握了 GDB,它会为你提供巨大的调试帮助。

1. GDB 的学习曲线

  • 易用,但不容易学会 :GDB 本身非常 强大 ,能够进行各种复杂的调试操作,但它的 使用方法命令 可能对于初学者来说不是特别直观。很多新手在刚接触 GDB 时会觉得操作有些困难。
  • 你可以进行 逐行调试查看变量值查看调用栈 等各种调试任务,但在开始使用时,可能会感到有些迷茫。

2. TUI:文本用户界面

  • TUI(Text User Interface) 是 GDB 提供的一个功能,它允许用户以文本形式进行交互,类似于 命令行界面 。这种方式比传统的 GDB 使用方式更加 直观
    例如,在 GDB 中使用 TUI,可以同时显示源代码和调试信息,帮助你更轻松地进行 步进调试(step through)。
  • TUI 是一种有效的调试方式,但它的名字可能让人误解 。很多人可能会以为它是图形化的用户界面(GUI),但实际上它只是一个 文本界面,提供更加直观的调试体验。

3. Python:自动化你的调试过程

  • Python 脚本 在 GDB 中的应用可以帮助你 自动化调试过程 ,尤其是在调试复杂的程序时,反复的手动操作会非常繁琐。通过 Python,你可以编写脚本来 自动化调试步骤 ,例如:
    • 自动设置断点
    • 动态检查变量值
    • 处理复杂的逻辑和条件断点
  • 使用 Python 脚本 可以大大提高调试的效率,尤其是在面对 大量重复性的调试任务 时。

4. 可逆调试:事情是如何发生的?

  • 可逆调试 是 GDB 提供的一个非常强大的功能,允许你 回溯程序的执行过程 ,查看程序在运行时的状态。这意味着你不仅可以 前进 ,还可以 后退,回顾代码是如何执行的。
  • 如何实现? 通过 GDB 的 记录和回放 功能,你可以在程序运行时记录每一步的执行状态,然后回放并查看程序状态在不同时间点的变化。这个功能对于调试 复杂问题 或是 难以重现的 bug 非常有帮助。
  • "事情是如何发生的?" :这种调试方式特别适用于追溯 难以复现的 bug ,可以帮助你 逆向 了解问题的根本原因。

总结

  • GDB 强大,但学习不易:掌握 GDB 的基本操作可以大大提高调试效率,但需要投入一定的学习时间。
  • TUI(文本用户界面):通过 TUI,可以更直观地进行调试,尽管它的名字容易引起误解。
  • Python 自动化调试:使用 Python 脚本可以有效地自动化调试过程,提高调试效率。
  • 可逆调试 :GDB 的回溯功能让你能够了解程序执行的每一步,并且回顾如何发生错误。
    GDB 的这些功能,虽然不容易上手,但一旦掌握,可以大大提升调试能力,帮助你解决许多棘手的问题。
cpp 复制代码
gdb -tui

GDB 的一些酷功能

GDB 是一个功能非常强大的调试工具,除了基本的调试操作外,它还提供了一些非常有用的高级功能。以下是一些 酷功能,这些功能可以帮助你更高效地调试和追踪程序。

1. tbreakrbreak

  • tbreak临时断点 ,设置一个断点,程序在触发该断点时会停止,但该断点会 自动移除 ,只触发一次。
    示例:

    bash 复制代码
    (gdb) tbreak foo
  • rbreak正则表达式断点 ,允许你设置多个断点,基于正则表达式匹配符号名。
    示例:

    bash 复制代码
    (gdb) rbreak foo.*

2. 条件断点 (break xxx if yyy)

  • 可以在设置断点时添加条件,只有当 条件满足时 ,断点才会触发。这对于调试某些特定情况下的问题非常有用。
    示例:

    bash 复制代码
    (gdb) break foo if x > 10

3. commandssilent

  • commands :设置断点后自动执行的命令列表。当断点被触发时,GDB 会自动执行这些命令,而不需要你手动输入。
    示例:

    bash 复制代码
    (gdb) break foo
    (gdb) commands
    > print x
    
    > continue
    
    > end
  • silent :用于 抑制 在触发断点时的输出,避免打扰。
    示例:

    bash 复制代码
    (gdb) break foo if x > 10
    (gdb) silent

4. 保存断点和历史 (save breakpoints, save history)

  • save breakpoints :将当前所有的断点保存到脚本文件中,方便下次使用。
    示例:

    bash 复制代码
    (gdb) save breakpoints my_breakpoints.txt
  • save history :将执行过的 GDB 命令历史保存到文件中。
    示例:

    bash 复制代码
    (gdb) save history my_history.txt

5. callwatch

  • call :调用程序中的函数并传入参数,允许在调试时调用目标程序的函数,查看其行为。
    示例:

    bash 复制代码
    (gdb) call my_function(5)
  • watch -l :创建基于 地址watchpoint ,当指定地址的数据发生变化时,程序会中断。
    示例:

    bash 复制代码
    (gdb) watch *0x601050
  • rwatch读型 watchpoint ,它会监视内存地址的读取操作。
    示例:

    bash 复制代码
    (gdb) rwatch foo

6. info 命令

  • info line foo.c:42 :查看指定源代码行的相关信息。
    示例:

    bash 复制代码
    (gdb) info line foo.c:42
  • info line * $pc :查看当前程序计数器 (PC) 所指向的源代码行。
    示例:

    bash 复制代码
    (gdb) info line *$pc

7. thread apply all bt

  • thread apply all bt :查看所有线程的 backtrace (调用栈),这对于调试多线程程序特别有用。
    示例:

    bash 复制代码
    (gdb) thread apply all bt

8. dprintf

  • dprintf动态的 printf 调试 ,允许在程序的运行过程中插入 打印调试信息 ,无需修改源代码。
    示例:

    bash 复制代码
    (gdb) dprintf 3 "Variable x = %d\n", x

9. Python 扩展功能

  • Python:定义自定义命令 :你可以通过继承 gdb.Command 类来定义自定义的 GDB 命令。
    示例:

    python 复制代码
    class MyCommand(gdb.Command):
        def __init__(self):
            super(MyCommand, self).__init__("my_command", gdb.COMMAND_USER)
        def invoke(self, arg, from_tty):
            gdb.write("This is a custom command!\n")
  • Python:钩子事件 :你可以使用 gdb.events.stop.connect 来挂钩 GDB 的事件,在调试过程中触发 Python 函数。
    示例:

    python 复制代码
    def stop_handler(event):
        print("GDB stopped at:", event)
    gdb.events.stop.connect(stop_handler)

10. gcc 的 -g 和 -O 标志是正交的

  • -g:表示生成调试信息,允许调试器可以访问到源代码和变量信息。
  • -O :表示优化,优化代码以提高运行效率,通常会改变代码结构,可能会使调试变得更加困难。
    正交性-g-O 标志是 独立的 ,你可以同时使用它们。即使你使用了优化(-O),只要加上 -g,GDB 仍然可以使用调试信息。

总结

这些是 GDB 中一些非常 有用强大的功能,它们不仅可以帮助你更好地进行调试,还能提高你的调试效率:

  • tbreak, rbreak:临时断点和正则断点。
  • commands, silent:在断点处自动执行命令,并抑制输出。
  • 保存断点和历史:将调试设置和命令历史保存以便重用。
  • call, watch, rwatch:调用函数和监视变量的变化。
  • info 命令:查看源代码和程序计数器信息。
  • thread apply all bt:查看所有线程的调用栈。
  • dprintf :动态的 printf 调试。
  • Python 扩展:用 Python 脚本自定义调试命令和钩子事件。
  • gcc 的 -g 和 -O 是正交的:调试信息和优化标志不冲突。
相关推荐
南枝异客5 分钟前
三数之和-力扣
开发语言·javascript·数据结构·算法·leetcode·排序算法
德先生&赛先生20 分钟前
深入理解c语言中的static
c++
爱意随风起风止意难平24 分钟前
AIGC 基础篇 Python基础 05 元组,集合与字典
开发语言·python·aigc
栗子不爱栗子29 分钟前
从理解AI到驾驭文字:一位技术爱好者的写作工具探索手记
python·学习·ai
鸢时望巧38 分钟前
Shell循环(二)
运维·开发语言
景彡先生1 小时前
C++ 中的 iostream 库:cin/cout 基本用法
开发语言·c++
vvilkim1 小时前
Flutter 核心概念:深入理解 StatelessWidget 与 StatefulWidget
开发语言·javascript·flutter
sunly_1 小时前
Flutter:导航背景固定在顶部,下拉分页布局
开发语言·javascript·flutter
悟能不能悟2 小时前
讲一件Java虚拟线程
java·开发语言·oracle
sjg200104142 小时前
golang学习随便记x[2,3]-字符串处理与正则表达式
开发语言·学习·golang