调试器揭秘,第五部分:指令级单步执行和断点
Demystifying Debuggers, Part 5: Instruction-Level Stepping and Breakpoints

原始链接: https://www.dgtlgrove.com/p/demystifying-debuggers-part-5-instruction

本文是调试器实现系列的一部分,详细介绍了围绕调试器事件处理构建基本控制循环的过程。此前,调试器只是启动、附加到进程并记录调试事件,而没有交互。现在,目标是添加用于断点和单步执行的用户控制。 核心思想是将事件循环(使用`WaitForDebugEvent`和`ContinueDebugEvent`)包装在一个命令循环中。该循环将接受诸如“继续”、“退出”以及关键的单步执行和断点命令。 “继续”只是继续执行,而“退出”则终止被调试进程。 本文为实现单步执行和断点奠定了基础,并指出事件循环需要进行调整,以便在特定事件(如指令步骤或异常)发生时暂停执行,从而允许调试器在恢复被调试进程之前处理命令。重点是建立控制这些功能的框架,而不是详细说明它们的具体实现。

黑客新闻 新 | 过去 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 揭秘调试器,第五部分:指令级单步执行和断点 (dgtlgrove.com) 3 分,ibobev 发表于 1 小时前 | 隐藏 | 过去 | 收藏 | 讨论 帮助 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系 搜索:
相关文章

原文

Part 5 in a series.

Now that we’ve seen how a debugger modifies a debuggee (using the kernel and CPU features), let’s put these pieces together and see how we might implement both breakpoints and instruction-level stepping in a basic debugger.

Recall in Part 3 that we wrote a simple Windows “debugger”, which launched and attached to a process, and logged the debug events that the debugger received.

We launched and attached to the process through CreateProcessA:

We gathered debug events using WaitForDebugEvent and ContinueDebugEvent:

This “debugger” does nothing but follow along the debuggee as it executes. When it receives an event, it immediately resumes the debuggee, and doesn’t modify it at all. But an actually usable debugger, of course, allows the user to choose when the debuggee resumes, and what modifications to make before it does, through a user interface.

For the purposes of this post, those debuggee modifications will include instruction-level stepping and instruction-level breakpoints.

To support this, let’s enclose this event gathering loop with a control loop, which will receive commands to either place breakpoints, step threads, or to resume the debuggee.

First, for the basic commands, our work is simple.

For CommandKind_Resume, we simply set need_commands to 0. Execution flows to the event loop, which resumes the debuggee until an event occurs which the debugger would need to know about.

For CommandKind_Quit, we simply set need_commands to 0, then is_running to 0, and then we kill the debuggee—for example, on Windows, using the TerminateProcess API:

We also need to adjust our debug event loop to terminate (thus allowing for more command execution) under certain conditions. This is a debugger design decision, although many choices are obvious—for example, should the debuggee pause if the debugger is notified that a debuggee thread is created? Probably not. If the debuggee completes an instruction-level step, or hits a trap instruction? Then yes. If the debuggee encounters an exception? Then also yes.

Now, let’s consider how we might implement the instruction-level stepping and breakpoint commands.

联系我们 contact @ memedata.com