Module: wine Branch: refs/heads/master Commit: 2878d9921669aaceb840ce460be4026f039076ec URL: http://source.winehq.org/git/?p=wine.git;a=commit;h=2878d9921669aaceb840ce46...
Author: Alexandre Julliard julliard@winehq.org Date: Fri Jan 13 13:58:14 2006 +0100
ntdll: Add debug registers to the context of all exceptions. Maintain a local cache of the debug registers to avoid server calls where possible.
---
dlls/ntdll/ntdll_misc.h | 17 ++++++++++++++ dlls/ntdll/signal_i386.c | 47 ++++++++++++++++++++++++---------------- dlls/ntdll/thread.c | 33 ++++++++++++++++++++++++++-- include/wine/server_protocol.h | 3 ++- include/winternl.h | 2 +- server/protocol.def | 1 + server/thread.c | 1 + server/trace.c | 1 + 8 files changed, 81 insertions(+), 24 deletions(-)
diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index ac9acae..c63b700 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -134,4 +134,21 @@ static inline struct ntdll_thread_data * 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 be33458..1b2e8f0 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c @@ -740,7 +740,9 @@ inline static void restore_fpu( const CO */ 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->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 */ 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( cons /*********************************************************************** * 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 *con
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( } }
- 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 9a2e2bd..d189bf7 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -294,6 +294,9 @@ NTSTATUS WINAPI RtlCreateUserThread( HAN 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( HAND
#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( HAND NTSTATUS ret; CONTEXT ctx; DWORD dummy, i; + BOOL self = FALSE;
SERVER_START_REQ( get_thread_context ) { @@ -789,6 +799,7 @@ NTSTATUS WINAPI NtGetContextThread( HAND 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( HAND } }
- 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 5f2ad9e..4ab1467 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 67403bb..a5a2e83 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 55aef19..d3878cb 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 3ffbf85..1c00ce7 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 49ff25e..1aa964e 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1895,6 +1895,7 @@ static void dump_get_thread_context_requ
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 ); }