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