我一直想知道调试器是如何工作的?特别是可以‘附加’到已经运行的可执行文件上的那个。我知道编译器会将代码翻译成机器语言,但是调试器如何“知道”它所附加的是什么呢?
发布于 2008-10-19 19:32:03
调试器如何工作的细节将取决于您正在调试的是什么,以及操作系统是什么。对于Windows上的本机调试,您可以在MSDN:Win32 Debugging API上找到一些详细信息。
用户通过名称或进程ID告诉调试器要附加到哪个进程。如果是一个名称,则调试器将查找进程ID,并通过系统调用启动调试会话;在Windows下,这将是DebugActiveProcess。
一旦附加,调试器将进入事件循环,这与任何UI很相似,但操作系统将根据正在调试的进程中发生的事件生成事件,而不是来自窗口系统的事件-例如,发生异常。参见WaitForDebugEvent。
调试器能够读取和写入目标进程的虚拟内存,甚至可以通过操作系统提供的API调整其寄存器值。请参阅适用于Windows的debugging functions列表。
调试器能够使用符号文件中的信息将地址转换为源代码中的变量名称和位置。符号文件信息是一组单独的API,并不是操作系统的核心部分。在Windows上,这是通过Debug Interface Access SDK实现的。
如果您正在调试托管环境(.NET、Java等)该过程通常看起来类似,但细节不同,因为虚拟机环境提供的是调试API,而不是底层操作系统。
发布于 2014-02-13 14:30:40
据我所知:
对于x86上的软件断点,调试器用CC
(int3
.这是在Windows上使用WriteProcessMemory
完成的。当CPU到达该指令并执行int3
时,这会导致CPU生成调试异常。OS接收到此中断,意识到进程正在被调试,并通知调试器进程命中断点。
命中断点并停止进程后,调试器将在其断点列表中查找,并将CC
替换为最初存在的字节。调试器在EFLAGS
中设置TF
, the Trap Flag (通过修改CONTEXT
),并继续该过程。陷阱标志使中央处理器在下一条指令上自动生成单步异常(INT 1
)。
当正在调试的进程下一次停止时,调试器再次将断点指令的第一个字节替换为CC
,然后该进程继续。
我不确定是否所有调试器都是这样实现的,但我已经编写了一个Win32程序,它可以使用这种机制进行自我调试。完全没用,但很有教育意义。
发布于 2008-10-19 20:52:27
在Linux中,调试进程是从ptrace(2)系统调用开始的。关于如何使用ptrace
实现一些简单的调试构造,This article有一个很好的教程。
https://stackoverflow.com/questions/216819
复制相似问题