Rob*_*ker 92
调试器如何工作的细节取决于您正在调试的内容以及操作系统的内容.对于Windows上的本机调试,您可以在MSDN:Win32调试API上找到一些详细信息.
用户通过名称或进程ID告诉调试器要附加哪个进程.如果是名称,则调试器将查找进程ID,并通过系统调用启动调试会话; 在Windows下,这将是DebugActiveProcess.
一旦连接,调试器就会像任何UI一样进入事件循环,但是不是来自窗口系统的事件,操作系统将根据正在调试的进程中发生的事情生成事件 - 例如发生异常.请参阅WaitForDebugEvent.
调试器能够读取和写入目标进程的虚拟内存,甚至可以通过操作系统提供的API调整其寄存器值.请参阅Windows 的调试功能列表.
调试器能够使用符号文件中的信息将地址转换为源代码中的变量名称和位置.符号文件信息是一组独立的API,并不是操作系统的核心部分.在Windows上,这是通过调试接口访问SDK.
如果您正在调试托管环境(.NET,Java等),则该过程通常看起来类似,但细节不同,因为虚拟机环境提供调试API而不是底层操作系统.
Jon*_*art 59
据我了解:
对于x86上的软件断点,调试器用CC
(int3
)替换指令的第一个字节.这是WriteProcessMemory
在Windows上完成的.当CPU到达该指令并执行时int3
,这会导致CPU生成调试异常.操作系统收到此中断,意识到正在调试进程,并通知调试器进程断点被命中.
在命中断点并且进程停止后,调试器会在其断点列表中查找,并将其替换为CC
最初的字节.调试器套TF
,所述陷阱标志中EFLAGS
(通过修改CONTEXT
),并且继续处理.陷阱标志使CPU INT 1
在下一条指令上自动生成单步异常().
当正在调试的进程下次停止时,调试器再次用断言替换断点指令的第一个字节CC
,然后继续该过程.
我不确定这是否完全是由所有调试器实现的,但我编写了一个Win32程序,该程序设法使用此机制调试自身.完全无用,但有教育意义.
如果您使用的是Windows操作系统,那么很好的资源就是John Robbins的"调试Microsoft .NET和Microsoft Windows应用程序":
(甚至是旧版本:"调试应用程序")
本书有一章介绍调试器的工作原理,包括几个简单(但工作)调试器的代码.
由于我不熟悉Unix/Linux调试的细节,这些东西可能根本不适用于其他操作系统.但我猜想,作为一个非常复杂的主题的介绍,概念 - 如果不是细节和API - 应该"移植"到大多数操作系统.
我认为这里有两个主要问题需要回答:
\n1. 调试器如何知道发生了异常?
\n当正在调试的进程中发生异常时,调试器会在目标进程中定义的任何用户异常处理程序有机会响应异常之前收到操作系统的通知。如果调试器选择不处理此(第一次机会)异常通知,则异常分派序列将进一步进行,然后目标线程将有机会处理该异常(如果它想要这样做)。如果目标进程未处理 SEH 异常,则会向调试器发送另一个调试事件(称为第二次机会通知),以通知它目标进程中发生了未处理的异常。来源
\n\n2. 调试器如何知道如何在断点处停止?
\n简单的答案是:当您在程序中放置断点时,调试器会用 int3 指令(软件中断)替换该点的代码。结果,程序被挂起并调用调试器。
\n了解调试的另一个有价值的来源是 Intel CPU 手册(Intel\xc2\xae 64 和 IA-32 架构\nSoftware Developer\xe2\x80\x99s 手册)。在第3A卷第16章中,介绍了调试的硬件支持,例如特殊异常和硬件调试寄存器。以下摘自该章:
\n\nT(陷阱)标志,TSS \xe2\x80\x94 当尝试切换到 TSS 中设置了 T 标志的任务时,\n生成调试异常 (#DB)。
\n\n我不确定 Window 或 Linux 是否使用这个标志,但是阅读该章非常有趣。
\n\n希望这对某人有帮助。
\n 归档时间: |
|
查看次数: |
42295 次 |
最近记录: |