Unable to ‘set next statement’ when debugging a 64-bit debuggee in Visual Studio 2005, sometimes


As I've mentioned before, I use Windows Server 2003 x64 as my desktop OS so I am always particularly interested when I get a support problem from a customer that appears to be specific to the 64-bit environment. A case in point happened recently when I had a problem report that the customer could not use the 'set next statement' feature in Visual Studio 2005.  At first we thought the problem was specific to AMD64 machines as the customer had not seen the problem on Intel EM64T systems and I could not reproduce it either (I run a Dell Precision 670 with dual Xeon EM64T capable CPUs). However later it turned out I could reproduce it - I don't know what I was doing wrong.

The repro was simple:

 

Ensure you are compiling to 64-bit and set a breakpoint inside the exception handler and allow the code to reach the breakpoint. Once there, right click on a line within the try block and try to 'set next statement' on the context menu:

 

The result is this dialog:

 

(For the benefit of search engines and others, the error says "Unable to set the next statement at this location. The attempt to unwind the callstack failed.")

The dialog lists a number of reasons why this might not be possible right now but the point is if you compile to 32-bit it works just fine.

After a bit of messy debugging trying to capture some dump files at the exact point of failure (so I could remote them out to the development team) and a bit of emailing back and forward with Redmond, it turns out the answer is annoyingly simple..

 

You can't do it here.

 

Why not?

It turns out that we cannot do it because of the way that exception handling is implemented on 64-bit processors. If the current instruction pointer (IP) is within a catch block we cannot set the new IP to within the try block (or anywhere else not in the catch block for that matter). This is because setting the next statement is not as simple as setting the value of the instruction pointer register in current thread context. We need to fix up other registers etc that may be getting used for local variables and such like.  In fact we even have an internal error code relating to the situation, CORDBG_E_CANT_SET_IP_OUT_OF_CATCH_ON_WIN64, which is mentioned in Mike Stalls blog on this and other SetIP failure cases.

Visual Studio tries to cope with this situation by intercepting the exception but is unable to because we are already on our second pass. By the time the catch clause is executed the exception dispatch is at the end of the second pass.

There are a couple of ways to cope with this:

1) Don't get to the catch block in the first place - set the Visual Studio debugger to stop on the exception and go from there

2) Step out of the catch block and then 'set next statement' to where you want.

It'd be nice if Visual Studio gave a slightly more helpful error message in this situation, since it is expected (at least from an ICorDebug API point of view). I'll file a bug against Orcas and see if we can get that improved.

 

Bye for now

Doug

Comments (3)

  1. I find that dialogues tend to fall into four categories 1) Clear, obvious and helpful 2) Clear, obvious

  2. John says:

    .NET uses the underlying plumbing of Windows' structured exception handling. There's a Big Difference in the way x64 exception handling is implemented. It uses tables of addresses, generated by the compiler to locate the proper exception filter. x86 uses a linked list of function pointers, much easier to implement by a compiler.

    One of the reasons the x64 way was changed was for security reasons, viral code managed to inject itself by patching the linked list and causing an exception, allowing its payload to execute. There were counter-measures against that in XP SP1, at a cost of efficiency. The x64 redesign avoids that cost.

    Well, you can see where that's heading. You ought to debug code with the Platform Target set to x86 anyway. This also enables Edit + Continue, a very valuable debugging aid. It is the default setting for VS2010 projects. Only flip to AnyCPU for the Release build.

  3. Hi John, thanks for the very interesting insight!  Doug

Skip to main content