Commit 2878d992 authored by Alexandre Julliard's avatar Alexandre Julliard

ntdll: Add debug registers to the context of all exceptions.

Maintain a local cache of the debug registers to avoid server calls where possible.
parent d6bfc17b
......@@ -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 );
}
......
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