ntdll: Add debug registers to the context of all exceptions.
Maintain a local cache of the debug registers to avoid server calls where possible.
This commit is contained in:
parent
d6bfc17ba3
commit
2878d99216
|
@ -134,4 +134,21 @@ static inline struct ntdll_thread_data *ntdll_get_thread_data(void)
|
||||||
return (struct ntdll_thread_data *)NtCurrentTeb()->SystemReserved2;
|
return (struct ntdll_thread_data *)NtCurrentTeb()->SystemReserved2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* thread registers, stored in NtCurrentTeb()->SpareBytes1 */
|
||||||
|
struct ntdll_thread_regs
|
||||||
|
{
|
||||||
|
DWORD dr0; /* debug registers */
|
||||||
|
DWORD dr1;
|
||||||
|
DWORD dr2;
|
||||||
|
DWORD dr3;
|
||||||
|
DWORD dr6;
|
||||||
|
DWORD dr7;
|
||||||
|
DWORD spare[4]; /* change this if you add fields! */
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct ntdll_thread_regs *ntdll_get_thread_regs(void)
|
||||||
|
{
|
||||||
|
return (struct ntdll_thread_regs *)NtCurrentTeb()->SpareBytes1;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -740,7 +740,9 @@ inline static void restore_fpu( const CONTEXT *context )
|
||||||
*/
|
*/
|
||||||
inline static void save_context( CONTEXT *context, const SIGCONTEXT *sigcontext, WORD fs, WORD gs )
|
inline static void save_context( CONTEXT *context, const SIGCONTEXT *sigcontext, WORD fs, WORD gs )
|
||||||
{
|
{
|
||||||
context->ContextFlags = CONTEXT_FULL;
|
struct ntdll_thread_regs * const regs = ntdll_get_thread_regs();
|
||||||
|
|
||||||
|
context->ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
|
||||||
context->Eax = EAX_sig(sigcontext);
|
context->Eax = EAX_sig(sigcontext);
|
||||||
context->Ebx = EBX_sig(sigcontext);
|
context->Ebx = EBX_sig(sigcontext);
|
||||||
context->Ecx = ECX_sig(sigcontext);
|
context->Ecx = ECX_sig(sigcontext);
|
||||||
|
@ -757,6 +759,12 @@ inline static void save_context( CONTEXT *context, const SIGCONTEXT *sigcontext,
|
||||||
context->SegFs = fs;
|
context->SegFs = fs;
|
||||||
context->SegGs = gs;
|
context->SegGs = gs;
|
||||||
context->SegSs = LOWORD(SS_sig(sigcontext));
|
context->SegSs = LOWORD(SS_sig(sigcontext));
|
||||||
|
context->Dr0 = regs->dr0;
|
||||||
|
context->Dr1 = regs->dr1;
|
||||||
|
context->Dr2 = regs->dr2;
|
||||||
|
context->Dr3 = regs->dr3;
|
||||||
|
context->Dr6 = regs->dr6;
|
||||||
|
context->Dr7 = regs->dr7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -767,6 +775,14 @@ inline static void save_context( CONTEXT *context, const SIGCONTEXT *sigcontext,
|
||||||
*/
|
*/
|
||||||
inline static void restore_context( const CONTEXT *context, SIGCONTEXT *sigcontext )
|
inline static void restore_context( const CONTEXT *context, SIGCONTEXT *sigcontext )
|
||||||
{
|
{
|
||||||
|
struct ntdll_thread_regs * const regs = ntdll_get_thread_regs();
|
||||||
|
|
||||||
|
regs->dr0 = context->Dr0;
|
||||||
|
regs->dr1 = context->Dr1;
|
||||||
|
regs->dr2 = context->Dr2;
|
||||||
|
regs->dr3 = context->Dr3;
|
||||||
|
regs->dr6 = context->Dr6;
|
||||||
|
regs->dr7 = context->Dr7;
|
||||||
EAX_sig(sigcontext) = context->Eax;
|
EAX_sig(sigcontext) = context->Eax;
|
||||||
EBX_sig(sigcontext) = context->Ebx;
|
EBX_sig(sigcontext) = context->Ebx;
|
||||||
ECX_sig(sigcontext) = context->Ecx;
|
ECX_sig(sigcontext) = context->Ecx;
|
||||||
|
@ -797,7 +813,7 @@ inline static void restore_context( const CONTEXT *context, SIGCONTEXT *sigconte
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* set_cpu_context
|
* set_cpu_context
|
||||||
*
|
*
|
||||||
* Set the new CPU context.
|
* Set the new CPU context. Used by NtSetContextThread.
|
||||||
*/
|
*/
|
||||||
void set_cpu_context( const CONTEXT *context )
|
void set_cpu_context( const CONTEXT *context )
|
||||||
{
|
{
|
||||||
|
@ -805,6 +821,16 @@ void set_cpu_context( const CONTEXT *context )
|
||||||
|
|
||||||
if (flags & CONTEXT_FLOATING_POINT) restore_fpu( context );
|
if (flags & CONTEXT_FLOATING_POINT) restore_fpu( context );
|
||||||
|
|
||||||
|
if (flags & CONTEXT_DEBUG_REGISTERS)
|
||||||
|
{
|
||||||
|
struct ntdll_thread_regs * const regs = ntdll_get_thread_regs();
|
||||||
|
regs->dr0 = context->Dr0;
|
||||||
|
regs->dr1 = context->Dr1;
|
||||||
|
regs->dr2 = context->Dr2;
|
||||||
|
regs->dr3 = context->Dr3;
|
||||||
|
regs->dr6 = context->Dr6;
|
||||||
|
regs->dr7 = context->Dr7;
|
||||||
|
}
|
||||||
if (flags & CONTEXT_FULL)
|
if (flags & CONTEXT_FULL)
|
||||||
{
|
{
|
||||||
if ((flags & CONTEXT_FULL) != (CONTEXT_FULL & ~CONTEXT_i386))
|
if ((flags & CONTEXT_FULL) != (CONTEXT_FULL & ~CONTEXT_i386))
|
||||||
|
@ -1027,8 +1053,6 @@ done:
|
||||||
*/
|
*/
|
||||||
static void WINAPI raise_trap_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
|
static void WINAPI raise_trap_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
|
||||||
{
|
{
|
||||||
DWORD dr0, dr1, dr2, dr3, dr6, dr7;
|
|
||||||
|
|
||||||
if (rec->ExceptionCode == EXCEPTION_SINGLE_STEP)
|
if (rec->ExceptionCode == EXCEPTION_SINGLE_STEP)
|
||||||
{
|
{
|
||||||
if (context->EFlags & 0x100)
|
if (context->EFlags & 0x100)
|
||||||
|
@ -1048,22 +1072,7 @@ static void WINAPI raise_trap_exception( EXCEPTION_RECORD *rec, CONTEXT *context
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dr0 = context->Dr0;
|
|
||||||
dr1 = context->Dr1;
|
|
||||||
dr2 = context->Dr2;
|
|
||||||
dr3 = context->Dr3;
|
|
||||||
dr6 = context->Dr6;
|
|
||||||
dr7 = context->Dr7;
|
|
||||||
|
|
||||||
__regs_RtlRaiseException( rec, context );
|
__regs_RtlRaiseException( rec, context );
|
||||||
|
|
||||||
context->ContextFlags = CONTEXT_FULL;
|
|
||||||
if (dr0 != context->Dr0 || dr1 != context->Dr1 || dr2 != context->Dr2 ||
|
|
||||||
dr3 != context->Dr3 || dr6 != context->Dr6 || dr7 != context->Dr7)
|
|
||||||
{
|
|
||||||
/* the debug registers have changed, set the new values */
|
|
||||||
context->ContextFlags |= CONTEXT_DEBUG_REGISTERS;
|
|
||||||
}
|
|
||||||
NtSetContextThread( GetCurrentThread(), context );
|
NtSetContextThread( GetCurrentThread(), context );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -294,6 +294,9 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR *
|
||||||
teb->ClientId.UniqueProcess = (HANDLE)GetCurrentProcessId();
|
teb->ClientId.UniqueProcess = (HANDLE)GetCurrentProcessId();
|
||||||
teb->ClientId.UniqueThread = (HANDLE)tid;
|
teb->ClientId.UniqueThread = (HANDLE)tid;
|
||||||
|
|
||||||
|
/* inherit registers from parent thread */
|
||||||
|
memcpy( teb->SpareBytes1, ntdll_get_thread_regs(), sizeof(teb->SpareBytes1) );
|
||||||
|
|
||||||
thread_data = (struct ntdll_thread_data *)teb->SystemReserved2;
|
thread_data = (struct ntdll_thread_data *)teb->SystemReserved2;
|
||||||
thread_data->request_fd = request_pipe[1];
|
thread_data->request_fd = request_pipe[1];
|
||||||
|
|
||||||
|
@ -495,8 +498,14 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
|
||||||
|
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
/* on i386 debug registers always require a server call */
|
/* on i386 debug registers always require a server call */
|
||||||
self = ((handle == GetCurrentThread()) &&
|
self = (handle == GetCurrentThread());
|
||||||
!(context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386)));
|
if (self && (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386)))
|
||||||
|
{
|
||||||
|
struct ntdll_thread_regs * const regs = ntdll_get_thread_regs();
|
||||||
|
self = (regs->dr0 == context->Dr0 && regs->dr1 == context->Dr1 &&
|
||||||
|
regs->dr2 == context->Dr2 && regs->dr3 == context->Dr3 &&
|
||||||
|
regs->dr6 == context->Dr6 && regs->dr7 == context->Dr7);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!self)
|
if (!self)
|
||||||
|
@ -781,6 +790,7 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
|
||||||
NTSTATUS ret;
|
NTSTATUS ret;
|
||||||
CONTEXT ctx;
|
CONTEXT ctx;
|
||||||
DWORD dummy, i;
|
DWORD dummy, i;
|
||||||
|
BOOL self = FALSE;
|
||||||
|
|
||||||
SERVER_START_REQ( get_thread_context )
|
SERVER_START_REQ( get_thread_context )
|
||||||
{
|
{
|
||||||
|
@ -789,6 +799,7 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
|
||||||
req->suspend = 0;
|
req->suspend = 0;
|
||||||
wine_server_set_reply( req, &ctx, sizeof(ctx) );
|
wine_server_set_reply( req, &ctx, sizeof(ctx) );
|
||||||
ret = wine_server_call( req );
|
ret = wine_server_call( req );
|
||||||
|
self = reply->self;
|
||||||
}
|
}
|
||||||
SERVER_END_REQ;
|
SERVER_END_REQ;
|
||||||
|
|
||||||
|
@ -814,7 +825,23 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == STATUS_SUCCESS) copy_context( context, &ctx, context->ContextFlags );
|
if (ret == STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
copy_context( context, &ctx, context->ContextFlags );
|
||||||
|
#ifdef __i386__
|
||||||
|
/* update the cached version of the debug registers */
|
||||||
|
if (self && (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386)))
|
||||||
|
{
|
||||||
|
struct ntdll_thread_regs * const regs = ntdll_get_thread_regs();
|
||||||
|
regs->dr0 = context->Dr0;
|
||||||
|
regs->dr1 = context->Dr1;
|
||||||
|
regs->dr2 = context->Dr2;
|
||||||
|
regs->dr3 = context->Dr3;
|
||||||
|
regs->dr6 = context->Dr6;
|
||||||
|
regs->dr7 = context->Dr7;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
else if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED;
|
else if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1990,6 +1990,7 @@ struct get_thread_context_request
|
||||||
struct get_thread_context_reply
|
struct get_thread_context_reply
|
||||||
{
|
{
|
||||||
struct reply_header __header;
|
struct reply_header __header;
|
||||||
|
int self;
|
||||||
/* VARARG(context,context); */
|
/* VARARG(context,context); */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4348,6 +4349,6 @@ union generic_reply
|
||||||
struct query_symlink_reply query_symlink_reply;
|
struct query_symlink_reply query_symlink_reply;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SERVER_PROTOCOL_VERSION 219
|
#define SERVER_PROTOCOL_VERSION 220
|
||||||
|
|
||||||
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
||||||
|
|
|
@ -282,7 +282,7 @@ typedef struct _TEB
|
||||||
PVOID SystemReserved1[54]; /* 0cc used for kernel32 private data in Wine */
|
PVOID SystemReserved1[54]; /* 0cc used for kernel32 private data in Wine */
|
||||||
PVOID Spare1; /* 1a4 */
|
PVOID Spare1; /* 1a4 */
|
||||||
LONG ExceptionCode; /* 1a8 */
|
LONG ExceptionCode; /* 1a8 */
|
||||||
BYTE SpareBytes1[40]; /* 1ac */
|
BYTE SpareBytes1[40]; /* 1ac used for ntdll private data in Wine */
|
||||||
PVOID SystemReserved2[10]; /* 1d4 used for ntdll private data in Wine */
|
PVOID SystemReserved2[10]; /* 1d4 used for ntdll private data in Wine */
|
||||||
GDI_TEB_BATCH GdiTebBatch; /* 1fc */
|
GDI_TEB_BATCH GdiTebBatch; /* 1fc */
|
||||||
ULONG gdiRgn; /* 6dc */
|
ULONG gdiRgn; /* 6dc */
|
||||||
|
|
|
@ -1432,6 +1432,7 @@ enum char_info_mode
|
||||||
unsigned int flags; /* context flags */
|
unsigned int flags; /* context flags */
|
||||||
int suspend; /* if getting context during suspend */
|
int suspend; /* if getting context during suspend */
|
||||||
@REPLY
|
@REPLY
|
||||||
|
int self; /* was it a handle to the current thread? */
|
||||||
VARARG(context,context); /* thread context */
|
VARARG(context,context); /* thread context */
|
||||||
@END
|
@END
|
||||||
|
|
||||||
|
|
|
@ -1094,6 +1094,7 @@ DECL_HANDLER(get_thread_context)
|
||||||
memset( data, 0, sizeof(CONTEXT) );
|
memset( data, 0, sizeof(CONTEXT) );
|
||||||
get_thread_context( thread, data, req->flags );
|
get_thread_context( thread, data, req->flags );
|
||||||
}
|
}
|
||||||
|
reply->self = (thread == current);
|
||||||
release_object( thread );
|
release_object( thread );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1895,6 +1895,7 @@ static void dump_get_thread_context_request( const struct get_thread_context_req
|
||||||
|
|
||||||
static void dump_get_thread_context_reply( const struct get_thread_context_reply *req )
|
static void dump_get_thread_context_reply( const struct get_thread_context_reply *req )
|
||||||
{
|
{
|
||||||
|
fprintf( stderr, " self=%d,", req->self );
|
||||||
fprintf( stderr, " context=" );
|
fprintf( stderr, " context=" );
|
||||||
dump_varargs_context( cur_size );
|
dump_varargs_context( cur_size );
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue