CLR中执行的托管代码分为Jitted 代码和ngened代码。区Jitted代码是动态编译生成的而ngened代码是预编译生成的。本文将讲述使用Windbg在这两种不同的代码中设置断点的方法。本文将使用如下的例子进行说明:

using System;

public class Test {

    public static void Main() {

        Console.WriteLine("Test");

    }

}

编译上面的代码生成test.exe

 

Jitted代码(Test.Main

 

同一个托管方法的Jitted代码地址并不固定,所以在托管方法中设置断点较麻烦。托管方法对应的CLR数据结构是MethodDescMethodDesc中有一个变量DWORD_PTR m_CodeOrIL储存Jitted代码地址(编译后)或IL相对地址(编译后)。JIT在编译一个方法后会改变该变量的值。下面是设置断点的步骤:

 

(1)       mscorjitJIT Engine)设置模块加载断点:“sxe ld:mscorjit.dll”。然后输入输入g命令。

(2)       载入sos,“.loadby sos mscorwks”。

(3)       查找Test.MainMethodDesc:“!name2ee test.exe Test.Main”.

MethodDesc: 975070

Name: [DEFAULT] Void test.Main()

(4)        在该MethodDescm_CodeOrIL域(MethodDesc的地址加4)上设置一个内存断点:

       ba w4 975070+0x04 "bp poi(975070+0x04);g"

上面的断点的意思是在m_CodeOrIL被改变后在m_CodeOrIL中存储的地址上设置代码断点并继续执行。

(5)        Debugger会停在Test.Main的入口处。输入!clrstack

ESP       EIP    

0012f6ac  06cb0058 [DEFAULT] Void test.Main()

  at [+0x0] [+0x0] g:\t.cs:7

0012f9b0  791da717 [FRAME: GCFrame]

0012fa94  791da717 [FRAME: GCFrame]

 

Ngened代码

 

如果执行的方法是预编译过(关于细节请参阅关于ngen的文章),它的地址将是固定的,所以只需要找出该地址一次。假设我们想调试Console.WriteLine,可以使用如下的步骤来设置断点:

(1)      windbg test.exe

(2)       输入g命令。Debugger会停在进程结束(process termination)断点处。

(3)       载入sos.loadby sos mscorwks”。

(4)       输入“!name2ee mscorlib.dll System.Console.WriteLine”。Debugger会显示Console.WriteLine的所有Overloads。我们感兴趣的是:

MethodDesc: 79bb96b8

Name: [DEFAULT] Void System.Console.WriteLine(String)

(5)       显示该方法的信息:

   !DumpMD 79bb96b8

    Method Name : [DEFAULT] Void System.Console.WriteLine(String)

    MethodTable 79bb92a0

    Module: 79b66000

    mdToken: 0600051a (c:\windows.0\microsoft.net\framework\v1.1.4322\mscorlib.dll)

    Flags : 8010

    Method VA : 799f91b8

(6)      windbg test.exe

(7)       mscorlibConsole.WriteLine所在模块)设置模块加载断点。“sxe ld:mscorlib.dll.

(8)       输入g命令两次。注意对于预编译的AssemblyCLR会先载入IL Assembly,然后在载入Ngened Image。这是为什么要“g”两次的原因。在Debugger中应当有如下的输出:

ModLoad: 79780000 79980000   c:\windows.0\microsoft.net\framework\v1.1.4322\mscorlib.dll

ModLoad: 79980000 79ca6000  

c:\windows\assembly\nativeimages1_v1.1.4322\mscorlib\1.0.5000.0__b77a5c561934e089_a6cf3080\mscorlib.dll

(9)       Ngened Image被加载后,可以直接在以前得到的地址上设置断点:“bp 799f91b8

gDebugger会停在Console.WriteLine的入口处。输入!clrstack

       Thread 0

ESP       EIP    

0012f6a4  799f91b8 [DEFAULT] Void System.Console.WriteLine(String)

0012f6a8  06cb0067 [DEFAULT] Void Test.Main()

  at [+0xf] [+0xa] g:\t.cs:8

0012f9b0  791da717 [FRAME: GCFrame]

0012fa94  791da717 [FRAME: GCFrame]

 

 

WindbgCLR Whidbey的支持更强。K会直接显示托管方法名。Bp可以直接支持托管方法:bp mscorlib_dll!System.ConsoleWriteLine