Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/ntdll/unix/server.c | 7 +++++ dlls/ntdll/unix/signal_i386.c | 31 +++++++++++------- dlls/ntdll/unix/signal_x86_64.c | 35 ++++++++++++++------- dlls/ntdll/unix/thread.c | 36 ++++++++++++++++++--- dlls/ntdll/unix/unix_private.h | 56 ++++++++++++++++++++++++++++----- include/wine/server_protocol.h | 5 +++ server/protocol.def | 5 +++ server/thread.c | 1 + server/trace.c | 6 ++++ 9 files changed, 148 insertions(+), 34 deletions(-)
diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index 81a903ca77a..7236f0acb83 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -631,8 +631,15 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT if (wine_server_reply_size( reply )) { DWORD context_flags = context->ContextFlags; /* unchanged registers are still available */ + XSTATE *xs = xstate_from_context( context ); + ULONG64 mask; + + if (xs) + mask = xs->Mask; context_from_server( context, &server_context ); context->ContextFlags |= context_flags; + if (xs) + xs->Mask |= mask; } } SERVER_END_REQ; diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index e0ba27d3e94..4d8eeb2072c 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -886,14 +886,16 @@ static inline void save_context( struct xcontext *xcontext, const ucontext_t *si } if (fpux) { + XSTATE *xs; + context->ContextFlags |= CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS; memcpy( context->ExtendedRegisters, fpux, sizeof(*fpux) ); if (!fpu) fpux_to_fpu( &context->FloatSave, fpux ); - xcontext->xstate = XState_sig(fpux); - } - else - { - xcontext->xstate = NULL; + if ((xs = XState_sig(fpux))) + { + context_init_xstate( context, xs ); + xcontext->host_compaction_mask = xs->CompactionMask; + } } if (!fpu && !fpux) save_fpu( context ); } @@ -944,6 +946,7 @@ static inline void restore_context( const struct xcontext *xcontext, ucontext_t { memcpy( &dst_xs->YmmContext, &src_xs->YmmContext, sizeof(dst_xs->YmmContext) ); dst_xs->Mask |= src_xs->Mask; + dst_xs->CompactionMask = xcontext->host_compaction_mask; } } if (!fpu && !fpux) restore_fpu( context ); @@ -1023,6 +1026,7 @@ static unsigned int get_server_context_flags( DWORD flags ) if (flags & CONTEXT_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT; if (flags & CONTEXT_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS; if (flags & CONTEXT_EXTENDED_REGISTERS) ret |= SERVER_CTX_EXTENDED_REGISTERS; + if (flags & CONTEXT_XSTATE) ret |= SERVER_CTX_YMM_REGISTERS; return ret; }
@@ -1095,6 +1099,7 @@ NTSTATUS context_to_server( context_t *to, const CONTEXT *from ) to->flags |= SERVER_CTX_EXTENDED_REGISTERS; memcpy( to->ext.i386_regs, from->ExtendedRegisters, sizeof(to->ext.i386_regs) ); } + xstate_to_server( to, xstate_from_context( from ) ); return STATUS_SUCCESS; }
@@ -1108,7 +1113,7 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from ) { if (from->cpu != CPU_x86) return STATUS_INVALID_PARAMETER;
- to->ContextFlags = CONTEXT_i386; + to->ContextFlags = CONTEXT_i386 | (to->ContextFlags & 0x40); if (from->flags & SERVER_CTX_CONTROL) { to->ContextFlags |= CONTEXT_CONTROL; @@ -1165,6 +1170,7 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from ) to->ContextFlags |= CONTEXT_EXTENDED_REGISTERS; memcpy( to->ExtendedRegisters, from->ext.i386_regs, sizeof(to->ExtendedRegisters) ); } + xstate_from_server( xstate_from_context( to ), from ); return STATUS_SUCCESS; }
@@ -1246,7 +1252,7 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
/* Save xstate before any calls which can potentially change volatile ymm registers. * E. g., debug output will clobber ymm registers. */ - xsave_status = self ? save_xstate( context ) : STATUS_SUCCESS; /* FIXME: other thread. */ + xsave_status = self ? save_xstate( context ) : STATUS_SUCCESS;
/* debug registers require a server call */ if (needed_flags & CONTEXT_DEBUG_REGISTERS) self = FALSE; @@ -1293,7 +1299,6 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) } if (needed_flags & CONTEXT_FLOATING_POINT) save_fpu( context ); if (needed_flags & CONTEXT_EXTENDED_REGISTERS) save_fpux( context ); - /* FIXME: xstate */ /* update the cached version of the debug registers */ if (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386)) { @@ -1579,6 +1584,7 @@ static void setup_raise_exception( ucontext_t *sigcontext, void *stack_ptr, { CONTEXT *context = &xcontext->c; size_t stack_size; + XSTATE *src_xs;
struct stack_layout { @@ -1606,7 +1612,7 @@ C_ASSERT( (offsetof(struct stack_layout, xstate) == sizeof(struct stack_layout)) if (rec->ExceptionCode == EXCEPTION_BREAKPOINT) context->Eip--;
stack_size = sizeof(*stack); - if (xcontext->xstate) + if ((src_xs = xstate_from_context( context ))) { stack_size += (ULONG_PTR)stack_ptr - (((ULONG_PTR)stack_ptr - sizeof(XSTATE)) & ~(ULONG_PTR)63); @@ -1616,17 +1622,18 @@ C_ASSERT( (offsetof(struct stack_layout, xstate) == sizeof(struct stack_layout)) stack->rec = *rec; stack->context = *context;
- if (xcontext->xstate) + if (src_xs) { XSTATE *dst_xs = (XSTATE *)stack->xstate;
assert(!((ULONG_PTR)dst_xs & 63)); context_init_xstate( &stack->context, stack->xstate ); + memset( dst_xs, 0, offsetof(XSTATE, YmmContext) ); dst_xs->CompactionMask = user_shared_data->XState.CompactionEnabled ? 0x8000000000000004 : 0; - if (xcontext->xstate->Mask & 4) + if (src_xs->Mask & 4) { dst_xs->Mask = 4; - memcpy( &dst_xs->YmmContext, &xcontext->xstate->YmmContext, sizeof(dst_xs->YmmContext) ); + memcpy( &dst_xs->YmmContext, &src_xs->YmmContext, sizeof(dst_xs->YmmContext) ); } }
diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index e11b2c70b59..030f8cc6feb 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -1461,14 +1461,19 @@ static void save_context( struct xcontext *xcontext, const ucontext_t *sigcontex context->Dr7 = amd64_thread_data()->dr7; if (FPU_sig(sigcontext)) { + XSTATE *xs; + context->ContextFlags |= CONTEXT_FLOATING_POINT; context->u.FltSave = *FPU_sig(sigcontext); context->MxCsr = context->u.FltSave.MxCsr; - xcontext->xstate = XState_sig(FPU_sig(sigcontext)); - } - else - { - xcontext->xstate = NULL; + if ((xs = XState_sig(FPU_sig(sigcontext)))) + { + /* xcontext and sigcontext are both on the signal stack, so we can + * just reference sigcontext without overflowing 32 bit XState.Offset */ + context_init_xstate( context, xs ); + assert( xcontext->c_ex.XState.Offset == (BYTE *)xs - (BYTE *)&xcontext->c_ex ); + xcontext->host_compaction_mask = xs->CompactionMask; + } } }
@@ -1531,6 +1536,7 @@ static inline NTSTATUS save_xstate( CONTEXT *context ) static void restore_context( const struct xcontext *xcontext, ucontext_t *sigcontext ) { const CONTEXT *context = &xcontext->c; + XSTATE *xs;
amd64_thread_data()->dr0 = context->Dr0; amd64_thread_data()->dr1 = context->Dr1; @@ -1540,6 +1546,8 @@ static void restore_context( const struct xcontext *xcontext, ucontext_t *sigcon amd64_thread_data()->dr7 = context->Dr7; set_sigcontext( context, sigcontext ); if (FPU_sig(sigcontext)) *FPU_sig(sigcontext) = context->u.FltSave; + if ((xs = XState_sig(FPU_sig(sigcontext)))) + xs->CompactionMask = xcontext->host_compaction_mask; }
@@ -1628,6 +1636,7 @@ static unsigned int get_server_context_flags( DWORD flags ) if (flags & CONTEXT_SEGMENTS) ret |= SERVER_CTX_SEGMENTS; if (flags & CONTEXT_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT; if (flags & CONTEXT_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS; + if (flags & CONTEXT_XSTATE) ret |= SERVER_CTX_YMM_REGISTERS; return ret; }
@@ -1695,6 +1704,7 @@ NTSTATUS context_to_server( context_t *to, const CONTEXT *from ) to->debug.x86_64_regs.dr6 = from->Dr6; to->debug.x86_64_regs.dr7 = from->Dr7; } + xstate_to_server( to, xstate_from_context( from ) ); return STATUS_SUCCESS; }
@@ -1708,7 +1718,7 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from ) { if (from->cpu != CPU_x86_64) return STATUS_INVALID_PARAMETER;
- to->ContextFlags = CONTEXT_AMD64; + to->ContextFlags = CONTEXT_AMD64 | (to->ContextFlags & 0x40); if (from->flags & SERVER_CTX_CONTROL) { to->ContextFlags |= CONTEXT_CONTROL; @@ -1762,6 +1772,7 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from ) to->Dr6 = from->debug.x86_64_regs.dr6; to->Dr7 = from->debug.x86_64_regs.dr7; } + xstate_from_server( xstate_from_context( to ), from ); return STATUS_SUCCESS; }
@@ -1831,7 +1842,7 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
/* Save xstate before any calls which can potentially change volatile ymm registers. * E. g., debug output will clobber ymm registers. */ - xsave_status = self ? save_xstate( context ) : STATUS_SUCCESS; /* FIXME: other thread. */ + xsave_status = self ? save_xstate( context ) : STATUS_SUCCESS;
needed_flags = context->ContextFlags & ~CONTEXT_AMD64;
@@ -1924,6 +1935,7 @@ static void setup_raise_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec struct stack_layout *stack; size_t stack_size; NTSTATUS status; + XSTATE *src_xs;
if (rec->ExceptionCode == EXCEPTION_SINGLE_STEP) { @@ -1953,7 +1965,7 @@ static void setup_raise_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec if (rec->ExceptionCode == EXCEPTION_BREAKPOINT) context->Rip--;
stack_size = sizeof(*stack); - if (xcontext->xstate) + if ((src_xs = xstate_from_context( context ))) { stack_size += (ULONG_PTR)stack_ptr - (((ULONG_PTR)stack_ptr - sizeof(XSTATE)) & ~(ULONG_PTR)63); @@ -1962,17 +1974,18 @@ static void setup_raise_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec stack = virtual_setup_exception( stack_ptr, stack_size, rec ); stack->rec = *rec; stack->context = *context; - if (xcontext->xstate) + if (src_xs) { XSTATE *dst_xs = (XSTATE *)stack->xstate;
assert( !((ULONG_PTR)dst_xs & 63) ); context_init_xstate( &stack->context, stack->xstate ); + memset( dst_xs, 0, offsetof(XSTATE, YmmContext) ); dst_xs->CompactionMask = user_shared_data->XState.CompactionEnabled ? 0x8000000000000004 : 0; - if (xcontext->xstate->Mask & 4) + if (src_xs->Mask & 4) { dst_xs->Mask = 4; - memcpy( &dst_xs->YmmContext, &xcontext->xstate->YmmContext, sizeof(dst_xs->YmmContext) ); + memcpy( &dst_xs->YmmContext, &src_xs->YmmContext, sizeof(dst_xs->YmmContext) ); } }
diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index ded4b33eb01..a161c5d1c90 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -344,7 +344,6 @@ NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_c DWORD i; obj_handle_t handle = 0; client_ptr_t params[EXCEPTION_MAXIMUM_PARAMETERS]; - CONTEXT exception_context = *context; select_op_t select_op; sigset_t old_set;
@@ -370,10 +369,22 @@ NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_c
if (handle) { + struct xcontext exception_context; + DECLSPEC_ALIGN(64) XSTATE xs; + XSTATE *src_xs; + select_op.wait.op = SELECT_WAIT; select_op.wait.handles[0] = handle; + + exception_context.c = *context; + if ((src_xs = xstate_from_context( context ))) + { + context_init_xstate( &exception_context.c, &xs ); + memcpy( &xs, src_xs, sizeof(xs) ); + } + server_select( &select_op, offsetof( select_op_t, wait.handles[1] ), SELECT_INTERRUPTIBLE, - TIMEOUT_INFINITE, &exception_context, NULL, NULL ); + TIMEOUT_INFINITE, &exception_context.c, NULL, NULL );
SERVER_START_REQ( get_exception_status ) { @@ -381,7 +392,12 @@ NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_c ret = wine_server_call( req ); } SERVER_END_REQ; - if (ret >= 0) *context = exception_context; + if (ret >= 0) + { + *context = exception_context.c; + if (src_xs) + memcpy( src_xs, &xs, sizeof(xs) ); + } }
pthread_sigmask( SIG_SETMASK, &old_set, NULL ); @@ -632,7 +648,7 @@ static NTSTATUS wow64_context_from_server( WOW64_CONTEXT *to, const context_t *f { if (from->cpu != CPU_x86) return STATUS_INVALID_PARAMETER;
- to->ContextFlags = WOW64_CONTEXT_i386; + to->ContextFlags = WOW64_CONTEXT_i386 | (to->ContextFlags & 0x40); if (from->flags & SERVER_CTX_CONTROL) { to->ContextFlags |= WOW64_CONTEXT_CONTROL; @@ -689,6 +705,12 @@ static NTSTATUS wow64_context_from_server( WOW64_CONTEXT *to, const context_t *f to->ContextFlags |= WOW64_CONTEXT_EXTENDED_REGISTERS; memcpy( to->ExtendedRegisters, from->ext.i386_regs, sizeof(to->ExtendedRegisters) ); } + if ((to->ContextFlags & WOW64_CONTEXT_XSTATE) == WOW64_CONTEXT_XSTATE) + { + CONTEXT_EX *c_ex = (CONTEXT_EX *)(to + 1); + + xstate_from_server( (XSTATE *)((BYTE *)c_ex + c_ex->XState.Offset), from ); + } return STATUS_SUCCESS; }
@@ -758,6 +780,12 @@ static void wow64_context_to_server( context_t *to, const WOW64_CONTEXT *from ) to->flags |= SERVER_CTX_EXTENDED_REGISTERS; memcpy( to->ext.i386_regs, from->ExtendedRegisters, sizeof(to->ext.i386_regs) ); } + if (flags & WOW64_CONTEXT_XSTATE) + { + CONTEXT_EX *c_ex = (CONTEXT_EX *)(from + 1); + + xstate_to_server( to, (XSTATE *)((BYTE *)c_ex + c_ex->XState.Offset) ); + } }
#endif /* __x86_64__ */ diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index f99c13fe2ad..c3ad0a41098 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -288,13 +288,14 @@ static inline void mutex_unlock( pthread_mutex_t *mutex ) static inline TEB64 *NtCurrentTeb64(void) { return (TEB64 *)NtCurrentTeb()->GdiBatchCount; } #endif
-#if defined(__i386__) || defined(__x86_64__) struct xcontext { CONTEXT c; - XSTATE *xstate; /* points to xstate in sigcontext */ + CONTEXT_EX c_ex; + ULONG64 host_compaction_mask; };
+#if defined(__i386__) || defined(__x86_64__) static inline XSTATE *xstate_from_context( const CONTEXT *context ) { CONTEXT_EX *xctx = (CONTEXT_EX *)(context + 1); @@ -308,21 +309,62 @@ static inline XSTATE *xstate_from_context( const CONTEXT *context ) static inline void context_init_xstate( CONTEXT *context, void *xstate_buffer ) { CONTEXT_EX *xctx; - XSTATE *xs;
xctx = (CONTEXT_EX *)(context + 1); xctx->Legacy.Length = sizeof(CONTEXT); xctx->Legacy.Offset = -(LONG)sizeof(CONTEXT);
xctx->XState.Length = sizeof(XSTATE); - xctx->XState.Offset = xstate_buffer ? (((ULONG_PTR)xstate_buffer + 63) & ~63) - (ULONG_PTR)xctx - : (((ULONG_PTR)context + sizeof(CONTEXT) + sizeof(CONTEXT_EX) + 63) & ~63) - (ULONG_PTR)xctx; + xctx->XState.Offset = (BYTE *)xstate_buffer - (BYTE *)xctx; + xctx->All.Length = sizeof(CONTEXT) + xctx->XState.Offset + xctx->XState.Length; xctx->All.Offset = -(LONG)sizeof(CONTEXT); context->ContextFlags |= 0x40; +}
- xs = xstate_from_context(context); - memset( xs, 0, offsetof(XSTATE, YmmContext) ); +static inline void xstate_to_server( context_t *to, const XSTATE *xs ) +{ + if (!xs) + return; + + to->flags |= SERVER_CTX_YMM_REGISTERS; + if (xs->Mask & 4) + memcpy(&to->ymm.ymm_high_regs.ymm_high, &xs->YmmContext, sizeof(xs->YmmContext)); + else + memset(&to->ymm.ymm_high_regs.ymm_high, 0, sizeof(xs->YmmContext)); +} + +static inline void xstate_from_server_( XSTATE *xs, const context_t *from, BOOL compaction_enabled) +{ + if (!xs) + return; + + xs->Mask = 0; + xs->CompactionMask = compaction_enabled ? 0x8000000000000004 : 0; + + if (from->flags & SERVER_CTX_YMM_REGISTERS) + { + unsigned long *src = (unsigned long *)&from->ymm.ymm_high_regs.ymm_high; + unsigned int i; + + for (i = 0; i < sizeof(xs->YmmContext) / sizeof(unsigned long); ++i) + if (src[i]) + { + memcpy( &xs->YmmContext, &from->ymm.ymm_high_regs.ymm_high, sizeof(xs->YmmContext) ); + xs->Mask = 4; + break; + } + } +} +#define xstate_from_server( xs, from ) xstate_from_server_( xs, from, user_shared_data->XState.CompactionEnabled ) + +#else +static inline XSTATE *xstate_from_context( const CONTEXT *context ) +{ + return NULL; +} +static inline void context_init_xstate( CONTEXT *context, void *xstate_buffer ) +{ } #endif
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 751ca59ad6b..5e267195f20 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -170,6 +170,10 @@ typedef struct { unsigned char i386_regs[512]; } ext; + union + { + struct { struct { unsigned __int64 low, high; } ymm_high[16]; } ymm_high_regs; + } ymm; } context_t;
#define SERVER_CTX_CONTROL 0x01 @@ -178,6 +182,7 @@ typedef struct #define SERVER_CTX_FLOATING_POINT 0x08 #define SERVER_CTX_DEBUG_REGISTERS 0x10 #define SERVER_CTX_EXTENDED_REGISTERS 0x20 +#define SERVER_CTX_YMM_REGISTERS 0x40
struct send_fd diff --git a/server/protocol.def b/server/protocol.def index 16c0b936743..305a1d0186f 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -186,6 +186,10 @@ typedef struct { unsigned char i386_regs[512]; } ext; /* selected by SERVER_CTX_EXTENDED_REGISTERS */ + union + { + struct { struct { unsigned __int64 low, high; } ymm_high[16]; } ymm_high_regs; + } ymm; /* selected by SERVER_CTX_YMM_REGISTERS */ } context_t;
#define SERVER_CTX_CONTROL 0x01 @@ -194,6 +198,7 @@ typedef struct #define SERVER_CTX_FLOATING_POINT 0x08 #define SERVER_CTX_DEBUG_REGISTERS 0x10 #define SERVER_CTX_EXTENDED_REGISTERS 0x20 +#define SERVER_CTX_YMM_REGISTERS 0x40
/* structure used in sending an fd from client to server */ struct send_fd diff --git a/server/thread.c b/server/thread.c index eb138079739..942a8ff8389 100644 --- a/server/thread.c +++ b/server/thread.c @@ -1285,6 +1285,7 @@ static void copy_context( context_t *to, const context_t *from, unsigned int fla if (flags & SERVER_CTX_FLOATING_POINT) to->fp = from->fp; if (flags & SERVER_CTX_DEBUG_REGISTERS) to->debug = from->debug; if (flags & SERVER_CTX_EXTENDED_REGISTERS) to->ext = from->ext; + if (flags & SERVER_CTX_YMM_REGISTERS) to->ymm = from->ymm; }
/* return the context flags that correspond to system regs */ diff --git a/server/trace.c b/server/trace.c index 17dd415b958..8ee0bc8c3e3 100644 --- a/server/trace.c +++ b/server/trace.c @@ -620,6 +620,9 @@ static void dump_varargs_context( const char *prefix, data_size_t size ) if (ctx.flags & SERVER_CTX_EXTENDED_REGISTERS) dump_uints( ",extended=", (const unsigned int *)ctx.ext.i386_regs, sizeof(ctx.ext.i386_regs) / sizeof(int) ); + if (ctx.flags & SERVER_CTX_YMM_REGISTERS) + dump_uints( ",ymm_high=", (const unsigned int *)ctx.ymm.ymm_high_regs.ymm_high, + sizeof(ctx.ymm.ymm_high_regs) / sizeof(int) ); break; case CPU_x86_64: if (ctx.flags & SERVER_CTX_CONTROL) @@ -669,6 +672,9 @@ static void dump_varargs_context( const char *prefix, data_size_t size ) (unsigned int)(ctx.fp.x86_64_regs.fpregs[i].low >> 32), (unsigned int)ctx.fp.x86_64_regs.fpregs[i].low ); } + if (ctx.flags & SERVER_CTX_YMM_REGISTERS) + dump_uints( ",ymm_high=", (const unsigned int *)ctx.ymm.ymm_high_regs.ymm_high, + sizeof(ctx.ymm.ymm_high_regs) / sizeof(int) ); break; case CPU_POWERPC: if (ctx.flags & SERVER_CTX_CONTROL)
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/ntdll/tests/exception.c | 362 ++++++++++++++++++++++++----------- 1 file changed, 253 insertions(+), 109 deletions(-)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 66dbe8089c3..07b813ac1fa 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -6423,6 +6423,172 @@ done: return ExceptionContinueExecution; }
+struct call_func_offsets +{ + unsigned int func_addr; + unsigned int func_param1; + unsigned int func_param2; + unsigned int ymm0_save; +}; +#ifdef __x86_64__ +static BYTE call_func_code_set_ymm0[] = +{ + 0x55, /* pushq %rbp */ + 0x48, 0xb8, /* mov imm,%rax */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x48, 0xb9, /* mov imm,%rcx */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x48, 0xba, /* mov imm,%rdx */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x48, 0xbd, /* mov imm,%rbp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xc5, 0xfc, 0x10, 0x45, 0x00, /* vmovups (%rbp),%ymm0 */ + 0x48, 0x83, 0xec, 0x20, /* sub $0x20,%rsp */ + 0xff, 0xd0, /* call *rax */ + 0x48, 0x83, 0xc4, 0x20, /* add $0x20,%rsp */ + 0xc5, 0xfc, 0x11, 0x45, 0x00, /* vmovups %ymm0,(%rbp) */ + 0x5d, /* popq %rbp */ + 0xc3, /* ret */ +}; +static BYTE call_func_code_reset_ymm_state[] = +{ + 0x55, /* pushq %rbp */ + 0x48, 0xb8, /* mov imm,%rax */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x48, 0xb9, /* mov imm,%rcx */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x48, 0xba, /* mov imm,%rdx */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x48, 0xbd, /* mov imm,%rbp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xc5, 0xf8, 0x77, /* vzeroupper */ + 0x0f, 0x57, 0xc0, /* xorps %xmm0,%xmm0 */ + 0x48, 0x83, 0xec, 0x20, /* sub $0x20,%rsp */ + 0xff, 0xd0, /* call *rax */ + 0x48, 0x83, 0xc4, 0x20, /* add $0x20,%rsp */ + 0xc5, 0xfc, 0x11, 0x45, 0x00, /* vmovups %ymm0,(%rbp) */ + 0x5d, /* popq %rbp */ + 0xc3, /* ret */ +}; +static const struct call_func_offsets call_func_offsets = {3, 13, 23, 33}; +#else +static BYTE call_func_code_set_ymm0[] = +{ + 0x55, /* pushl %ebp */ + 0xb8, /* mov imm,%eax */ + 0x00, 0x00, 0x00, 0x00, + + 0xb9, /* mov imm,%ecx */ + 0x00, 0x00, 0x00, 0x00, + + 0xba, /* mov imm,%edx */ + 0x00, 0x00, 0x00, 0x00, + + 0xbd, /* mov imm,%ebp */ + 0x00, 0x00, 0x00, 0x00, + + 0x81, 0xfa, 0xef, 0xbe, 0xad, 0xde, + /* cmpl $0xdeadbeef, %edx */ + 0x74, 0x01, /* je 1f */ + 0x52, /* pushl %edx */ + 0x51, /* 1: pushl %ecx */ + 0xc5, 0xfc, 0x10, 0x45, 0x00, /* vmovups (%ebp),%ymm0 */ + 0xff, 0xd0, /* call *eax */ + 0xc5, 0xfc, 0x11, 0x45, 0x00, /* vmovups %ymm0,(%ebp) */ + 0x5d, /* popl %ebp */ + 0xc3, /* ret */ +}; +static BYTE call_func_code_reset_ymm_state[] = +{ + 0x55, /* pushl %ebp */ + 0xb8, /* mov imm,%eax */ + 0x00, 0x00, 0x00, 0x00, + + 0xb9, /* mov imm,%ecx */ + 0x00, 0x00, 0x00, 0x00, + + 0xba, /* mov imm,%edx */ + 0x00, 0x00, 0x00, 0x00, + + 0xbd, /* mov imm,%ebp */ + 0x00, 0x00, 0x00, 0x00, + + 0x81, 0xfa, 0xef, 0xbe, 0xad, 0xde, + /* cmpl $0xdeadbeef, %edx */ + 0x74, 0x01, /* je 1f */ + 0x52, /* pushl %edx */ + 0x51, /* 1: pushl %ecx */ + 0xc5, 0xf8, 0x77, /* vzeroupper */ + 0x0f, 0x57, 0xc0, /* xorps %xmm0,%xmm0 */ + 0xff, 0xd0, /* call *eax */ + 0xc5, 0xfc, 0x11, 0x45, 0x00, /* vmovups %ymm0,(%ebp) */ + 0x5d, /* popl %ebp */ + 0xc3, /* ret */ +}; +static const struct call_func_offsets call_func_offsets = {2, 7, 12, 17}; +#endif + +static DWORD WINAPI test_extended_context_thread(void *arg) +{ + ULONG (WINAPI* func)(void) = code_mem; + static unsigned int data[8]; + unsigned int i; + + memcpy(code_mem, call_func_code_reset_ymm_state, sizeof(call_func_code_reset_ymm_state)); + *(void **)((BYTE *)code_mem + call_func_offsets.func_addr) = SuspendThread; + *(void **)((BYTE *)code_mem + call_func_offsets.func_param1) = (void *)GetCurrentThread(); + *(void **)((BYTE *)code_mem + call_func_offsets.func_param2) = (void *)0xdeadbeef; + *(void **)((BYTE *)code_mem + call_func_offsets.ymm0_save) = data; + func(); + + for (i = 0; i < 4; ++i) + ok(!data[i], "Got unexpected data %#x, i %u.\n", data[i], i); + for (; i < 8; ++i) + ok(data[i] == 0x48484848, "Got unexpected data %#x, i %u.\n", data[i], i); + memset(data, 0x68, sizeof(data)); + + memcpy(code_mem, call_func_code_set_ymm0, sizeof(call_func_code_set_ymm0)); + *(void **)((BYTE *)code_mem + call_func_offsets.func_addr) = SuspendThread; + *(void **)((BYTE *)code_mem + call_func_offsets.func_param1) = (void *)GetCurrentThread(); + *(void **)((BYTE *)code_mem + call_func_offsets.func_param2) = (void *)0xdeadbeef; + *(void **)((BYTE *)code_mem + call_func_offsets.ymm0_save) = data; + func(); + + memcpy(code_mem, call_func_code_reset_ymm_state, sizeof(call_func_code_reset_ymm_state)); + *(void **)((BYTE *)code_mem + call_func_offsets.func_addr) = SuspendThread; + *(void **)((BYTE *)code_mem + call_func_offsets.func_param1) = (void *)GetCurrentThread(); + *(void **)((BYTE *)code_mem + call_func_offsets.func_param2) = (void *)0xdeadbeef; + *(void **)((BYTE *)code_mem + call_func_offsets.ymm0_save) = data; + func(); + return 0; +} + +static void wait_for_thread_next_suspend(HANDLE thread) +{ + DWORD result; + + result = ResumeThread(thread); + ok(result == 1, "Got unexpexted suspend count %u.\n", result); + + /* NtQueryInformationThread(ThreadSuspendCount, ...) is not supported on older Windows. */ + while (!(result = SuspendThread(thread))) + { + ResumeThread(thread); + Sleep(1); + } + ok(result == 1, "Got unexpexted suspend count %u.\n", result); + result = ResumeThread(thread); + ok(result == 2, "Got unexpexted suspend count %u.\n", result); +} + #define CONTEXT_NATIVE (CONTEXT_XSTATE & CONTEXT_CONTROL)
static void test_extended_context(void) @@ -6462,115 +6628,6 @@ static void test_extended_context(void) 0xc3, /* ret */ };
- struct call_func_offsets - { - unsigned int func_addr; - unsigned int func_param1; - unsigned int func_param2; - unsigned int ymm0_save; - }; -#ifdef __x86_64__ - static BYTE call_func_code_set_ymm0[] = - { - 0x55, /* pushq %rbp */ - 0x48, 0xb8, /* mov imm,%rax */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x48, 0xb9, /* mov imm,%rcx */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x48, 0xba, /* mov imm,%rdx */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x48, 0xbd, /* mov imm,%rbp */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0xc5, 0xfc, 0x10, 0x45, 0x00, /* vmovups (%rbp),%ymm0 */ - 0xff, 0xd0, /* call *rax */ - 0xc5, 0xfc, 0x11, 0x45, 0x00, /* vmovups %ymm0,(%rbp) */ - 0x5d, /* popq %rbp */ - 0xc3, /* ret */ - }; - static BYTE call_func_code_reset_ymm_state[] = - { - 0x55, /* pushq %rbp */ - 0x48, 0xb8, /* mov imm,%rax */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x48, 0xb9, /* mov imm,%rcx */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x48, 0xba, /* mov imm,%rdx */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x48, 0xbd, /* mov imm,%rbp */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0xc5, 0xf8, 0x77, /* vzeroupper */ - 0x0f, 0x57, 0xc0, /* xorps %xmm0,%xmm0 */ - 0xff, 0xd0, /* call *rax */ - 0xc5, 0xfc, 0x11, 0x45, 0x00, /* vmovups %ymm0,(%rbp) */ - 0x5d, /* popq %rbp */ - 0xc3, /* ret */ - }; - static const struct call_func_offsets call_func_offsets = {3, 13, 23, 33}; -#else - static BYTE call_func_code_set_ymm0[] = - { - 0x55, /* pushl %ebp */ - 0xb8, /* mov imm,%eax */ - 0x00, 0x00, 0x00, 0x00, - - 0xb9, /* mov imm,%ecx */ - 0x00, 0x00, 0x00, 0x00, - - 0xba, /* mov imm,%edx */ - 0x00, 0x00, 0x00, 0x00, - - 0xbd, /* mov imm,%ebp */ - 0x00, 0x00, 0x00, 0x00, - - 0x81, 0xfa, 0xef, 0xbe, 0xad, 0xde, - /* cmpl $0xdeadbeef, %edx */ - 0x74, 0x01, /* je 1f */ - 0x52, /* pushl %edx */ - 0x51, /* 1: pushl %ecx */ - 0xc5, 0xfc, 0x10, 0x45, 0x00, /* vmovups (%ebp),%ymm0 */ - 0xff, 0xd0, /* call *eax */ - 0xc5, 0xfc, 0x11, 0x45, 0x00, /* vmovups %ymm0,(%ebp) */ - 0x5d, /* popl %ebp */ - 0xc3, /* ret */ - }; - static BYTE call_func_code_reset_ymm_state[] = - { - 0x55, /* pushl %ebp */ - 0xb8, /* mov imm,%eax */ - 0x00, 0x00, 0x00, 0x00, - - 0xb9, /* mov imm,%ecx */ - 0x00, 0x00, 0x00, 0x00, - - 0xba, /* mov imm,%edx */ - 0x00, 0x00, 0x00, 0x00, - - 0xbd, /* mov imm,%ebp */ - 0x00, 0x00, 0x00, 0x00, - - 0x81, 0xfa, 0xef, 0xbe, 0xad, 0xde, - /* cmpl $0xdeadbeef, %edx */ - 0x74, 0x01, /* je 1f */ - 0x52, /* pushl %edx */ - 0x51, /* 1: pushl %ecx */ - 0xc5, 0xf8, 0x77, /* vzeroupper */ - 0x0f, 0x57, 0xc0, /* xorps %xmm0,%xmm0 */ - 0xff, 0xd0, /* call *eax */ - 0xc5, 0xfc, 0x11, 0x45, 0x00, /* vmovups %ymm0,(%ebp) */ - 0x5d, /* popl %ebp */ - 0xc3, /* ret */ - }; - static const struct call_func_offsets call_func_offsets = {2, 7, 12, 17}; -#endif - static const struct { ULONG flag; @@ -6622,6 +6679,7 @@ static void test_extended_context(void) CONTEXT_EX *context_ex; CONTEXT *context; unsigned data[8]; + HANDLE thread; ULONG64 mask; XSTATE *xs; BOOL bret; @@ -7396,6 +7454,92 @@ static void test_extended_context(void)
for (i = 0; i < 8; ++i) ok(data[i] == test_extended_context_data[i], "Got unexpected data %#x, i %u.\n", data[i], i); + + /* Test GetThreadContext for the other thread. */ + thread = CreateThread(NULL, 0, test_extended_context_thread, 0, CREATE_SUSPENDED, NULL); + ok(!!thread, "Failed to create thread.\n"); + + bret = pInitializeContext(context_buffer, CONTEXT_FULL | CONTEXT_XSTATE | CONTEXT_FLOATING_POINT, + &context, &length); + ok(bret, "Got unexpected bret %#x.\n", bret); + memset(&xs->YmmContext, 0xcc, sizeof(xs->YmmContext)); + context_ex = (CONTEXT_EX *)(context + 1); + xs = (XSTATE *)((BYTE *)context_ex + context_ex->XState.Offset); + pSetXStateFeaturesMask(context, 4); + + bret = GetThreadContext(thread, context); + ok(bret, "Got unexpected bret %#x, GetLastError() %u.\n", bret, GetLastError()); + ok(!xs->Mask, "Got unexpected Mask %s.\n", wine_dbgstr_longlong(xs->Mask)); + ok(xs->CompactionMask == expected_compaction, "Got unexpected CompactionMask %s.\n", + wine_dbgstr_longlong(xs->CompactionMask)); + for (i = 0; i < 16 * 4; ++i) + ok(((ULONG *)&xs->YmmContext)[i] == 0xcccccccc, "Got unexpected value %#x, i %u.\n", + ((ULONG *)&xs->YmmContext)[i], i); + + pSetXStateFeaturesMask(context, 4); + memset(&xs->YmmContext, 0, sizeof(xs->YmmContext)); + bret = SetThreadContext(thread, context); + ok(bret, "Got unexpected bret %#x, GetLastError() %u.\n", bret, GetLastError()); + + memset(&xs->YmmContext, 0xcc, sizeof(xs->YmmContext)); + bret = GetThreadContext(thread, context); + ok(bret, "Got unexpected bret %#x, GetLastError() %u.\n", bret, GetLastError()); + ok(!xs->Mask || broken(xs->Mask == 4), "Got unexpected Mask %s.\n", wine_dbgstr_longlong(xs->Mask)); + ok(xs->CompactionMask == expected_compaction, "Got unexpected CompactionMask %s.\n", + wine_dbgstr_longlong(xs->CompactionMask)); + for (i = 0; i < 16 * 4; ++i) + ok(((ULONG *)&xs->YmmContext)[i] == 0xcccccccc || broken(xs->Mask == 4 && !((ULONG *)&xs->YmmContext)[i]), + "Got unexpected value %#x, i %u.\n", ((ULONG *)&xs->YmmContext)[i], i); + + pSetXStateFeaturesMask(context, 4); + memset(&xs->YmmContext, 0x28, sizeof(xs->YmmContext)); + bret = SetThreadContext(thread, context); + ok(bret, "Got unexpected bret %#x, GetLastError() %u.\n", bret, GetLastError()); + memset(&xs->YmmContext, 0xcc, sizeof(xs->YmmContext)); + bret = GetThreadContext(thread, context); + ok(bret, "Got unexpected bret %#x, GetLastError() %u.\n", bret, GetLastError()); + ok(xs->Mask == 4, "Got unexpected Mask %s.\n", wine_dbgstr_longlong(xs->Mask)); + ok(xs->CompactionMask == expected_compaction, "Got unexpected CompactionMask %s.\n", + wine_dbgstr_longlong(xs->CompactionMask)); + for (i = 0; i < 16 * 4; ++i) + ok(((ULONG *)&xs->YmmContext)[i] == 0x28282828, "Got unexpected value %#x, i %u.\n", + ((ULONG *)&xs->YmmContext)[i], i); + + wait_for_thread_next_suspend(thread); + + bret = GetThreadContext(thread, context); + ok(bret, "Got unexpected bret %#x, GetLastError() %u.\n", bret, GetLastError()); + pSetXStateFeaturesMask(context, 4); + memset(&xs->YmmContext, 0x48, sizeof(xs->YmmContext)); + bret = SetThreadContext(thread, context); + ok(bret, "Got unexpected bret %#x, GetLastError() %u.\n", bret, GetLastError()); + + wait_for_thread_next_suspend(thread); + + memset(&xs->YmmContext, 0xcc, sizeof(xs->YmmContext)); + bret = GetThreadContext(thread, context); + ok(bret, "Got unexpected bret %#x, GetLastError() %u.\n", bret, GetLastError()); + ok(xs->Mask == 4, "Got unexpected Mask %s.\n", wine_dbgstr_longlong(xs->Mask)); + + for (i = 0; i < 4; ++i) + ok(((ULONG *)&xs->YmmContext)[i] == 0x68686868, "Got unexpected value %#x, i %u.\n", + ((ULONG *)&xs->YmmContext)[i], i); + + wait_for_thread_next_suspend(thread); + + memset(&xs->YmmContext, 0xcc, sizeof(xs->YmmContext)); + bret = GetThreadContext(thread, context); + ok(bret, "Got unexpected bret %#x, GetLastError() %u.\n", bret, GetLastError()); + ok(xs->Mask == (sizeof(void *) == 4 ? 4 : 0), "Got unexpected Mask %s.\n", wine_dbgstr_longlong(xs->Mask)); + for (i = 0; i < 16 * 4; ++i) + ok(((ULONG *)&xs->YmmContext)[i] == (sizeof(void *) == 4 ? (i < 8 * 4 ? 0 : 0x48484848) : 0xcccccccc), + "Got unexpected value %#x, i %u.\n", ((ULONG *)&xs->YmmContext)[i], i); + + bret = ResumeThread(thread); + ok(bret, "Got unexpected bret %#x, GetLastError() %u.\n", bret, GetLastError()); + + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); }
struct modified_range
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/ntdll/tests/exception.c | 144 ++++++++++++++++++++++++++++++----- 1 file changed, 127 insertions(+), 17 deletions(-)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 07b813ac1fa..b2331b739ac 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -189,6 +189,67 @@ static BOOL is_wow64; static BOOL have_vectored_api; static int test_stage;
+#if defined(__i386__) || defined(__x86_64__) +static void test_debugger_xstate(HANDLE thread, CONTEXT *ctx, int stage) +{ + char context_buffer[sizeof(CONTEXT) + sizeof(CONTEXT_EX) + sizeof(XSTATE) + 63]; + CONTEXT_EX *c_ex; + NTSTATUS status; + YMMCONTEXT *ymm; + CONTEXT *xctx; + DWORD length; + XSTATE *xs; + M128A *xmm; + BOOL bret; + + if (!pRtlGetEnabledExtendedFeatures || !pRtlGetEnabledExtendedFeatures(1 << XSTATE_AVX)) + return; + + if (stage == 14) + return; + + length = sizeof(context_buffer); + bret = pInitializeContext(context_buffer, ctx->ContextFlags | CONTEXT_XSTATE, &xctx, &length); + ok(bret, "Got unexpected bret %#x, GetLastError() %u.\n", bret, GetLastError()); + + ymm = pLocateXStateFeature(xctx, XSTATE_AVX, &length); + ok(!!ymm, "Got zero ymm.\n"); + memset(ymm, 0xcc, sizeof(*ymm)); + + xmm = pLocateXStateFeature(xctx, XSTATE_LEGACY_SSE, &length); + ok(length == sizeof(*xmm) * (sizeof(void *) == 8 ? 16 : 8), "Got unexpected length %#x.\n", length); + ok(!!xmm, "Got zero xmm.\n"); + memset(xmm, 0xcc, length); + + status = pNtGetContextThread(thread, xctx); + ok(!status, "NtSetContextThread failed with 0x%x\n", status); + + c_ex = (CONTEXT_EX *)(xctx + 1); + xs = (XSTATE *)((char *)c_ex + c_ex->XState.Offset); + ok((xs->Mask & 7) == 4 || broken(!xs->Mask) /* Win7 */, + "Got unexpected xs->Mask %s.\n", wine_dbgstr_longlong(xs->Mask)); + + ok(xmm[0].Low == 0x200000001, "Got unexpected data %s.\n", wine_dbgstr_longlong(xmm[0].Low)); + ok(xmm[0].High == 0x400000003, "Got unexpected data %s.\n", wine_dbgstr_longlong(xmm[0].High)); + + ok(ymm->Ymm0.Low == 0x600000005 || broken(!xs->Mask && ymm->Ymm0.Low == 0xcccccccccccccccc) /* Win7 */, + "Got unexpected data %s.\n", wine_dbgstr_longlong(ymm->Ymm0.Low)); + ok(ymm->Ymm0.High == 0x800000007 || broken(!xs->Mask && ymm->Ymm0.High == 0xcccccccccccccccc) /* Win7 */, + "Got unexpected data %s.\n", wine_dbgstr_longlong(ymm->Ymm0.High)); + + xmm = pLocateXStateFeature(ctx, XSTATE_LEGACY_SSE, &length); + ok(!!xmm, "Got zero xmm.\n"); + + xmm[0].Low = 0x2828282828282828; + xmm[0].High = xmm[0].Low; + ymm->Ymm0.Low = 0x4848484848484848; + ymm->Ymm0.High = ymm->Ymm0.Low; + + status = pNtSetContextThread(thread, xctx); + ok(!status, "NtSetContextThread failed with 0x%x\n", status); +} +#endif + #ifdef __i386__
#ifndef __WINE_WINTRNL_H @@ -1055,7 +1116,7 @@ static void test_debugger(void) sizeof(stage), &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%x\n", status);
- ctx.ContextFlags = CONTEXT_FULL; + ctx.ContextFlags = CONTEXT_FULL | CONTEXT_EXTENDED_REGISTERS; status = pNtGetContextThread(pi.hThread, &ctx); ok(!status, "NtGetContextThread failed with 0x%x\n", status);
@@ -1156,6 +1217,10 @@ static void test_debugger(void)
if (stage == 12|| stage == 13) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } + else if (stage == 14 || stage == 15) + { + test_debugger_xstate(pi.hThread, &ctx, stage); + } else ok(FALSE, "unexpected stage %x\n", stage);
@@ -3331,6 +3396,10 @@ static void test_debugger(void)
if (stage == 12|| stage == 13) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } + else if (stage == 14 || stage == 15) + { + test_debugger_xstate(pi.hThread, &ctx, stage); + } else ok(FALSE, "unexpected stage %x\n", stage);
@@ -5957,6 +6026,57 @@ static void test_breakpoint(DWORD numexc) pRtlRemoveVectoredExceptionHandler(vectored_handler); }
+#if defined(__i386__) || defined(__x86_64__) +static BYTE except_code_set_ymm0[] = +{ +#ifdef __x86_64__ + 0x48, +#endif + 0xb8, /* mov imm,%ax */ + 0x00, 0x00, 0x00, 0x00, +#ifdef __x86_64__ + 0x00, 0x00, 0x00, 0x00, +#endif + + 0xc5, 0xfc, 0x10, 0x00, /* vmovups (%ax),%ymm0 */ + 0xcc, /* int3 */ + 0xc5, 0xfc, 0x11, 0x00, /* vmovups %ymm0,(%ax) */ + 0xc3, /* ret */ +}; + +static void test_debuggee_xstate(void) +{ + void (CDECL *func)(void) = code_mem; + unsigned int address_offset, i; + unsigned int data[8]; + + if (!pRtlGetEnabledExtendedFeatures || !pRtlGetEnabledExtendedFeatures(1 << XSTATE_AVX)) + { + memcpy(code_mem, breakpoint_code, sizeof(breakpoint_code)); + func(); + return; + } + + memcpy(code_mem, except_code_set_ymm0, sizeof(except_code_set_ymm0)); + address_offset = sizeof(void *) == 8 ? 2 : 1; + *(void **)((BYTE *)code_mem + address_offset) = data; + + for (i = 0; i < ARRAY_SIZE(data); ++i) + data[i] = i + 1; + + func(); + + for (i = 0; i < 4; ++i) + ok(data[i] == (test_stage == 14 ? i + 1 : 0x28282828), + "Got unexpected data %#x, test_stage %u, i %u.\n", data[i], test_stage, i); + + for ( ; i < ARRAY_SIZE(data); ++i) + ok(data[i] == (test_stage == 14 ? i + 1 : 0x48484848) + || broken(test_stage == 15 && data[i] == i + 1) /* Win7 */, + "Got unexpected data %#x, test_stage %u, i %u.\n", data[i], test_stage, i); +} +#endif + static DWORD invalid_handle_exceptions;
static LONG CALLBACK invalid_handle_vectored_handler(EXCEPTION_POINTERS *ExceptionInfo) @@ -6593,22 +6713,6 @@ static void wait_for_thread_next_suspend(HANDLE thread)
static void test_extended_context(void) { - static BYTE except_code_set_ymm0[] = - { -#ifdef __x86_64__ - 0x48, -#endif - 0xb8, /* mov imm,%ax */ - 0x00, 0x00, 0x00, 0x00, -#ifdef __x86_64__ - 0x00, 0x00, 0x00, 0x00, -#endif - - 0xc5, 0xfc, 0x10, 0x00, /* vmovups (%ax),%ymm0 */ - 0xcc, /* int3 */ - 0xc5, 0xfc, 0x11, 0x00, /* vmovups %ymm0,(%ax) */ - 0xc3, /* ret */ - }; static BYTE except_code_reset_ymm_state[] = { #ifdef __x86_64__ @@ -8029,6 +8133,12 @@ START_TEST(exception) test_closehandle(1, (HANDLE)0xdeadbeef); test_stage = 13; test_closehandle(0, 0); /* Special case. */ +#if defined(__i386__) || defined(__x86_64__) + test_stage = 14; + test_debuggee_xstate(); + test_stage = 15; + test_debuggee_xstate(); +#endif
/* rest of tests only run in parent */ return;