国产午夜成人免费看片无遮挡_日本免费xxxx色视频_免费人成网上在线观看_黄网址在线永久免费观看

當前位置:雨林木風下載站 > 技術開發教程 > 詳細頁面

用WinDbg探索CLR世界 [3] 跟蹤辦法的 JIT 過程

用WinDbg探索CLR世界 [3] 跟蹤辦法的 JIT 過程

更新時間:2022-04-26 文章作者:未知 信息來源:網絡 閱讀次數:

本來想按照 sos 的幫助文件上命令的分類逐步介紹 WinDbg 下使用 sos 調試 CLR 程序,但發現這樣實在不夠直觀。索性改成根據我分析 CLR 的實際案例,step by step 介紹功能,這樣結構上雖然混亂一點,但更加直觀,也易于上手 :P

前面兩篇文章里面分別介紹了 WinDbg 的調試配置和線程的基本概念,這篇文章將針對 JIT 編譯對象方法的流程進行分析,逐步介紹如何使用 WinDbg 調試 CLR 程序。

用WinDbg探索CLR世界 [1] - 安裝與環境配置
用WinDbg探索CLR世界 [2] - 線程

首先寫一個簡單的例子程序 demo.cs 并編譯為 demo.exe,使用配置好的 WinDbg 打開之:


以下為引用:

using System;

namespace flier
{
class EntryPoint
{
public void m1()
{
System.Console.Write("EntryPoint.m1()");
}

public void m2()
{
System.Console.Write("EntryPoint.m2()");
}

public static void Main()
{
EntryPoint ep = new EntryPoint();

ep.m1();
ep.m2();
}
}
}




WinDbg 會在載入 demo.exe 后中斷執行。此時可以使用 .load sos 命令加載 sos.dll 命令擴展,并用 .chain 驗證加載是否成功;然后用 ld demo 命令加載 demo.exe 的調試符號文件,用 lm 命令驗證加載是否成功。
然后用 ld kernel32 加載 Kernel32 的調試符號文件,并用 bp kernel32!LoadLibraryExW "du poi(esp+4)" 命令在載入 DLL 的函數入口加上斷點。接下來就是一路 g 指令,直到 mscorwks.dll 被加載。這個 mscorwks.dll 就是類似 JVM 中 jvm.dll 的虛擬機實現代碼,我們要了解的大部分功能都在其中。詳細的解釋可以參看我以前的一篇文章《.Net平臺下CLR程序載入原理分析》

在 mscorwks.dll 被載入后用 ld mscorwks 命令載入其調試符號庫,就可以正式開始我們的探索工作了 :D

目前使用到的 WinDbg 命令如下



以下為引用:

.load sos // 加載 sos 調試擴展模塊,可使用 .chain 命令驗證

ld demo // 加載 demo.exe 調試符號庫,可使用 lm 命令驗證

ld kernel32 // 加載 kernel32.exe 調試符號庫

bp kernel32!LoadLibraryExW "du poi(esp+4)" // 設置斷點監視何時 mscorwks.dll 被載入

g // 執行直到 mscorwks.dll被加載

bd 0 // 清除前面設置的斷點,開始對 mscorwks.dll 進行處理

ld mscorwks // 加載 mscorwks.dll 調試符號庫





Don Box 在《.NET本質論 第1卷:公共語言運行庫》的第六章介紹了方法調用的內部實現流程。其中提到方法表在 JIT 之前,保存的都是 call mscorwks.dll!PreStubWorker 調用,直到第一次使用時,才會對目標 IL 代碼進行 JIT 編譯,并調用之。因此我們第一步可以在此函數上設置斷點(bp mscorwks!PreStubWorker),看看系統是如何調用此函數的。


以下為引用:

