Interop-Debugging,互操作调试,又称混合调试。

一般调试背景
当调试进程时,它会生成调试事件,调试器可以监听和响应这些事件。这些事件包括CreateProcess、LoadModule、异常、ExitThread、断点等。
调度调试事件时,调试对象将停止,直到调试器继续调试事件为止。当调试对象停止时,调试器可以在窗口期间检查调试对象。一旦debugger继续运行,它将自由运行,直到下一个调试事件。调试事件以每个线程为基础。
托管+本机调试都共享这个概念模型,尽管它们有不同的调试事件集,以及在停止和运行之间循环的不同方法。
调试器使用调试事件和检查API来实现所有调试操作。本文只涉及解释互操作调试如何路由托管+本机调试事件。如何在这些事件的基础上构建调试器不在本文的讨论范围之内。

本机调试:
本机调试由操作系统实现。操作系统提供用于监听和继续调试事件(WaitForDebugEvent和ContinueDebugEvent)的调试API。在调试事件中,操作系统冻结调试对象。本机调试API非常小。只有少数本机调试事件。
本机调试的关键属性:

-本机调试完全是进程外的(oop)。调试器不需要来自调试对象的额外合作(在操作系统支持之外)。
-我们将本机调试对象停止状态称为“冻结”。操作系统已停止冻结进程,并且在恢复之前不执行任何用户代码。
-本机调试事件可以在进程自由运行的任何时候出现。
-对win32调试API的所有调用都必须在同一线程上进行。我们称这个线程为W32ET,它变成了一个非常特殊的b/c,它决不能阻塞。

 

托管调试

托管调试完全是由CLR在用户模式下实现的,因此操作系统不知道何时进行纯托管调试。
CLR在为来自托管调试API的请求提供服务的每个托管进程中都有一个特殊线程(称为帮助线程)。CLR中专门用于托管调试的部分称为Left-Side(LS)。驻留在调试器进程中的ICorDebug的实现称为right-side(RS)。LS和RS通过各种用户模式进程间通信(IPC)机制进行通信,例如命名事件和共享内存块。
托管调试接口(ICorDebug)比其本机接口丰富得多。关键属性:

-托管调试是一个进程内模型。帮助线程必须存在并在调试对象的进程中运行,以便托管调试正常工作。
-我们将托管调试对象停止状态称为“已同步”。从操作系统的角度来看,同步进程是实时的,但是所有托管线程都被CLR停止。
-托管调试事件完全是在用户模式下创建和调度的。
-托管调试事件可以建立在本机调试事件之上。
-托管调试操作只能在托管停止状态下发生(这需要助手线程正在运行)

Managed vs. Native operations.

托管调试和本机调试是两个不同的世界。对于任何调试操作,查看它是在托管世界还是在本机世界中进行都非常重要。CLR调试服务只实现托管调试操作,不实现任何本机调试操作。同样,本机调试API不提供任何托管调试支持。
例如,最终用户只想到“步进”,但实际上有两个离散的操作,“托管步进”和“本机步进”,有两个完全不相交的实现。托管单步执行是通过CLR的ICorDebug API实现的;而本机单步执行是通过使用Win32调试事件的非CLR本机调试库实现的。
本机调试API级别很低,而托管调试API非常丰富。例如,本机执行控制(例如步进和断点)完全在异常之上实现,并且在本机调试API中没有显式的支持。托管调试API显式具有断点和步进器功能。
抽象级别的这种差异阻止了托管+本机调试操作之间的代码共享。

那么什么是互操作调试?
最终用户对互操作调试的看法是能够在单个调试会话中调试应用程序的托管+本机部分。这包括在托管+本机代码和运行混合调用堆栈之间单步执行的能力。托管+本机调试事件完全不相交,由调试器中的不同组件处理(我们称之为托管调试引擎和本机调试引擎)。
如果托管+本机调试器只是天真地同时附加到同一进程上,它们将相互干扰。互操作调试器确保这两个不相交的模型协同工作。
从接口的角度来看,互操作调试是将同一进程上的托管调试接口和本机调试接口公开给单个调试器。这意味着调试器的本机调试引擎和托管调试引擎可以同时运行,只需稍加修改。从理论上讲,这意味着可以轻松地扩展一个只进行托管调试和只进行本机调试的调试器来执行互操作调试。
理想情况下,本机+管理的调试引擎将彼此充分合作,以向最终用户呈现统一的模型。实际上,调试引擎之间的这种通信可能需要对调试器的设计进行重大的更改和规划。

 

标签: none

添加新评论