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;
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
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->Ebx = EBX_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->SegGs = gs;
|
||||
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 )
|
||||
{
|
||||
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;
|
||||
EBX_sig(sigcontext) = context->Ebx;
|
||||
ECX_sig(sigcontext) = context->Ecx;
|
||||
|
@ -797,7 +813,7 @@ inline static void restore_context( const CONTEXT *context, SIGCONTEXT *sigconte
|
|||
/***********************************************************************
|
||||
* set_cpu_context
|
||||
*
|
||||
* Set the new CPU context.
|
||||
* Set the new CPU context. Used by NtSetContextThread.
|
||||
*/
|
||||
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_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) != (CONTEXT_FULL & ~CONTEXT_i386))
|
||||
|
@ -1027,8 +1053,6 @@ done:
|
|||
*/
|
||||
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 (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 );
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -294,6 +294,9 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR *
|
|||
teb->ClientId.UniqueProcess = (HANDLE)GetCurrentProcessId();
|
||||
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->request_fd = request_pipe[1];
|
||||
|
||||
|
@ -495,8 +498,14 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
|
|||
|
||||
#ifdef __i386__
|
||||
/* on i386 debug registers always require a server call */
|
||||
self = ((handle == GetCurrentThread()) &&
|
||||
!(context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386)));
|
||||
self = (handle == GetCurrentThread());
|
||||
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
|
||||
|
||||
if (!self)
|
||||
|
@ -781,6 +790,7 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
|
|||
NTSTATUS ret;
|
||||
CONTEXT ctx;
|
||||
DWORD dummy, i;
|
||||
BOOL self = FALSE;
|
||||
|
||||
SERVER_START_REQ( get_thread_context )
|
||||
{
|
||||
|
@ -789,6 +799,7 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
|
|||
req->suspend = 0;
|
||||
wine_server_set_reply( req, &ctx, sizeof(ctx) );
|
||||
ret = wine_server_call( req );
|
||||
self = reply->self;
|
||||
}
|
||||
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;
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -1990,6 +1990,7 @@ struct get_thread_context_request
|
|||
struct get_thread_context_reply
|
||||
{
|
||||
struct reply_header __header;
|
||||
int self;
|
||||
/* VARARG(context,context); */
|
||||
};
|
||||
|
||||
|
@ -4348,6 +4349,6 @@ union generic_reply
|
|||
struct query_symlink_reply query_symlink_reply;
|
||||
};
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 219
|
||||
#define SERVER_PROTOCOL_VERSION 220
|
||||
|
||||
#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 Spare1; /* 1a4 */
|
||||
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 */
|
||||
GDI_TEB_BATCH GdiTebBatch; /* 1fc */
|
||||
ULONG gdiRgn; /* 6dc */
|
||||
|
|
|
@ -1432,6 +1432,7 @@ enum char_info_mode
|
|||
unsigned int flags; /* context flags */
|
||||
int suspend; /* if getting context during suspend */
|
||||
@REPLY
|
||||
int self; /* was it a handle to the current thread? */
|
||||
VARARG(context,context); /* thread context */
|
||||
@END
|
||||
|
||||
|
|
|
@ -1094,6 +1094,7 @@ DECL_HANDLER(get_thread_context)
|
|||
memset( data, 0, sizeof(CONTEXT) );
|
||||
get_thread_context( thread, data, req->flags );
|
||||
}
|
||||
reply->self = (thread == current);
|
||||
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 )
|
||||
{
|
||||
fprintf( stderr, " self=%d,", req->self );
|
||||
fprintf( stderr, " context=" );
|
||||
dump_varargs_context( cur_size );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue