首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

在托管代码中设置断点(Windbg)

Posted on 2009-04-11 00:03  饭后爱  阅读(1768)  评论(0编辑  收藏  举报

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”

 

“g”Debugger会停在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

 

 

 

 

 

 

 

 2004428 9:24 - (阅读:2567;评论:6)

 

反馈

# 回复: 在托管代码中设置断点(WINDBG) 2004-4-28 12:30 Flier Lu

太好了,呵呵,前两天还在琢磨着怎么写个插件实现 bp 命令直接给函数下断点呢 :D

 

# 回复: 在托管代码中设置断点(WINDBG) 2004-5-1 12:45 chiv_BJ

问一下,你有Shared source CLI Essential, by Stutz David,

这本书 电子版吗?

 

# re: 在托管代码中设置断点(WINDBG) 2004-9-13 15:19 twinsant

Is mscorlib_dll!System.Console.WriteLine managed code?

 

I did think it is native code.

 

# re: 在托管代码中设置断点(WINDBG) 2004-9-14 11:51 Peng Gang

It is prejitted code for mscorlib.dll (native). Note the format was changed, so you might see something like:

mscorlib_ni!System.Console.WriteLine

 

# re: 在托管代码中设置断点(WINDBG) 2005-4-25 2:00 尖锐湿疣

Thank YOu!

 

# 使用WindbgSoS扩展调试分析.NET程序 2006-12-23 0:30 自由、创新、研究、探索……

在博客堂的不是我舍不得-HighCPUinGC(都是 =惹的祸,为啥不用StringBuilder呢?)、不是我舍不得-.NET里面的OutOfMemory看到很多人在问如何分析...