日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

WinDbg+Rotor解析WinForm调用堆栈及实现

發布時間:2025/3/15 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 WinDbg+Rotor解析WinForm调用堆栈及实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前段寫過一篇文章“CLR探索系列:深入追蹤托管exe加載執行過程”,在那篇文章中,主要是側重靜態代碼的分析,追蹤源代碼的流程一步一步看是如何實現的。

這次,寫一篇文章,結合Windbg,從一個托管應用程序執行的調用堆棧開始,追蹤其調用堆棧中的線索,以及這些托管應用程序執行中調用的功能實現,來展示托管代碼的加載和執行的流程和實現。

首先還是找一個小白鼠:

<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

?

?????public partial class Form1 : Form

??? {

??????? public Form1()

??????? {

??????????? InitializeComponent();

??????? }

??????? private void button1_Click(object sender, EventArgs e)

??????? {

??????????? System.Object o = new object();

??????????? lock (o)

??????????? {

??????????????? System.GC.Collect();

??????????? }

???????? }

}

?

這里找的是一個WinForm應用程序來作為小白鼠。

咱就不采用在調用的關鍵的mscorwksMscoeEE的方法上面下斷點來跟蹤,然后解釋每個斷點調用堆棧和環境的解釋方法了,直接把main threadcall stack給打出來一行一行的去挖掘好了。

?

打開Windbg,附加到進程,加載好相關的symbol2.0SOS,切換到第0Thread然后輸出其調用堆棧:

?

0:000> k

ChildEBP RetAddr?

0012f4a0 7c92e9ab ntdll!KiFastSystemCallRet

<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />0012f3c4 7b08432d USER32!NtUserWaitMessage+0xc

0012f434 7b08416b System_Windows_Forms_ni+0xb432d

0012f464 7b0c69fe System_Windows_Forms_ni+0xb416b

0012f490 79e88ee4 System_Windows_Forms_ni+0xf69fe

0012f510 79e88e31 mscorwks!CallDescrWorkerWithHandler+0xa3

0012f650 79e88d19 mscorwks!MethodDesc::CallDescr+0x19c

0012f668 79e88cf6 mscorwks!MethodDesc::CallTargetWorker+0x20

0012f67c 79f084b0 mscorwks!MethodDescCallSite::Call+0x18

0012f7e0 79f082a9 mscorwks!ClassLoader::RunMain+0x220

0012fa48 79f0817e mscorwks!Assembly::ExecuteMainMethod+0xa6

0012ff18 79f07dc7 mscorwks!SystemDomain::ExecuteMainMethod+0x398

0012ff68 79f05f61 mscorwks!ExecuteEXE+0x59

0012ffb0 79011b5fmscorwks!_CorExeMain+0x11b

0012ffc0 7c816fd7 mscoree!_CorExeMain+0x2c

0012fff0 00000000 KERNEL32!BaseProcessStart+0x23

?

BaseProcessStart表示的是運行的Winform啟動的進程。在前面的上一篇文章里面已經分析過,并且用相關的工具查看過,一個托管模塊開始運行的時候只想的是_CorExeMain方法。這是mscoree里面的一個方法。而mscoree只是選擇加載CLR版本的一個Loader

之后,就跳轉到了選擇了特定版本了的mscorwks里面的_CorExeMain中:

0012ffb0 79011b5f mscorwks!_CorExeMain+0x11b

sscli中,這個程序的名字就換成了_CorExeMain2來顯示對商業版本的區別。打開CorExeMain的定義:

?

__int32 STDMETHODCALLTYPE _CorExeMain2(? // Executable exit code.

??? PBYTE? ?pUnmappedPE,????????????? ???// -> memory mapped code

??? DWORD?? cUnmappedPE,?????????? ????// Size of memory mapped code

??? __in LPWSTR? pImageNameIn,????????? // -> Executable Name

??? __in LPWSTR? pLoadersFileName,? ????// -> Loaders Name

__in LPWSTR? pCmdLine)??????????? // -> Command Line

?

?????? Load這個應用程序的image的時候,這個entry point是從native entry point中被call的。在_CorExeMain2中,我們可以看到如下部分屬性和方法:

__int32 STDMETHODCALLTYPE _CorExeMain2( …)?????????