0:000> bp mscorwks!PreStubWorker
0:000> g
ModLoad: 70ad0000 70bb6000 E:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.100.0_x-ww_8417450B\comctl32.dll
ModLoad: 79780000 79980000 e:\windows\microsoft.net\framework\v1.1.4322\mscorlib.dll
ModLoad: 79980000 79ca6000 e:\windows\assembly\nativeimages1_v1.1.4322\mscorlib\1.0.5000.0__b77a5c561934e089_ed6bc96c\mscorlib.dll
ModLoad: 79510000 79523000 E:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\mscorsn.dll
Breakpoint 1 hit
eax=0012f7c0 ebx=00148c60 ecx=04aa112c edx=00000004 esi=0012f784 edi=0012f9a8
eip=791d6a4a esp=0012f764 ebp=0012f79c iopl=0 nv up ei pl zr na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=0038 gs=0000 efl=00000246
mscorwks!PreStubWorker:
791d6a4a 55 push ebp




斷點被激活就代表函數被調用。我們先使用 k 看看函數被調用時的上下文環境。


以下為引用:

0:000> k
ChildEBP RetAddr
0012f760 0014930e mscorwks!PreStubWorker
WARNING: Frame IP not in any known module. Following frames may be wrong.
0012f79c 791da434 0x14930e
0012f8b4 791dd2ec mscorwks!MethodDesc::CallDescr+0x1b6
0012f96c 79240405 mscorwks!MethodDesc::Call+0xc5
0012fa18 79240520 mscorwks!AppDomain::InitializeDomainContext+0x10f
0012fa7c 7923d744 mscorwks!SystemDomain::InitializeDefaultDomain+0x11c
0012fd60 791c6e73 mscorwks!SystemDomain::ExecuteMainMethod+0x120
0012ffa0 791c6ef3 mscorwks!ExecuteEXE+0x1c0
0012ffb0 7880a53e mscorwks!_CorExeMain+0x59
0012ffc0 77e1f38c mscoree!_CorExeMain+0x30 [f:\dd\ndp\clr\src\dlls\shim\shim.cpp @ 5426]
0012fff0 00000000 KERNEL32!BaseProcessStart+0x23




這里可以看到從 mscoree!_CorExeMain 一路執行下來的步驟,而那個警告說明這個 stack frame 不在任意一個已知模塊中。這是很正常的,因為這個棧幀實際上是指向由 JIT 動態生成的代碼。我們監視的 mscorwks!PreStubWorker 函數只是作為方法表中函數的入口 stub,系統啟動時還會通過其他方式調用 JIT 完成代碼的編譯執行。
接下來用 SOS 的 !clrstack 命令看看 CLR 的調用堆棧,顯示如下:


以下為引用:

0:000> !clrstack
succeeded
Loaded Son of Strike data table version 5 from "E:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\mscorwks.dll"
Thread 0
ESP EIP
0012f784 791d6a4a [FRAME: PrestubMethodFrame] [DEFAULT] [hasThis] Void System.AppDomain.SetupDomain(ValueClass System.LoaderOptimization,String,String)
0012f9a8 791d6a4a [FRAME: GCFrame]
0012fad0 791d6a4a [FRAME: DebuggerClassInitMarkFrame]
0012fa94 791d6a4a [FRAME: GCFrame]




如果需要更為詳細的詳細,可以使用 -p, -l 或 -r 參數分別顯示參數、局部變量和寄存器,當然前兩者需要調試符號庫的支持才行。

如此一路 g; !clrstack 執行下去,直到 flier.EntryPoint.m1 函數需要被處理為止:


以下為引用:

0:000> !clrstack
Thread 0
ESP EIP
0012f68c 791d6a4a [FRAME: PrestubMethodFrame] [DEFAULT] [hasThis] Void flier.EntryPoint.m1()
0012f69c 06d90080 [DEFAULT] Void flier.EntryPoint.Main()
0012f9b0 791da717 [FRAME: GCFrame]
0012fa94 791da717 [FRAME: GCFrame]




此時用 !dumpstackobjects 命令可以查看當前線程堆棧中使用的所有對象


以下為引用:

