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:
Alexandre Julliard 2006-01-13 13:58:14 +01:00
parent d6bfc17ba3
commit 2878d99216
8 changed files with 81 additions and 24 deletions

View File

@ -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

View File

@ -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 );
} }

View File

@ -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;
} }

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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 );
} }

View File

@ -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 );
} }