diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index ac9acaeff36..c63b70049c2 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -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 diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c index be33458ccb2..1b2e8f044b7 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c @@ -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 ); } diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index 9a2e2bd80f2..d189bf7444f 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -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; } diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 5f2ad9ea4a0..4ab14677d66 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -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 */ diff --git a/include/winternl.h b/include/winternl.h index 67403bba806..a5a2e838ab2 100644 --- a/include/winternl.h +++ b/include/winternl.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 */ diff --git a/server/protocol.def b/server/protocol.def index 55aef190841..d3878cbe457 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -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 diff --git a/server/thread.c b/server/thread.c index 3ffbf8538fe..1c00ce71106 100644 --- a/server/thread.c +++ b/server/thread.c @@ -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 ); } diff --git a/server/trace.c b/server/trace.c index 49ff25e81dc..1aa964eceae 100644 --- a/server/trace.c +++ b/server/trace.c @@ -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 ); }