.NET / Rotor源码分析4 - 修改Rotor使其发送CLR Notification

本文介绍了解决Rotor默认不发出CLRNotification的问题,通过修改IsDebuggerPresent宏定义为TRUE,使WinDbg能接收到CLRNotification,便于.NET和Rotor的调试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在使用WinDbg + SOS正式跟踪Rotor的源代码研究.NET的实现之前,还有个问题需要解决:Rotor缺省并不会发出CLR NotificationCLR Notification是指CLR在运行的时候发出的一些通知,比如加载模块,代码被编译等等,这些通知对于调试Rotor / .NET以及SOS都非常重要。例如你可以设置调试器为一遇到CLR Notification便中断,在某些情况下非常有用。还有就是SOS的部分命令如BPMD等依赖于CLR notification实现其部分功能。因此这个问题必须得解决。

CLR Notifcation本质上其实就是一个SEH (Structured Exception Handling)异常。同时VC的异常以及CLR本身的托管异常也是SEH异常,只是他们的Exception Code不同和参数不同而已。CLR通过调用RaiseException函数产生Exception Code = CLR Notification的异常,这个异常并不会导致程序非正常退出,而是仅仅对调试器起到一个通知作用,CLR本身在异常处理代码中会自动处理掉这个异常。

Rotor通过间接调用DACNotificationHelper来产生CLR Notification,如下:

void DACNotifyExceptionHelper(TADDR *args,UINT argCount)

{

    PAL_TRY

    { 

        if (IsDebuggerPresent() && !CORDebuggerAttached())

        {

            RaiseException(CLRDATA_NOTIFY_EXCEPTION, 0, argCount, (ULONG_PTR *) args);

        }

    }

    PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)

    {       

    }

    PAL_ENDTRY

}

可以看到Rotor调用RaiseException产生代码为CLRDATA_NOTIFICATION_EXCEPTIONSEH异常,也就是CLR Notification,这个异常将被后面的PAL_EXCEPT块(类似__except)处理,不作任何事情,直接“吞掉”异常。启动调试器跟踪一下发现在if语句时候并没有对IsDebuggerPresent() API进行调用,这个函数的作用是检查进程是否被正在被调试器所调试,只有在调试器挂接上此进程并且CLR调试器没有挂接上的时候才会发生此种Notification。进一步观察汇编:

xor    eax, eax

test    eax,eax

je      mscorwks!DACNotifyExceptionHelper+0x89

发现这里没有调用API而直接对eax赋值为0,然后加以判断,提示IsDebuggerPresent可能被定义成FALSE。在命令行下面输入:

D:/usr/src/sscli20>findstr /s "IsDebuggerPresent" *.c *.cpp *.h

binaries.x86dbg.rotor/sdk/pal/inc/rotor_palrt.h:#define IsDebuggerPresent() FALSE

 

clr/src/debug/ee/debugger.cpp:        if (IsDebuggerPresent() && !g_pRCThread->G

etDCB(iWhich)->m_rightSideIsWin32Debugger)

clr/src/utilcode/debug.cpp:            t_pDbgPres pFcn = (t_pDbgPres) GetProcAdd

ress(hKrnl32, "IsDebuggerPresent");

clr/src/vm/eeconfig.h:            if (IsDebuggerPresent()) DebugBreak();

              /

clr/src/vm/i386/gmsx86.cpp:                if (IsDebuggerPresent())

clr/src/vm/pefile.cpp:    BOOL fOutputToDebugger = (level == LL_ERROR && IsDebug

gerPresent());

clr/src/vm/stubmgr.cpp:    if (IsDebuggerPresent())

clr/src/vm/util.cpp:        if (IsDebuggerPresent() && !CORDebuggerAttached())

palrt/inc/rotor_palrt.h:#define IsDebuggerPresent() FALSE

发现果然IsDebuggerPresent被定义为FALSE,看来是Rotor将其禁止掉了。因为我们这里目的是对.NET / Rotor进行研究,不太在意程序的性能,因此这里只需要将这里的IsDebuggerPresent定义成TRUE重新编译即可。

修改之后重新编译,启动Windbg调试clix,运行一个托管代码程序,可以在调试器中发现类似下面的输出:

(1464.c88): CLR notification exception - code e0444143 (first chance)

First chance exceptions are reported before any exception handling.

This exception may be expected and handled.

可以看到CLR Notification已经被Windbg接收到了,之后,如果想当每一个CLR Notifcation到来的时候让调试器中断,只需输入:

sxe clrn

Clrn代表CLR Notification所对应的Exception Code,预定义在WinDbg内部。

OK,至此我们的准备工作完成,下一篇文章我们将正式使用WinDbg+SOS来调试一个托管程序在CLR中的运行过程。

 

作者:      张羿/ATField
Blog:     
http://blog.youkuaiyun.com/atfield
转载请注明出处

 
http://blog.csdn.net/atfield/article/details/1471465 Introduction Shared Source CLI 2.0 (开发代号Rotor) 是微软.NET Framework 2.0的Shared Source实现版本。Shared Source是微软推出的源代码共享计划,可以在一定限制的情况下获得/使用源代码,详情可以参考Microsoft Shared Source Initiative主页:http://www.microsoft.com/resources/sharedsource/。Rotor的代码可以在非商业行为的前提下可以自由修改和发布,只需保留License声明即可。Rotor包含了下面的内容: 1. CLI的运行时(CLR)的符合ECMA标准的实现 2. C# & Jscript编译器 3. .NET Framework中的部分工具,如ilasm, ildasm, cordbg, gacutil, sn等 4. Build工具,如Build, Binplace, NMake等 5. PAL (Platform Adaptation Layer),支持其他平台 6. 自动化回归测试 7. Samples 由此可见,Rotor是研究.NET Framework实现的最佳材料。 Rotor的全部源代码可以在微软的MSDN网站上下载:http://msdn.microsoft.com/net/sscli/ 下载后解压缩,可以看到如下的目录结构: 目录 内容 Binaries.x86*.rotor Build出来的可执行文件和Symbols。这个目录在Build之后才会出现 clr CLI和BCL(Base Class Library)的实现 csharp C#编译器的实现就在这里了 Docs 文档 Env Build时所需的一些文件 Fx 类库的实现 Jscript Jscript编译器的实现 Pal Platform Adaptation Layer的实现。PAL是Rotor对Windows和Unix的一些基本API的封装 Palrt Platform Adaptive Layer Runtime的实现。PAL中的和操作系统平台无关可重用的部分 prebuilt 存放着build所需的一些事先用工具生成好的文件 Samples Samples Tests Regression Test Suite Tools Build工具,包括binplace, build, cppmunge等 Vscommon 公共头文件,主要是微软内部使用的一些产品有关的公用的宏定义 总共大概有150MB左右。 本人先发在优快云上做个备份。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值