像 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 在这样的处理器上执行一条机器指令时,这是一个非常简单的过程:
- 安排处理器以 single-step 模式执行(这是特定于处理器的,请阅读
i*86
实现 here)。
- 恢复劣质进程
- 等待中断(如果第 1 步成功,将在 1 条指令完成后立即出现)。
在没有 single-step 支持的处理器上,GDB 的工作有点复杂:
- 反汇编当前指令(以了解下一条指令从哪里开始;这在指令大小固定的 RISC 处理器上是微不足道的),
- 在下一条指令上插入一个临时断点(由于控制转移指令,这有点复杂——下一条指令可能很远)
- 恢复劣质进程
- 等待中断(如果第 2 步有效,将在 1 条指令完成后立即出现)。
- 删除步骤 2 中插入的临时断点。
资源:
- 您可以阅读 source of GDB,但它不是最容易导航的代码。
- 约瑟夫·凯恩 (Joseph Kain) 有一系列 blog posts 解释事情是如何运作的,尽管它似乎已经停滞不前。
我能理解专门为调试而编译的程序如何在代码中插入断点和陷阱,但像 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 在这样的处理器上执行一条机器指令时,这是一个非常简单的过程:
- 安排处理器以 single-step 模式执行(这是特定于处理器的,请阅读
i*86
实现 here)。 - 恢复劣质进程
- 等待中断(如果第 1 步成功,将在 1 条指令完成后立即出现)。
在没有 single-step 支持的处理器上,GDB 的工作有点复杂:
- 反汇编当前指令(以了解下一条指令从哪里开始;这在指令大小固定的 RISC 处理器上是微不足道的),
- 在下一条指令上插入一个临时断点(由于控制转移指令,这有点复杂——下一条指令可能很远)
- 恢复劣质进程
- 等待中断(如果第 2 步有效,将在 1 条指令完成后立即出现)。
- 删除步骤 2 中插入的临时断点。
资源:
- 您可以阅读 source of GDB,但它不是最容易导航的代码。
- 约瑟夫·凯恩 (Joseph Kain) 有一系列 blog posts 解释事情是如何运作的,尽管它似乎已经停滞不前。