CLR探索系列:Windbg+SOS动态调试分析托管代码
http://blog.csdn.net/garyye/article/details/4788070
??
在使用VS進行托管應用程序的調試的時候,有的時候總感覺有些力不從心。譬如查看一個托管堆或者計算堆棧的時候,VS就不能勝任了。這個時候,Windbg+SOS擴展調試模塊就為我們提供了一個很好的解決方案。
我們看一段代碼:
class Program
??? {
??????? static void Main(string[] args)
??????? {
??????????? Program b = new Program();
??????????? b.test();
??????????? System.Console.ReadLine();
??????? }
??????? public void test()
??????? {
??????????? int i = 67;
??????????? System.Console.WriteLine((char)i);
??????????? System.Console.WriteLine((char)67);
??????????? i = 1;
??????? }
??? }
這是C#里面的一個強制類型轉換,我們現在用windbg+SOS來分析下計算堆棧,以及強制類型轉換之后的JIT代碼。
在windbg里面加載這個正在運行的程序,attach to this process,然后加載SOS擴展調試模塊:
0:003> .load C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/SOS.dll
然后顯示當前的線程:
0:003> ~
?? 0? Id: cf0.450 Suspend: 1 Teb: 7ffdf000 Unfrozen
?? 1? Id: cf0.be8 Suspend: 1 Teb: 7ffdd000 Unfrozen
?? 2? Id: cf0.168 Suspend: 1 Teb: 7ffdc000 Unfrozen
.? 3? Id: cf0.7d0 Suspend: 1 Teb: 7ffde000 Unfrozen
切換到第0個線程:
0:003> ~0s
eax=0012f2e4 ebx=00000000 ecx=0012f400 edx=00000008 esi=0012f1f4 edi=00250688
eip=7c92eb94 esp=0012f194 ebp=0012f1b4 iopl=0???????? nv up ei pl zr na pe nc
cs=001b? ss=0023? ds=0023? es=0023? fs=003b? gs=0000???????????? efl=00000246
ntdll!KiFastSystemCallRet:
7c92eb94 c3????????????? ret
顯示test方法相關的地址:
0:000> !name2ee TestConcoleApp.exe TestConcoleApp.Program.test
Module: 00ab2c24 (TestConcoleApp.exe)
Token: 0x06000002
MethodDesc: 00ab2ff0
Name: TestConcoleApp.Program.test()
JITTED Code Address: 00d000f8
顯示這個方法被C#編譯器編譯之后的IL代碼:
0:000> !dumpil 00ab2ff0
ilAddr = 00402074
IL_0000: nop?
IL_0001: ldc.i4.s 67
IL_0003: stloc.0?
IL_0004: ldloc.0?
IL_0005: conv.u2?
IL_0006: call System.Console::WriteLine?
IL_000b: nop?
IL_000c: ldc.i4.s 67
IL_000e: call System.Console::WriteLine?
IL_0013: nop?
IL_0014: ldc.i4.1?
IL_0015: stloc.0?
IL_0016: ret?
這里,sandwi對conv.u2這條指令一直困惑良多。我也對這個問題困惑了好久,翻閱了很多資料也沒找到,后來準備在sscli的C#編譯器里面找到答案,不過沒找到地方......
后來被證實,這條指令是C#編譯器為了類型安全,而生成的一條指令。作用在于把一個integer轉換稱為一個unsigned int16,然后前面補0成為int32壓入堆棧里面去。
這是一個語言編譯器行為,為了證實這個想法,同時寫了一段同樣的VB代碼來證實我們的想法:
Module Module1
??? Sub Main()
??????? Dim i As Integer
??????? i = 67
??????? System.Console.WriteLine(Chr(i))
??????? System.Console.WriteLine(Chr(67))
??????? System.Console.ReadLine()
??? End Sub
???
End Module
編譯之后的IL代碼也同樣支持上面的想法。
這里,感謝微軟的張翼證實了我關于conv.u2的存在原因的猜想。但是,zhangyi說在test方法中的conv.u2指令在JIT生成的本地代碼中被優化掉了,我卻不同意這種看法:
0:000> !u 00d000f8
這條指令,是顯示JIT編譯了的test方法的本地代碼,根據
JITTED Code Address: 00d000f8
這一行得來的。顯示結果如下:
Normal JIT generated code
TestConcoleApp.Program.test()
push??????????esi
push??????????eax
mov?????? ? ?dword ptr [esp],ecx
cmp??????? ? dword ptr ds:[0AB2DD8h],0
je??????????????00d0010b? (跳到xor? esi,esi這里)
call??????????? mscorwks!CorLaunchApplication+0x108b4 (7a08e179)?
xor??????? ??? esi,esi
nop
mov?????????? esi,43h
movzx??? ?? ecx,si
call????????? ??mscorlib_ni+0x2f8b9c (793b8b9c) (System.Console.WriteLine(Char), mdToken: 06000759)
nop
mov?????????? ecx,43h
call???????? ?? mscorlib_ni+0x2f8b9c (793b8b9c) (System.Console.WriteLine(Char), mdToken: 06000759)
nop
mov??????? ?? esi,1
pop????????? ? ecx
pop?????? ? ? ?esi
ret
這里,movzx?? ecx,si這條指令就對應了IL代碼里面的Conv.u2,把對應的int前面補0放入到ecx寄存器里面去。
后記:關于動態調試托管代碼,我也是剛接觸不久,上面有不準確的地方,歡迎大家多多指正
轉載于:https://www.cnblogs.com/zengkefu/p/6938186.html
總結
以上是生活随笔為你收集整理的CLR探索系列:Windbg+SOS动态调试分析托管代码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 英语U校园班级测试,有一题不会,在线问答
- 下一篇: python 统计文件夹各类格式文件数量