调试、调试、调试...
A. 如何在Visual Studio 2005中对托管代码及非托管的CLR环境同时进行调试?
步骤远比你想象的简单,而且更重要的是比windbg方便。举例:
1. | 开启一个C#的项目,打开该项目的属性窗口 |
2. | 将Debug页面中的Enable Unmanaged Code Debugging选中 |
3. | 在某语句处设置好断点,F5重新编译,运行,命中断点 |
4. | 打开Immediate窗口,输入!Load sos.dll加载CLR调试扩展(这个sos.dll是.NET Framework 2.0 SDK自带的) |
5. | 然后在Immediate窗口里开始愉快的!DumpStackObjects、!DumpClass、!DumpMT,一窥CLR内部堂奥吧。!Help是帮助 |
6. | 使用这种方式,对于托管代码的调试跟平时并没有啥区别 |
B. 可以使用Visual Studio 2005来调试Rotor 2.0编译的托管代码吗?
不行。Rotor对托管代码调试支持不全,只能使用其自带的cordbg来进行调试(无意中发现Rotor自带的cordbg版本号居然比SDK 2.0的还要高,一个是2.0.50826,一个是2.0.50727 RTM....-_-b)
C. 可以使用Visual Studio 2005来跟踪和调试非托管的Rotor代码吗?
虽然不能直接用vs2005来调试Rotor编译的托管代码,但是,调试Rotor本身却是可以的!步骤也不是很复杂:
1. | 用记事本编辑Rotor编译所得的sos.dll.manifest文件(例如d:\Rotor2\binaries.x86chk.Rotor\sos.dll.manifest) |
2. |
copy其中<dependency>...</dependency>部分内容,将其paste进C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\devenv.exe.manifest文件的<assembly>一节当中,保存之 |
3. | 假设某Rotor2下编译的托管测试文件的全路径名为d:\Rotor2\samples\hello.exe |
4. | Rotor控制台下输入"devenv /debugexe clix d:\Rotor2\samples\hello.exe",启动vs2005,加载clix |
5. | F5启动,稍等几秒钟,确信Rotor的运行时环境已启动,然后按Ctrl-Alt-Break抢占中断clix执行 |
6. | 打开Immediate窗口,输入!Load d:\Rotor2\binaries.x86chk.Rotor\sos.dll,加载Rotor自己编译生成的CLR调试扩展 |
7. | 好戏开始了!快单步跟踪、输入>cmd / !threads / !dumpstack试试看吧! |
D. "稍等几秒钟,确信Rotor的运行时环境已启动,再按Ctrl-Alt-Break抢占中断其执行"是啥意思?
意思就是说,在调试Rotor时,如何合理、适时地设置断点是关键。为了简单起见,可以在上述那个简单示例中使用一条Console.ReadLine语句暂时锁死流程的执行,启动后稍等一会儿再按Ctrl-Alt-Break返回调试器,这样我们便能保证中断时Rotor的运行时环境已经完成加载了。
或者更专业一点,还可以通过设置环境变量来启动Rotor的辅助调试机制,如COMPlus_BreakOnEELoad、COMPlus_JitBreak等,这比“猜测式断点”更准确、更方便,这里就不多说了,请进一步参考Rotor自带的调试文档,里面说得很详细。
参考文献:
[1] Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects, MSDN Magazine, May 2005
[2] SOS: It's Not Just an ABBA Song Anymore, MSDN Magazine, MSDN Magazine, Jun. 2003
[3] SOS Debugging with the CLR, Jason Zander's Blog, Oct. 2003