0:000> !dumpstackobjects
ESP/REG Object Name
ecx 04aa1a90 flier.EntryPoint
0012f678 04aa1a90 flier.EntryPoint
0012f67c 04aa1a90 flier.EntryPoint
0012f680 04aa1a90 flier.EntryPoint




這里的 flier.EntryPoint 對象地址 0x04aa1a90 就是我們要分析的對象在內存中的位置。

這一階段使用到的 WinDbg 命令如下:


以下為引用:

bp mscorwks!PreStubWorker // 設置代碼斷點

g // 繼續運行至斷點

k // 查看函數調用時的 Native 堆棧調用

!clrstack // 查看函數調用時的 CLR 堆棧調用

!dumpstackobjects // 查看線程堆棧中使用到的所有對象





知道地址后,就可以用 !dumpobj 命令查看對象的詳細信息


以下為引用:

0:000> !dumpobj 04aa1a90
Name: flier.EntryPoint
MethodTable 0x009750a8
EEClass 0x06c632e8
Size 12(0xc) bytes
mdToken: 02000002 (D:\Temp\demo.exe)




信息包括對象的類型名字(Name)和類型信息的地址(EEClass),以及對象的大小(Size)和 Token (mdToken),而方法表 (MethodTable) 正是我們分析方法調用的目標。我們可以用 !dumpclass 命令先進一步查看對象的類型信息:


以下為引用:

0:000> !dumpclass 0x6c632e8
Class Name : flier.EntryPoint
mdToken : 02000002 ()
Parent Class : 79b7c3c8
ClassLoader : 00153850
Method Table : 009750a8
Vtable Slots : 4
Total Method Slots : 8
Class Attributes : 100000 :
Flags : 1000003
NumInstanceFields: 0
NumStaticFields: 0
ThreadStaticOffset: 0
ThreadStaticsSize: 0
ContextStaticOffset: 0
ContextStaticsSize: 0




可以發現其信息與對象信息有很多符合之處,正如 Don Box 所說,一個對象引用指向一個類型 EEClass 實例,而方法表為類型所有,其對象共有。我們可以使用 !dumpmt 命令進一步查看方法表的信息,-md 參數表示需要查看每個方法描述 (MethodDesc):


以下為引用:

0:000> !dumpmt -md 0x09750a8
EEClass : 06c632e8
Module : 0014e090
Name: flier.EntryPoint
mdToken: 02000002 (D:\Temp\demo.exe)
MethodTable Flags : 80000
Number of IFaces in IFaceMap : 0
Interface Map : 009750f4
Slots in VTable : 8
--------------------------------------
MethodDesc Table
Entry MethodDesc JIT Name
79b7c4eb 79b7c4f0 None [DEFAULT] [hasThis] String System.Object.ToString()
79b7c473 79b7c478 None [DEFAULT] [hasThis] Boolean System.Object.Equals(Object)
79b7c48b 79b7c490 None [DEFAULT] [hasThis] I4 System.Object.GetHashCode()
79b7c52b 79b7c530 None [DEFAULT] [hasThis] Void System.Object.Finalize()
0097506b 00975070 None [DEFAULT] [hasThis] Void flier.EntryPoint.m1()
0097507b 00975080 None [DEFAULT] [hasThis] Void flier.EntryPoint.m2()
0097508b 00975090 None [DEFAULT] Void flier.EntryPoint.Main()
0097509b 009750a0 None [DEFAULT] [hasThis] Void flier.EntryPoint..ctor()




可以看到方法表中共有8個表項,其中前4個已經綁定到使用 ngen 預編譯好的靜態函數上


以下為引用:

0:000> u 79b7c4eb
mscorlib_79980000+0x1fc4eb:
79b7c4eb e8909cfeff call mscorlib_79980000+0x1e6180 (79b66180)
79b7c4f0 0000 add [eax],al
79b7c4f2 0080d86206c0 add [eax+0xc00662d8],al
79b7c4f8 06 push es
79b7c4f9 00fc add ah,bh
79b7c4fb e8809cfeff call mscorlib_79980000+0x1e6180 (79b66180)
79b7c500 07 pop es
79b7c501 0010 add [eax],dl




