.NET / Rotor原始碼分析4 - 修改Rotor使其傳送CLR Notification

ATField發表於2007-05-21

在使用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.csdn.net/atfield
轉載請註明出處

 

相關文章