4

假设一个调试器(常见的 x86 ring3 调试器,如 olly、IDA、gdb...)将软件断点设置为虚拟地址 0x1234。

这是通过将 0x1234 处的任何操作码替换为“0xCC”来完成的。现在让我们假设被调试进程运行此 0xCC 指令并引发软件异常,并且调试器捕获到此异常。

调试器检查内存内容、寄存器并做一些事情......现在它想要恢复被调试进程。

这是据我所知。从现在开始,这是我的假设。

调试器恢复被调试者的原始操作码(已替换为 0xCC)以恢复执行。

调试器操纵被调试者的 CONTEXT 的 EIP 来指向恢复的指令。

调试器处理异常,现在,被调试者从断点恢复。

但调试器希望保留断点。调试器如何管理这个?

4

2 回答 2

2

要直接回答原始问题,请参阅GDB 内部手册

当用户说要继续时,GDB 会恢复原来的指令,单步执行,重新插入陷阱,然后继续。

于 2016-05-24T17:08:47.230 回答
0

简而言之,普通人的话:

由于进入调试状态是处理器X86中的原子操作,ARM因此处理器进入调试状态并退出调试状态与架构中的任何其他指令相同。参见gdb 文档解释了它是如何工作的和可以使用的。

以下是 ARM 和 X86 规范的一些亮点:

ARM中:

SW(软件)断点是通过在单步执行或执行代码之前用特殊的“断点”指令临时替换断点位置的指令操作码来实现的。当内核执行断点指令时,将被强制进入调试状态。SW 断点只能放在 RAM 中,因为它们依赖于修改目标内存。

通过对观察点单元进行编程来设置 HW(硬件)断点,以监视内核总线是否从特定内存位置获取指令。可以在 RAM 或 ROM 中的任何位置设置硬件断点。在调试复制指令(分散加载)、修改或处理器 MMU 重新映射内存区域的代码时,应使用硬件断点。在这些情况下,软件断点是不可靠的,因为它们可能会丢失或被覆盖。

X86中:

The way software breakpoints work is fairly simple. Speaking about x86 specifically, to set a software breakpoint, the debugger simply writes an int 3 instruction (opcode 0xCC) over the first byte of the target instruction. This causes an interrupt 3 to be fired whenever execution is transferred to the address you set a breakpoint on. When this happens, the debugger “breaks in” and swaps the 0xCC opcode byte with the original first byte of the instruction when you set the breakpoint, so that you can continue execution without hitting the same breakpoint immediately. There is actually a bit more magic involved that allows you to continue execution from a breakpoint and not hit it immediately, but keep the breakpoint active for future use; I’ll discuss this in a future posting.

正如您可能想象的那样,硬件断点设置有特殊的硬件支持。特别是对于 x86,这涉及到一组特殊的可能鲜为人知的寄存器,称为“Dr”寄存器(用于调试寄存器)。这些寄存器允许您设置最多四个(对于 x86,这是高度特定于平台的)地址,当读取、读/写或执行时,将导致处理器抛出一个特殊异常,导致执行停止并控制转移到调试器

于 2013-04-18T20:12:44.683 回答