后四個則作為可被覆蓋的虛方法在方法表中,這也是為什么在查看類型信息時 Vtable Slots = 4 而 Total Method Slots = 8 的原因。

對方法表的每個項目,可以用 !DumpMD 命令查看詳細描述,如


以下為引用:

0:000> !DumpMD 0x00975070
Method Name : [DEFAULT] [hasThis] Void flier.EntryPoint.m1()
MethodTable 9750a8
Module: 14e090
mdToken: 06000001 (D:\Temp\demo.exe)
Flags : 0
IL RVA : 00002050




IL RVA 說明此方法的 IL 代碼相對虛擬地址(IL RVA),也就是說此方法還沒有被 JIT,仍以 IL 代碼形式存在。對于已經完成 JIT 的方法,將顯示其 JIT 后函數體代碼的虛擬地址(Method VA):


以下為引用:

0:000> !DumpMD 0x009750a0
Method Name : [DEFAULT] [hasThis] Void flier.EntryPoint..ctor()
MethodTable 9750a8
Module: 14e090
mdToken: 06000004 (D:\Temp\demo.exe)
Flags : 0
Method VA : 06d900a8





這一階段使用到的 WinDbg 命令如下:


以下為引用:

!dumpobj 04aa1a90 // 查看對象的詳細信息

!dumpclass 0x6c632e8 // 查看類型的詳細信息

!dumpmt -md 0x09750a8 // 查看方法表的詳細信息

!dumpmd 0x00975070 // 查看方法表項的方法描述的詳細信息

u 0x79b7c4eb // 反匯編指定地址的指令





我們反匯編一下 !DumpMT 命令列出的幾個方法,就會發現正如 Don Box 所說,已經被 JIT 的代碼指向一個jmp指令,直接跳轉到編譯后的方法體,如:


以下為引用:

0:000> u 0097509b
0097509b e908b04106 jmp 06d900a8




而沒有被 JIT 的函數,則指向一個call指令,調用一個 prolog 代碼,間接調用 mscorwks!PreStubWorker 函數完成實際 JIT 工作,如:


以下為引用:

0:000> u 0x0097506b
0097506b e878427dff call 001492e8

0:000> u 0x0097507b
0097507b e868427dff call 001492e8




這個 prolog 代碼很簡單,負責構造 mscorwks!PreStubWorker 所需的調用堆棧


以下為引用:

0:000> u 0x001492e8
001492e8 52 push edx
001492e9 68f0301b79 push 0x791b30f0
001492ee 55 push ebp
001492ef 53 push ebx
001492f0 56 push esi
001492f1 57 push edi
001492f2 8d742410 lea esi,[esp+0x10]
001492f6 51 push ecx
001492f7 52 push edx
001492f8 648b1d2c0e0000 mov ebx,fs:[00000e2c]
001492ff 8b7b08 mov edi,[ebx+0x8]
00149302 897e04 mov [esi+0x4],edi
00149305 897308 mov [ebx+0x8],esi
00149308 56 push esi
00149309 e83cd70879 call mscorwks!PreStubWorker (791d6a4a)
0014930e 897b08 mov [ebx+0x8],edi
00149311 894604 mov [esi+0x4],eax
00149314 5a pop edx
00149315 59 pop ecx
00149316 5f pop edi
00149317 5e pop esi
00149318 5b pop ebx
00149319 5d pop ebp
0014931a 83c404 add esp,0x4
0014931d 8f0424 pop [esp]
00149320 c3 ret




而這段 prolog 代碼是由類似 ROTOR 中的 GeneratePrestub 函數(vm\i386\cgenx86.cpp:1829) 動態生成的,完成對 PreStubWorker 函數調用的封裝。而 PreStubWorker 函數會調用 JIT 完成真正的函數編譯工作,并將方法表的入口改為指向編譯后函數體的 jmp 指令。具體的流程請參考Don Box 在《.NET本質論 第1卷:公共語言運行庫》的第六章中的介紹,這里就不再羅嗦了。以后有機會再寫篇文章詳細分析一下 JIT 的工作流程。

