【问题标题】:Debugger shows invalid instruction调试器显示无效指令
【发布时间】:2013-05-23 10:10:24
【问题描述】:

有时,Visual Studio 调试器会显示无效的当前指令。最简单的可能原因是:

  • 过时的 .pdb 文件。这些文件包含有关二进制文件的哪个偏移量对应于哪一行代码的信息。如果这些文件已经过时,显然调试器会显示无效行。
  • 在发布模式而不是调试模式下编译的程序。发布模式通常会开启优化,以便优化器可以将代码修改得更快(或更小)。在这种情况下,二进制文件不再对应源代码,因此调试器无法显示实际执行的行。

但我的情况不同。这是一段源代码(C#):

if (match.Groups.Count != 4)
    throw new InvalidOperationException("Internal error: Invalid regular expression!");

MyEnum myEnum;
try
{
    // (...)

我调试了源代码。调试器在条件语句处停止并显示match.Groups.Count 实际上等于 4。显然,应该跳过 throw 语句,但令人惊讶的是,并没有。但是,在“执行”throw 语句之后,调试器转到下一个有效语句并继续按预期执行。

发生了什么?

【问题讨论】:

  • 仅供参考:当您要回答自己的问题时,显示屏底部附近有一个“回答您自己的问题”复选框。我认为这会阻止人们介入并回答它。
  • 是的,我忘记了 :) 谢谢。

标签: c# visual-studio debugging compiler-construction


【解决方案1】:

在这种情况下,通常值得查看反汇编。就我而言,它看起来像:

    if (match.Groups.Count != 4)

00000344  mov         rax,qword ptr [rbp+30h] 
00000348  mov         rax,qword ptr [rax] 
(...)
00000399  test        eax,eax 
0000039b  jne         00000000000003ED // (1)

    throw new InvalidOperationException("Internal error: Invalid regular expression!");

0000039d  lea         rdx,[00049AC0h] 
000003a4  mov         ecx,7000024Eh 
000003a9  call        000000005F7CC994 
(...)
000003dc  call        000000005ED32730 
000003e1  mov         rcx,qword ptr [rbp+000000F8h] 
000003e8  call        000000005F7CC64C 
000003ed  nop // (2)

    MyEnum myEnum;
    try
    {

000003ee  nop // (3)

我在jne 指令 (1) 处设置断点。对于那些不太了解汇编程序的人(我实际上并不了解),条件语句通常编译成一对:test 和某种条件跳转,例如jne (jump if not equal)。所以我设置断点的地方实际上是一个最终决定,是否执行 throw 语句。

在跳过 (F10) 之后,调试器跳转到 (2) 位置,因此它正确地跳过了 throw 语句。对于那些不知道这一点的人来说,nop (No operation) 是一个汇编指令,它实际上什么都不做。编译器通常使用它来对齐汇编代码,使其性能更好(我猜是低级处理器的东西)。

但是编译器搞砸了并将信息保存在 .pdb 文件中,提到nopthrow 语句的一部分。调试器读取它并将当前指令标记定位在throw 语句上。但是,它只是执行它(什么也没做)并继续执行,因为实际的汇编代码是正确的。

我留下这个例子,以防有人发现自己遇到了类似的问题 - 希望它有助于找到原因。比较少见,但谁知道呢?...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-24
    • 2021-03-18
    • 1970-01-01
    • 1970-01-01
    • 2012-06-29
    • 2017-03-10
    • 1970-01-01
    相关资源
    最近更新 更多