ntdll: Add support for debug registers in exceptions on x86-64.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
9e59362ae3
commit
a1b563f41c
@ -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 )
|
|||||||
*/
|
*/
|
||||||
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 )
|
|||||||
#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 )
|
|||||||
*/
|
*/
|
||||||
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,
|
|||||||
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 )
|
|||||||
*/
|
*/
|
||||||
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 )
|
|||||||
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 )
|
|||||||
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:
|
|||||||
*/
|
*/
|
||||||
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 )
|
|||||||
*/
|
*/
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user