在 JIT 處理 flier.EntryPoint.m1 時,用 g 命令執行,再回頭來分析 m1 函數的入口,就會發現如前面所述,調用 JIT 過程的 call 指令變成了直接調用 Native 函數體的 jmp 指令。:D


這一小節,我們介紹了使用 WinDbg 跟蹤調試 CLR 程序的一遍流程,并了解了對堆棧、對象和類信息進行分析的 SOS 命令,希望大家能夠借此開始探索 CLR 內部世界的旅程。 :P

Jason Zander在其 BLog 的一篇文章,SOS Debugging with the CLR (Part 1),里面也詳細介紹了使用 WinDbg 和 SOS 調試 CLR 程序的部分方法,

溫馨提示:喜歡本站的話,請收藏一下本站!

本類教程下載

系統下載排行

国产午夜成人免费看片无遮挡_日本免费xxxx色视频_免费人成网上在线观看_黄网址在线永久免费观看

  • <label id="pxtpz"><meter id="pxtpz"></meter></label>
      1. <span id="pxtpz"><optgroup id="pxtpz"></optgroup></span>

        欧美哺乳videos| 国产精品视频免费看| 高清不卡在线观看| 国产精品自在欧美一区| 色综合天天综合| 欧美日韩国产高清一区二区三区 | 中文字幕精品—区二区四季| 亚洲精品国产a久久久久久| 日本vs亚洲vs韩国一区三区二区 | 国产九九视频一区二区三区| 91视频一区二区三区| 欧美性猛交xxxxxx富婆| 精品欧美一区二区在线观看| 中文字幕永久在线不卡| 蜜桃一区二区三区四区| 色88888久久久久久影院野外| 精品久久久久香蕉网| 亚洲成国产人片在线观看| 国产成人日日夜夜| 欧美一区二区三区在线视频| 一区二区三区日本| 成人国产亚洲欧美成人综合网| 91精品国产综合久久久蜜臀图片| 综合电影一区二区三区 | 欧美三级一区二区| 国产精品萝li| 久久99精品网久久| 欧美日韩亚洲综合一区二区三区| 国产欧美一区二区在线| 国内精品视频666| 欧美一区二区免费视频| 一区二区三区四区蜜桃| 91在线精品一区二区三区| 久久久亚洲午夜电影| 日本美女视频一区二区| 欧美日韩一区三区四区| 亚洲高清免费在线| 欧美亚洲日本国产| 亚洲一区视频在线| 色综合视频一区二区三区高清| 欧美国产日韩精品免费观看| 国产成人亚洲精品青草天美| 国产日韩欧美高清在线| 成人美女在线观看| 国产精品入口麻豆原神| 懂色av一区二区在线播放| 久久久久9999亚洲精品| 国产精品一二二区| 欧美国产精品中文字幕| 成人黄色小视频在线观看| 国产精品视频一二| 99国产精品99久久久久久| 亚洲三级视频在线观看| 色婷婷综合在线| 日韩专区一卡二卡| 精品久久国产97色综合| 久久99精品一区二区三区 | 久久久精品免费免费| 免费久久99精品国产| 欧美一区二区三区播放老司机| 老司机一区二区| 久久综合色之久久综合| www.亚洲色图.com| 亚洲国产精品久久不卡毛片 | 欧美综合天天夜夜久久| 午夜久久电影网| 日韩欧美一级精品久久| 国产精品亚洲第一| 亚洲美女视频一区| 欧美一区二区三区白人| 国产一区二区免费看| 国产精品短视频| 欧美日韩中文另类| 国产一区二区0| 亚洲精品国久久99热| 日韩午夜在线观看| 成人av资源在线| 日本麻豆一区二区三区视频| 久久九九久久九九| 欧美午夜片在线看| 国产精品一区二区无线| 亚洲一区二区三区国产| 久久亚洲精华国产精华液| 日本久久电影网| 久久91精品国产91久久小草| 亚洲欧美日韩电影| 国产欧美一区视频| 日韩免费观看高清完整版| 91丨porny丨国产| 国产一本一道久久香蕉| 午夜电影一区二区三区| 中文字幕一区二区三区色视频| 777午夜精品免费视频| 91在线精品一区二区三区| 国产美女av一区二区三区| 亚洲国产aⅴ天堂久久| 中文字幕中文字幕一区| 欧美精品一区男女天堂| 欧美日韩免费视频| 日本韩国一区二区三区视频| 高清不卡一二三区| 国产一区在线观看视频| 麻豆成人av在线| 午夜精品福利一区二区蜜股av | 91一区一区三区| 九色|91porny| 秋霞电影一区二区| 亚洲福利电影网| 一区二区三区四区亚洲| 欧美激情一区在线观看| 26uuu色噜噜精品一区| 91精品国产色综合久久| 91精品国产手机| 51午夜精品国产| 91精品国产乱| 制服丝袜一区二区三区| 在线成人小视频| 欧美一二三四在线| 欧美v日韩v国产v| 日韩三级电影网址| 日韩精品最新网址| 欧美大白屁股肥臀xxxxxx| 91精品福利在线一区二区三区| 欧美精品国产精品| 日韩一区二区免费在线电影| 欧美电影免费提供在线观看| 久久麻豆一区二区| 国产亚洲一区二区三区在线观看| xfplay精品久久| 国产精品免费av| 一区二区欧美在线观看| 亚洲制服丝袜av| 免费视频最近日韩| 激情欧美日韩一区二区| 国产+成+人+亚洲欧洲自线| 色综合久久中文字幕综合网| 欧美日韩黄色影视| 精品成人免费观看| 亚洲日本欧美天堂| 蜜桃视频一区二区| 成人性生交大片免费看视频在线 | 国产成人精品免费网站| 色综合久久久久综合99| 91精品视频网| 日本一区二区三区免费乱视频| 亚洲免费毛片网站| 麻豆91免费看| 91尤物视频在线观看| 欧美猛男男办公室激情| 久久精品亚洲精品国产欧美kt∨ | 欧美日韩午夜在线| 久久久精品综合| 夜夜嗨av一区二区三区中文字幕 | 在线观看日韩电影| 久久亚区不卡日本| 亚洲国产wwwccc36天堂| 国产精品综合在线视频| 欧美影院精品一区| 日本一区二区久久| 蜜桃在线一区二区三区| 99精品国产99久久久久久白柏| 日韩一区二区精品葵司在线| 国产精品久久久久aaaa樱花 | 色欧美日韩亚洲| 国产欧美1区2区3区| 免费观看30秒视频久久| 色猫猫国产区一区二在线视频| 2021国产精品久久精品| 午夜精品久久一牛影视| 色天使久久综合网天天| 日本一区二区三区在线观看| 免费高清不卡av| 欧美剧在线免费观看网站| 亚洲色图制服丝袜| 成人综合日日夜夜| 久久美女艺术照精彩视频福利播放| 视频一区免费在线观看| 91在线小视频| **网站欧美大片在线观看| 精品一区二区三区免费播放| 欧美日韩精品欧美日韩精品一综合| 中文字幕视频一区二区三区久| 国产精品一区二区三区四区| 欧美tk—视频vk| 蜜臀av亚洲一区中文字幕| 欧美系列亚洲系列| 一区二区三国产精华液| 色88888久久久久久影院按摩 | 国模套图日韩精品一区二区 | 亚洲婷婷国产精品电影人久久| 国产一区不卡在线| 国产天堂亚洲国产碰碰| 国产一本一道久久香蕉| 久久久www免费人成精品| 国产一区91精品张津瑜| 久久综合色综合88| 成人av免费网站| 一区二区三区四区不卡在线 | 激情综合色播五月| 精品国产乱码久久久久久久久 |