{

??? // This entry point is used by clix

??? BOOL bRetVal = 0;

?

??? // Before we initialize the EE, make sure we've snooped for all EE-specific

??? // command line arguments that might guide our startup.

??? HRESULT result = CorCommandLine::SetArgvW(pCmdLine);

?

??? if (!CacheCommandLine(pCmdLine, CorCommandLine::GetArgvW(NULL))) {

??????? LOG((LF_STARTUP, LL_INFO10, "Program exiting - CacheCommandLine failed\n"));

??????? bRetVal = -1;

??????? goto exit;

??? }

?

??? if (SUCCEEDED(result))

??????? result = CoInitializeEE(COINITEE_DEFAULT | COINITEE_MAIN);

??? if (FAILED(result)) {

??????? VMDumpCOMErrors(result);

??????? SetLatchedExitCode (-1);

??????? goto exit;

??? }

?

??? // Load the executable

??? bRetVal = ExecuteEXE(pImageNameIn);

?

if (!bRetVal) {

?????? //這里,如果出現錯誤的話,可能的原因不正確的metadata文件的格式,或者其版本,可能是loadmscorwks的版本不正確造成的。也可能是signed assemblies和對應的錯誤處理程序不匹配造成的。總之,運行正確的話,是不會走到這里的。這個地方也可以作為CLR在開發的時候調試下斷點的一個地方。

??????? EEMessageBoxCatastrophic(IDS_EE_COREXEMAIN2_FAILED_TEXT, IDS_EE_COREXEMAIN2_FAILED_TITLE);

??????? SetLatchedExitCode (-1);

??? }

?

//當程序走到這個地方的時候,it is the time to shut off the lights and went home了。這些都是程序退出的時候的執行的動作。

exit:

??? STRESS_LOG1(LF_STARTUP, LL_ALWAYS, "Program exiting: return code = %d", GetLatchedExitCode());

??? STRESS_LOG0(LF_STARTUP, LL_INFO10, "EEShutDown invoked from _CorExeMain2");

??? EEPolicy::HandleExitProcess();???

??? //END_ENTRYPOINT_VOIDRET;

??? return bRetVal;

}

?

OK,從上面的程序里面,我們大概看到了一個托管模塊的生命周期。所以,最關鍵的一句就在這里了:

bRetVal = ExecuteEXE(pImageNameIn);?

這一行,也就是對應這上面堆棧調用的倒數第四行了。

??????

接下來讓我們看看這個ExecuteEXE方法都做了些什么吧:

BOOL STDMETHODCALLTYPE ExecuteEXE(HMODULE hMod)

{

??? if (!hMod)

??????? return FALSE;

?

??? ETWTraceStartup::TraceEvent(ETW_TYPE_STARTUP_EXEC_EXE);

??? TIMELINE_START(STARTUP, ("ExecuteExe"));

?

??? EX_TRY_NOCATCH

??? {

??????? // Executables are part of the system domain

??????? SystemDomain::ExecuteMainMethod(hMod);

??? }

??? return TRUE;

}?

?????? 運行到這里,就可以看到,SystemDomain已經啟動,同時開始執行Main方法。繼續查看上面的調用堆棧:

?

0012f7e0 79f082a9 mscorwks!ClassLoader::RunMain+0x220

0012fa48 79f0817e mscorwks!Assembly::ExecuteMainMethod+0xa6

0012ff18 79f07dc7 mscorwks!SystemDomain::ExecuteMainMethod+0x398

??????

可以看到,繼SystemDomain之后,又將Assembly load到了Domain中,最后是用ClassLoader來執行Main程序。這里就不一一展示其實現了。

?????? 在執行了RunMain方法的時候,這時下面的三個堆棧:

?

0012f510 79e88e31 mscorwks!CallDescrWorkerWithHandler+0xa3

0012f650 79e88d19 mscorwks!MethodDesc::CallDescr+0x19c

0012f668 79e88cf6 mscorwks!MethodDesc::CallTargetWorker+0x20

0012f67c 79f084b0 mscorwks!MethodDescCallSite::Call+0x18

??????

?????? 在前面的上一篇文章中已經說過,MethodDescmethodtableEEClassMethodDescChunk這些結構的關系和區別。MethodDescCLR中對應的托管方法的非托管的結構。

?????? 下面的三個方法,主要是實現了定位和尋找Call Target,負責托管代碼的編譯等工作。

CallDescrWorkerWithHandler是調用的一個外部C語言編寫的函數,Call這個方法的目的,是為了把MethodTable與操作系統平臺相關的Exception Handle程序聯系起來。

?

最后的堆棧最上面的幾行:

?

0012f3c4 7b08432d USER32!NtUserWaitMessage+0xc

0012f434 7b08416b System_Windows_Forms_ni+0xb432d

0012f464 7b0c69fe System_Windows_Forms_ni+0xb416b

0012f490 79e88ee4 System_Windows_Forms_ni+0xf69fe

?

這個地方首先調用了System.Windows.Forms.NI中來初始化Winform的顯示。這里的ni后綴表面調用的是nGen函數。最后停在USER32!NtUserWaitMessage上面,等待用戶的操作。

?

這里的分析,只是展示了一個WinForm在執行完畢之后的調用堆棧。里面有很多和ThreadJITGC相關的功能的初始化和額外線程的啟動,譬如,主線程創建FinalizerThreadGCThread,由于沒有下斷點跟蹤,所以這里都沒有展現出來。

此文的主要目的,在于提供一種閱讀和分析Rotor的方法,讓對Rotorsscli)的分析,不僅僅限制與對靜態代碼的分析,我們還可以結合DotNet應用程序的運行,動態的分析代碼的執行和實現。

同時,研究不同類型應用程序調用堆棧,里面還有非常多有意思的東西可以發掘。

?

3/25/2008 10:38:33 AM

?

總結

以上是生活随笔為你收集整理的WinDbg+Rotor解析WinForm调用堆栈及实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。