Skip to content

SetThreadContext Fail on x64

July 2, 2009

On all 64-bit versions of Windows I have been experiencing weird crashes with apps running in a debugger, caused by all sorts of access violations in ntdll. I figured it must have been my code doing something incorrectly which works on x86 but breaks on 64-bit Windows.

The exceptions would usually happen after the break at ntdll!DbgBreakPoint, somewhere around RtlUserThreadBase on Vista SP2. I even got DEP access violations at random memory addresses outside of ntdll. This behaviour seemed to be consistent on all 64-bit Windows versions. I got similar exceptions on XP SP2, Vista SP2 and Win7 RC1.

I was able to nail it down to a call to SetThreadContext which was responsible for setting the DRX registers. The code did nothing more than call GetThreadContext, set DR0 to DR3 + DR7 and call SetThreadContext. I suspected the DRX values to be corrupted, so I removed everything between the two APIs. Surprisingly, the error remained. When I just removed SetThreadContext, it worked flawlessly.

Since I didn’t need to read and update anything other than the debug registers, I set the context flags to CONTEXT_DEBUG_REGISTERS. Because I lacked any logical solutions I played around with the flags and tried CONTEXT_ALL. All of a sudden the exceptions were gone and the debuggee started up normally. Wow.

Turns out that combining CONTEXT_DEBUG_REGISTERS with any other valid flag fixes this problem.

Just to be sure, I added this piece of code to the CREATE_PROCESS_DEBUG_EVENT handler:

CONTEXT Context;
Context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
HANDLE Thread = Event.u.CreateProcessInfo.hThread;
GetThreadContext(Thread, &Context);
SetThreadContext(Thread, &Context);

This perfectly reproduced all the crashes I was experiencing before. Changing the second line to:

Context.ContextFlags = CONTEXT_CONTROL | CONTEXT_DEBUG_REGISTERS;

made it work like a charm.

I had another bunch of DEP violations after every INT1 but didn’t realize it was the same problem. I forgot to adapt the flags for one piece of code which read and updated the debug registers after a hardware breakpoint or single step. After fixing that, I had a perfectly working debugger.

I can’t remember how much time I spent finding that stupid bug. Bill, you owe me big-time.

From → 64-Bit, Debugging, Windows

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.