Commit a1b563f4 authored by Alexandre Julliard's avatar Alexandre Julliard

ntdll: Add support for debug registers in exceptions on x86-64.

parent 9e59362a
...@@ -310,6 +310,12 @@ static wine_signal_handler handlers[256]; ...@@ -310,6 +310,12 @@ static wine_signal_handler handlers[256];
struct amd64_thread_data struct amd64_thread_data
{ {
DWORD_PTR dr0; /* debug registers */
DWORD_PTR dr1;
DWORD_PTR dr2;
DWORD_PTR dr3;
DWORD_PTR dr6;
DWORD_PTR dr7;
void *exit_frame; /* exit frame pointer */ void *exit_frame; /* exit frame pointer */
}; };
...@@ -1661,7 +1667,7 @@ static inline BOOL is_inside_signal_stack( void *ptr ) ...@@ -1661,7 +1667,7 @@ static inline BOOL is_inside_signal_stack( void *ptr )
*/ */
static void save_context( CONTEXT *context, const ucontext_t *sigcontext ) static void save_context( CONTEXT *context, const ucontext_t *sigcontext )
{ {
context->ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS; context->ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_DEBUG_REGISTERS;
context->Rax = RAX_sig(sigcontext); context->Rax = RAX_sig(sigcontext);
context->Rcx = RCX_sig(sigcontext); context->Rcx = RCX_sig(sigcontext);
context->Rdx = RDX_sig(sigcontext); context->Rdx = RDX_sig(sigcontext);
...@@ -1698,6 +1704,12 @@ static void save_context( CONTEXT *context, const ucontext_t *sigcontext ) ...@@ -1698,6 +1704,12 @@ static void save_context( CONTEXT *context, const ucontext_t *sigcontext )
#else #else
__asm__("movw %%ss,%0" : "=m" (context->SegSs)); __asm__("movw %%ss,%0" : "=m" (context->SegSs));
#endif #endif
context->Dr0 = amd64_thread_data()->dr0;
context->Dr1 = amd64_thread_data()->dr1;
context->Dr2 = amd64_thread_data()->dr2;
context->Dr3 = amd64_thread_data()->dr3;
context->Dr6 = amd64_thread_data()->dr6;
context->Dr7 = amd64_thread_data()->dr7;
if (FPU_sig(sigcontext)) if (FPU_sig(sigcontext))
{ {
context->ContextFlags |= CONTEXT_FLOATING_POINT; context->ContextFlags |= CONTEXT_FLOATING_POINT;
...@@ -1714,6 +1726,12 @@ static void save_context( CONTEXT *context, const ucontext_t *sigcontext ) ...@@ -1714,6 +1726,12 @@ static void save_context( CONTEXT *context, const ucontext_t *sigcontext )
*/ */
static void restore_context( const CONTEXT *context, ucontext_t *sigcontext ) static void restore_context( const CONTEXT *context, ucontext_t *sigcontext )
{ {
amd64_thread_data()->dr0 = context->Dr0;
amd64_thread_data()->dr1 = context->Dr1;
amd64_thread_data()->dr2 = context->Dr2;
amd64_thread_data()->dr3 = context->Dr3;
amd64_thread_data()->dr6 = context->Dr6;
amd64_thread_data()->dr7 = context->Dr7;
RAX_sig(sigcontext) = context->Rax; RAX_sig(sigcontext) = context->Rax;
RCX_sig(sigcontext) = context->Rcx; RCX_sig(sigcontext) = context->Rcx;
RDX_sig(sigcontext) = context->Rdx; RDX_sig(sigcontext) = context->Rdx;
...@@ -1873,6 +1891,16 @@ __ASM_GLOBAL_FUNC( set_full_cpu_context, ...@@ -1873,6 +1891,16 @@ __ASM_GLOBAL_FUNC( set_full_cpu_context,
static void set_cpu_context( const CONTEXT *context ) static void set_cpu_context( const CONTEXT *context )
{ {
DWORD flags = context->ContextFlags & ~CONTEXT_AMD64; DWORD flags = context->ContextFlags & ~CONTEXT_AMD64;
if (flags & CONTEXT_DEBUG_REGISTERS)
{
amd64_thread_data()->dr0 = context->Dr0;
amd64_thread_data()->dr1 = context->Dr1;
amd64_thread_data()->dr2 = context->Dr2;
amd64_thread_data()->dr3 = context->Dr3;
amd64_thread_data()->dr6 = context->Dr6;
amd64_thread_data()->dr7 = context->Dr7;
}
if (flags & CONTEXT_FULL) if (flags & CONTEXT_FULL)
{ {
if (!(flags & CONTEXT_CONTROL)) if (!(flags & CONTEXT_CONTROL))
...@@ -2081,10 +2109,20 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from ) ...@@ -2081,10 +2109,20 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
*/ */
NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context ) NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
{ {
NTSTATUS ret; NTSTATUS ret = STATUS_SUCCESS;
BOOL self; BOOL self = (handle == GetCurrentThread());
/* debug registers require a server call */
if (self && (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_AMD64)))
self = (amd64_thread_data()->dr0 == context->Dr0 &&
amd64_thread_data()->dr1 == context->Dr1 &&
amd64_thread_data()->dr2 == context->Dr2 &&
amd64_thread_data()->dr3 == context->Dr3 &&
amd64_thread_data()->dr6 == context->Dr6 &&
amd64_thread_data()->dr7 == context->Dr7);
if (!self) ret = set_thread_context( handle, context, &self );
ret = set_thread_context( handle, context, &self );
if (self && ret == STATUS_SUCCESS) set_cpu_context( context ); if (self && ret == STATUS_SUCCESS) set_cpu_context( context );
return ret; return ret;
} }
...@@ -2109,13 +2147,26 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) ...@@ -2109,13 +2147,26 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
needed_flags &= ~context->ContextFlags; needed_flags &= ~context->ContextFlags;
} }
if (self && needed_flags) if (self)
{
if (needed_flags)
{ {
CONTEXT ctx; CONTEXT ctx;
RtlCaptureContext( &ctx ); RtlCaptureContext( &ctx );
copy_context( context, &ctx, ctx.ContextFlags & needed_flags ); copy_context( context, &ctx, ctx.ContextFlags & needed_flags );
context->ContextFlags |= ctx.ContextFlags & needed_flags; context->ContextFlags |= ctx.ContextFlags & needed_flags;
} }
/* update the cached version of the debug registers */
if (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_AMD64))
{
amd64_thread_data()->dr0 = context->Dr0;
amd64_thread_data()->dr1 = context->Dr1;
amd64_thread_data()->dr2 = context->Dr2;
amd64_thread_data()->dr3 = context->Dr3;
amd64_thread_data()->dr6 = context->Dr6;
amd64_thread_data()->dr7 = context->Dr7;
}
}
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
...@@ -2618,14 +2669,42 @@ static void raise_segv_exception( EXCEPTION_RECORD *rec, CONTEXT *context ) ...@@ -2618,14 +2669,42 @@ static void raise_segv_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
case 3: /* BREAKPOINT_LOAD_SYMBOLS */ case 3: /* BREAKPOINT_LOAD_SYMBOLS */
case 4: /* BREAKPOINT_UNLOAD_SYMBOLS */ case 4: /* BREAKPOINT_UNLOAD_SYMBOLS */
case 5: /* BREAKPOINT_COMMAND_STRING (>= Win2003) */ case 5: /* BREAKPOINT_COMMAND_STRING (>= Win2003) */
goto done; set_cpu_context( context );
} }
break; break;
} }
status = raise_exception( rec, context, TRUE ); status = NtRaiseException( rec, context, TRUE );
if (status) raise_status( status, rec ); raise_status( status, rec );
done: }
set_cpu_context( context );
/**********************************************************************
* raise_trap_exception
*/
static void raise_trap_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
{
NTSTATUS status;
if (rec->ExceptionCode == EXCEPTION_SINGLE_STEP)
{
/* when single stepping can't tell whether this is a hw bp or a
* single step interrupt. try to avoid as much overhead as possible
* and only do a server call if there is any hw bp enabled. */
if( !(context->EFlags & 0x100) || (amd64_thread_data()->dr7 & 0xff) )
{
/* (possible) hardware breakpoint, fetch the debug registers */
DWORD saved_flags = context->ContextFlags;
context->ContextFlags = CONTEXT_DEBUG_REGISTERS;
NtGetContextThread(GetCurrentThread(), context);
context->ContextFlags |= saved_flags; /* restore flags */
}
context->EFlags &= ~0x100; /* clear single-step flag */
}
status = NtRaiseException( rec, context, TRUE );
raise_status( status, rec );
} }
...@@ -2636,9 +2715,8 @@ done: ...@@ -2636,9 +2715,8 @@ done:
*/ */
static void raise_generic_exception( EXCEPTION_RECORD *rec, CONTEXT *context ) static void raise_generic_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
{ {
NTSTATUS status = raise_exception( rec, context, TRUE ); NTSTATUS status = NtRaiseException( rec, context, TRUE );
if (status) raise_status( status, rec ); raise_status( status, rec );
set_cpu_context( context );
} }
...@@ -2747,7 +2825,7 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) ...@@ -2747,7 +2825,7 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
*/ */
static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext ) static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext )
{ {
EXCEPTION_RECORD *rec = setup_exception( sigcontext, raise_generic_exception ); EXCEPTION_RECORD *rec = setup_exception( sigcontext, raise_trap_exception );
switch (siginfo->si_code) switch (siginfo->si_code)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment