调试器显示无效指令

时间:2013-05-23 10:10:24

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

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

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

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

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

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

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

发生了什么事?

1 个答案:

答案 0 :(得分: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(< b> j ump如果 n ot e qual)。所以我设置断点的地方实际上是最终决定,是否执行throw语句。

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

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

我留下这个例子以防万一有人发现自己陷入了类似的问题 - 希望这有助于找到原因。遇到这种情况相当罕见,但谁知道呢?...