lep*_*pie 134 .net debugging clr visual-studio-2010 visual-studio
首先,我为这个问题的长度道歉.
我是IronScheme的作者.最近我一直在努力发出不错的调试信息,以便我可以使用'native'.NET调试器.
虽然这部分成功,但我遇到了一些问题.
第一个问题与踩踏有关.
由于Scheme是一种表达式语言,一切都倾向于用括号括起来,不像主要的.NET语言似乎是基于语句(或行).
原始代码(Scheme)看起来像:
(define (baz x)
(cond
[(null? x)
x]
[(pair? x)
(car x)]
[else
(assertion-violation #f "nooo" x)]))
Run Code Online (Sandbox Code Playgroud)
我故意在换行符上列出每个表达式.
发出的代码转换为C#(通过ILSpy),如下所示:
public static object ::baz(object x)
{
if (x == null)
{
return x;
}
if (x is Cons)
{
return Builtins.Car(x);
}
return #.ironscheme.exceptions::assertion-violation+(
RuntimeHelpers.False, "nooo", Builtins.List(x));
}
Run Code Online (Sandbox Code Playgroud)
如你所见,非常简单.
注意:如果代码在C#中转换为条件表达式(?:),那么整个过程只需要一个调试步骤,请记住这一点.
这是带有源和行号的IL输出:
.method public static object '::baz'(object x) cil managed
{
// Code size 56 (0x38)
.maxstack 6
.line 15,15 : 1,2 ''
//000014:
//000015: (define (baz x)
IL_0000: nop
.line 17,17 : 6,15 ''
//000016: (cond
//000017: [(null? x)
IL_0001: ldarg.0
IL_0002: brtrue IL_0009
.line 18,18 : 7,8 ''
//000018: x]
IL_0007: ldarg.0
IL_0008: ret
.line 19,19 : 6,15 ''
//000019: [(pair? x)
.line 19,19 : 6,15 ''
IL_0009: ldarg.0
IL_000a: isinst [IronScheme]IronScheme.Runtime.Cons
IL_000f: ldnull
IL_0010: cgt.un
IL_0012: brfalse IL_0020
IL_0017: ldarg.0
.line 20,20 : 7,14 ''
//000020: (car x)]
IL_0018: tail.
IL_001a: call object [IronScheme]IronScheme.Runtime.Builtins::Car(object)
IL_001f: ret
IL_0020: ldsfld object
[Microsoft.Scripting]Microsoft.Scripting.RuntimeHelpers::False
IL_0025: ldstr "nooo"
IL_002a: ldarg.0
IL_002b: call object [IronScheme]IronScheme.Runtime.Builtins::List(object)
.line 22,22 : 7,40 ''
//000021: [else
//000022: (assertion-violation #f "nooo" x)]))
IL_0030: tail.
IL_0032: call object [ironscheme.boot]#::
'ironscheme.exceptions::assertion-violation+'(object,object,object)
IL_0037: ret
} // end of method 'eval-core(033)'::'::baz'
Run Code Online (Sandbox Code Playgroud)
注意:为了防止调试器只是突出显示整个方法,我将方法入口点设为1列宽.
如您所见,每个表达式都正确映射到一条线.
现在步进的问题(在VS2010上测试,但VS2008上的相同/类似问题):
这些都IgnoreSymbolStoreSequencePoints没有应用.
申请时IgnoreSymbolStoreSequencePoints(按照建议):
我还发现在这种模式下,某些线条(此处未显示)未正确突出显示,它们偏离1.
以下是一些可能是原因的想法:
第二个也是严重的问题是调试器在某些情况下无法中断/命中断点.
我可以让调试器正确(和一致地)中断的唯一地方是方法入口点.
如果IgnoreSymbolStoreSequencePoints不应用,情况会好一些.
结论
可能是VS调试器只是普通的错误:(
参考文献:
更新1:
Mdbg不适用于64位程序集.这样就出来了.我没有更多的32位机器来测试它.更新:我相信这不是什么大问题,有人有修复吗?编辑:是的,傻我,只需在x64命令提示符下启动mdbg :)
更新2:
我创建了一个C#应用程序,并尝试剖析行信息.
我的发现:
brXXX指令之后你需要有一个序列点(如果无效,又称'#line hidden',则发出一个nop).brXXX指令之前,发出'#line hidden'和a nop.然而,应用此功能并不能解决问题(单独?).
但添加以下内容,给出了预期的结果:)
ret,发出'#line hidden'和a nop.这是使用IgnoreSymbolStoreSequencePoints未应用的模式.应用时,仍会跳过某些步骤:(
以下是应用以上时的IL输出:
.method public static object '::baz'(object x) cil managed
{
// Code size 63 (0x3f)
.maxstack 6
.line 15,15 : 1,2 ''
IL_0000: nop
.line 17,17 : 6,15 ''
IL_0001: ldarg.0
.line 16707566,16707566 : 0,0 ''
IL_0002: nop
IL_0003: brtrue IL_000c
.line 16707566,16707566 : 0,0 ''
IL_0008: nop
.line 18,18 : 7,8 ''
IL_0009: ldarg.0
IL_000a: ret
.line 16707566,16707566 : 0,0 ''
IL_000b: nop
.line 19,19 : 6,15 ''
.line 19,19 : 6,15 ''
IL_000c: ldarg.0
IL_000d: isinst [IronScheme]IronScheme.Runtime.Cons
IL_0012: ldnull
IL_0013: cgt.un
.line 16707566,16707566 : 0,0 ''
IL_0015: nop
IL_0016: brfalse IL_0026
.line 16707566,16707566 : 0,0 ''
IL_001b: nop
IL_001c: ldarg.0
.line 20,20 : 7,14 ''
IL_001d: tail.
IL_001f: call object [IronScheme]IronScheme.Runtime.Builtins::Car(object)
IL_0024: ret
.line 16707566,16707566 : 0,0 ''
IL_0025: nop
IL_0026: ldsfld object
[Microsoft.Scripting]Microsoft.Scripting.RuntimeHelpers::False
IL_002b: ldstr "nooo"
IL_0030: ldarg.0
IL_0031: call object [IronScheme]IronScheme.Runtime.Builtins::List(object)
.line 22,22 : 7,40 ''
IL_0036: tail.
IL_0038: call object [ironscheme.boot]#::
'ironscheme.exceptions::assertion-violation+'(object,object,object)
IL_003d: ret
.line 16707566,16707566 : 0,0 ''
IL_003e: nop
} // end of method 'eval-core(033)'::'::baz'
Run Code Online (Sandbox Code Playgroud)
更新3:
以上'半修复'的问题.Peverify报告由于nopafter 而导致的所有方法的错误ret.我真的不明白这个问题.怎么可以nop在a之后进行中断验证ret.它就像死代码(除了它甚至不是代码)......哦,实验继续.
更新4:
现在回到家里,删除了在VS2008上运行的'无法验证的'代码,事情变得更糟.也许为了正确调试而运行无法验证的代码可能就是答案.在'release'模式下,所有输出仍然可以验证.
更新5:
我现在已经确定我的上述想法是目前唯一可行的选择.虽然生成的代码无法验证,但我还没有找到任何代码VerificationException.我不知道这种情况对最终用户有什么影响.
作为奖励,我的第二个问题也得到了解决.:)
这是我最终得到的一个小小的截屏视频.它可以击中断点,进行适当的步进(进/出/结束)等等.总而言之,它可以达到预期的效果.
但是,我仍然不接受这样做.对我来说,我觉得过于苛刻.确认真正的问题会很好.
更新6:
刚刚对VS2010上的代码进行了测试,似乎存在一些问题:
这两种情况在VS2008下都能正常工作.主要的区别是在VS2010下,整个应用程序是针对.NET 4编译的,在VS2008下,编译为.NET 2.两者都运行64位.
更新7:
就像提到的那样,我让mdbg在64位下运行.不幸的是,它还有断点问题,如果我重新运行程序它不会破坏(这意味着它被重新编译,所以不使用相同的程序集,但仍使用相同的源).
更新8:
我在MS Connect网站上提交了有关断点问题的错误.
更新:已修复
更新9:
经过一番漫长的思考,使调试器开心的唯一方法似乎是做SSA,所以每一步都可以是隔离的和顺序的.我还是要证明这个概念.但这看似合乎逻辑.显然,从SSA清除临时值会破坏调试,但这很容易切换,留下它们没有太多开销.
Luk*_*Kim 26
我是Visual Studio Debugger团队的工程师.
如果我错了,请纠正我,但听起来唯一的问题是当从PDB切换到.NET 4动态编译符号格式时,一些断点正在被遗漏.
我们可能需要一个repro来准确诊断问题,但是这里有一些可能有用的注释.
JIT基于以下规则创建隐式序列点:1.IL nop指令2. IL堆栈空点3.紧接着调用指令的IL指令
如果事实证明我们确实需要一个repro来解决您的问题,您可以提交连接错误并通过该媒介安全地上传文件.
更新:
我们鼓励遇到此问题的其他用户从http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=27543尝试Dev11的开发者预览版并对任何反馈发表评论.(必须以4.5为目标)
更新2:
Leppie已经在http://www.microsoft.com/visualstudio/11/en-us/downloads上的Dev11 Beta版本上验证了为他工作的修复程序,如连接错误https://connect.microsoft中所述. com/VisualStudio/feedback/details/684089 /.
谢谢,
卢克
| 归档时间: |
|
| 查看次数: |
3703 次 |
| 最近记录: |