debugging器如何工作?

我一直在想,debugging器是如何工作的? 特别是可以“附加”到已经运行的可执行文件。 我明白,编译器将代码翻译成机器语言,但是debugging器怎么知道它被连接到什么地方呢?

debugging器的工作细节取决于你正在debugging什么,以及操作系统是什么。 对于Windows上的本地debugging,您可以在MSDN上find一些详细信息: Win32 Debugging API 。

用户通过名称或进程ID告诉debugging器要附加哪个进程。 如果它是一个名称,那么debugging器将查找进程ID,并通过系统调用启动debugging会话; 在Windows下这将是DebugActiveProcess 。

一旦连接,debugging器将进入一个事件循环,就像任何UI一样,而不是来自窗口系统的事件,操作系统将根据debugging过程中发生的事件生成事件 – 例如发生exception。 请参阅WaitForDebugEvent 。

debugging器能够读写目标进程的虚拟内存,甚至可以通过操作系统提供的API调整其寄存器值。 请参阅Windows的debuggingfunction列表。

debugging器能够使用符号文件中的信息将地址转换为源代码中的variables名称和位置。 符号文件信息是一组独立的API,并不是操作系统的核心部分。 在Windows上,这是通过debugging接口访问SDK 。

如果您正在debugging托pipe环境(.NET,Java等),那么进程通常看起来相似,但细节不同,因为虚拟机环境提供debuggingAPI而不是底层操作系统。

据我所知:

对于x86上的软件断点,debugging器用CCint3 )replace指令的第一个字节。 这是用Windows上的WriteProcessMemory完成的。 当CPU到达该指令并执行int3 ,会导致CPU产生debuggingexception。 操作系统接收到这个中断,意识到这个进程正在被debugging,并且通知debugging器进程该中断点被命中。

在命中断点并且进程停止之后,debugging器查找其断点列表,并用最初存在的字节代替CC 。 debugging器在EFLAGS设置TF (陷阱标志 ,通过修改CONTEXT ),并继续该过程。 陷阱标志使CPU在下一条指令中自动产生一个单步exception( INT 1 )。

当被debugging的进程下一次停止时,debugging器再次用CCreplace断点指令的第一个字节,并且过程继续。

我不确定这是否是所有debugging器实现的,但是我写了一个Win32程序来pipe理使用这种机制进行debugging。 完全没用,但教育。

在Linux中,debugging进程从ptrace(2)系统调用开始。 这篇文章有一个很好的教程,介绍如何使用ptrace来实现一些简单的debugging结构。

如果您使用的是Windows操作系统,那么John Robbins的“debuggingMicrosoft .NET和Microsoft Windows应用程序”

(甚至是旧版本: “debugging应用程序” )

本书有一个关于debugging器如何工作的章节,其中包括一些简单(但工作)的debugging器的代码。

由于我不熟悉Unix / Linuxdebugging的细节,这些东西可能根本不适用于其他操作系统。 但是我想,作为一个非常复杂的主题的介绍,概念 – 如果不是细节和API – 应该“移植”到任何操作系统上。

英特尔CPU手册(英特尔®64和IA-32架构软件开发人员手册)是了解debugging的另一个重要来源。 在第3A卷第16章中,介绍了debugging的硬件支持,如特殊exception和硬件debugging寄存器。 以下是这一章:

T(陷阱)标志,TSS – 尝试切换到其TSS中设置了T标志的任务时,生成debuggingexception(#DB)。

我不确定Window或者Linux是否使用这个标志,但是阅读这个章节非常有趣。

希望这有助于某人。

我的理解是,当你编译一个应用程序或DLL文件,无论它编译包含代表函数和variables的符号。

当你有一个debugging版本的时候,这些符号比它的发布版本更详细,因此允许debugging器给你更多的信息。 将debugging器附加到进程时,它会查看当前正在访问哪些函数,并从这里parsing所有可用的debugging符号(因为它知道编译文件的内部结构是什么样子,它可以确定内存中可能存在的内容,内容包括整数,浮点数,string等)。 就像第一张海报所说的那样,这些信息以及这些符号的工作方式在很大程度上取决于环境和语言。