zoukankan      html  css  js  c++  java
  • 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寄存器里面去。

    后记:关于动态调试托管代码,我也是刚接触不久,上面有不准确的地方,欢迎大家多多指正

  • 相关阅读:
    【今日CS 视觉论文速览】4 Jan 2019
    【今日CS 视觉论文速览】3 Jan 2019
    【今日CS 视觉论文速览】1 Jan 2019
    【机器学习】混淆矩阵及其绘制
    【Vim】批量插入注释符号
    【今日CS 视觉论文速览】31 Dec 2018
    【深度学习风格化/生成艺术】图像融合--毫无违和
    CSDN的一些年度大牛(2018)
    【今日CS 视觉论文速览】 27 Dec 2018
    python与机器视觉(X)打包为exe可执行文件
  • 原文地址:https://www.cnblogs.com/zengkefu/p/6938186.html
Copyright © 2011-2022 走看看