像 GDB 这样的调试器如何能够一次 运行 编写一条指令?

How is a debugger like GDB able to run a program one instruction at a time?

我能理解专门为调试而编译的程序如何在代码中插入断点和陷阱,但像 GDB 这样的程序如何在预编译程序上做到这一点?他们如何能够在每条指令后停止程序的执行?

我正在 Windows 机器上工作,但我也愿意了解它在 Linux 上的工作原理。

任何方向或资源将不胜感激,因为谷歌搜索 returns 说明如何使用 GDB,而不是它在低级别如何工作。

How are they able to halt the execution of a program after every single instruction?

大多数处理器,包括所有 i*86 个处理器,支持 single-step 执行。

当要求 GDB 在这样的处理器上执行一条机器指令时,这是一个非常简单的过程:

  1. 安排处理器以 single-step 模式执行(这是特定于处理器的,请阅读 i*86 实现 here)。
  2. 恢复劣质进程
  3. 等待中断(如果第 1 步成功,将在 1 条指令完成后立即出现)。

在没有 single-step 支持的处理器上,GDB 的工作有点复杂:

  1. 反汇编当前指令(以了解下一条指令从哪里开始;这在指令大小固定的 RISC 处理器上是微不足道的),
  2. 在下一条指令上插入一个临时断点(由于控制转移指令,这有点复杂——下一条指令可能很远)
  3. 恢复劣质进程
  4. 等待中断(如果第 2 步有效,将在 1 条指令完成后立即出现)。
  5. 删除步骤 2 中插入的临时断点。

资源:

  • 您可以阅读 source of GDB,但它不是最容易导航的代码。
  • 约瑟夫·凯恩 (Joseph Kain) 有一系列 blog posts 解释事情是如何运作的,尽管它似乎已经停滞不前。