Cui*_*崔鹏飞 16 .net c# debugging breakpoints visual-studio
一个奇怪的Visual Studio 2010调试器案例(它无法达到一个断点)
这是重现问题的代码:
class Program {
static void Main(string[] args) {
bool b = false;
if (b) {
List<string> list = new List<string>();
foreach (var item in list) {
}
} else {
Console.WriteLine("1");
}
Console.WriteLine("2");//add a break point here in VS2010
}
//1. configuration: release
//2. platform target: x64 or Any Cpu
//3. debug info: pdb only or full
//4. OS: Win7 x64
//5. optimize code: enabled
}
Run Code Online (Sandbox Code Playgroud)
在代码的最后一个语句中添加一个断点,然后在vs2010中调试它,你会看到无法命中断点.
要重现这个奇怪的情况,您需要满足以下条件:
我不确定这些条件是否足以重现它,但是当我发现这个问题时,这就是我的机器的配置方式.
为什么调试器无法达到断点?
提前致谢!
Den*_*nis 11
当提供的示例在发布模式下构建然后JIT编译为64位机器代码时,它不包含足够的信息供调试器将断点与任何特定的机器指令相关联.这就是为什么调试器在执行JIT-ed机器代码期间永远不会在此断点处停止的原因.它只是不知道在哪里停下来.可能是64位CLR调试器中存在某种不当行为甚至是错误,因为只有当它被JIT转换为64位机器代码而不能转换为32位机器代码时才可以重现.
当调试器在代码中看到断点时,它会尝试在JIT编码中找到与断点标记的位置对应的机器指令.首先,它需要找到与C#代码中的断点位置相对应的IL指令.然后,它需要找到与IL命令对应的机器指令.然后它在找到的机器指令上设置一个真正的断点并开始执行该方法.在您的情况下,看起来调试器只是忽略断点,因为它无法将其映射到特定的机器指令.
调试器找不到紧跟在if语句之后的机器指令的地址.if ... else语句及其中的代码以某种方式导致此行为.if ... else后跟哪个语句无关紧要.您可以将Console.WriteLine("2")语句替换为其他语句,您仍然可以重现该问题.
您将看到C#编译器在读取列表的逻辑周围发出try ... catch块,如果您将使用Reflector反汇编生成的程序集.它是C#编译器的文档功能.您可以在foreach声明中阅读更多相关信息
尝试... catch ... finally块对JIT编码有很大的侵入性.它使用引擎盖下的Windows SEH机制并严重重写您的代码.我现在找不到一篇好文章的链接,但我相信如果你有兴趣,你可以在那里找到一个.
这就是这里发生的事情.if ... else语句中的try ... finally块导致调试器打嗝.您可以使用非常简单的代码重现您的问题.
bool b = false;
if (b)
{
try
{
b = true;
}
finally
{
b = true;
}
}
else
{
b = true;
}
b = true;
Run Code Online (Sandbox Code Playgroud)
此代码不调用任何外部函数(它消除了其中一个答案提出的方法内联的影响),并且它直接编译到IL中,而不需要C#编译器添加任何其他编码.
它只能在发布模式下重现,因为在调试模式下,编译器会为C#代码的每一行发出IL NOP指令.IL NOP指令不执行任何操作,它由JITer直接编译为CPU NOP指令,它也不执行任何操作.该指令的用处在于它可以被调试器用作断点的锚点,即使其余的代码被JITer严重重写也是如此.
通过在if ... else之后的语句之前放置一条NOP指令,我能够使调试器正常工作.
你可以阅读更多关于NOP操作和调试映射过程在这里调试IL
您可以尝试使用WinDbg和SOS扩展来检查方法的JIT版本.您可以尝试检查JIT-er生成的机器代码,并尝试理解为什么它无法将该机器代码映射回特定的C#行.
以下是关于使用WinDbg打破托管代码并获取JIT-ed方法的内存地址的几个链接.我相信你应该能够找到一种从那里获取方法的JIT代码的方法:在WinDbg中为托管代码设置断点,SOS备忘单(.NET 2.0/3.0/3.5).
您还可以尝试向Microsoft报告问题.可能这是一个CLR调试器错误.
谢谢你提出这个有趣的问题.
归档时间: |
|
查看次数: |
7019 次 |
最近记录: |