Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/ntdll/tests/exception.c | 160 +++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 1effffd421f..460f0e9a03e 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -30,6 +30,7 @@ #include "winternl.h" #include "excpt.h" #include "wine/test.h" +#include "intrin.h"
static void *code_mem;
@@ -43,6 +44,7 @@ static ULONG (WINAPI *pRtlRemoveVectoredExceptionHandler)(PVOID handler); static PVOID (WINAPI *pRtlAddVectoredContinueHandler)(ULONG first, PVECTORED_EXCEPTION_HANDLER func); static ULONG (WINAPI *pRtlRemoveVectoredContinueHandler)(PVOID handler); static void (WINAPI *pRtlSetUnhandledExceptionFilter)(PRTL_EXCEPTION_FILTER filter); +static ULONG64 (WINAPI *pRtlGetEnabledExtendedFeatures)(ULONG64); static NTSTATUS (WINAPI *pNtReadVirtualMemory)(HANDLE, const void*, void*, SIZE_T, SIZE_T*); static NTSTATUS (WINAPI *pNtTerminateProcess)(HANDLE handle, LONG exit_code); static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG); @@ -5458,6 +5460,161 @@ static void test_unload_trace(void) } }
+#if defined(__i386__) || defined(__x86_64__) + +static const unsigned int test_extended_context_data[8] = {1, 2, 3, 4, 5, 6, 7, 8}; +static const unsigned test_extended_context_spoil_data1[8] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80}; +static const unsigned test_extended_context_spoil_data2[8] = {0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75, 0x85}; + +static BOOL test_extended_context_modified_state; + +static DWORD test_extended_context_handler(EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, + CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher) +{ + static const ULONG64 expected_compaction_mask = 0x8000000000000004; + CONTEXT_EX *xctx = (CONTEXT_EX *)(context + 1); + unsigned int *context_ymm_data; + DWORD expected_min_offset; + BOOL compaction; + int regs[4]; + XSTATE *xs; + + /* Since we got xstates enabled by OS this cpuid level should be supported. */ + __cpuidex(regs, 0xd, 1); + compaction = regs[0] & 2; + todo_wine ok((context->ContextFlags & (CONTEXT_FULL | CONTEXT_XSTATE)) == (CONTEXT_FULL | CONTEXT_XSTATE), + "Got unexpected ContextFlags %#x.\n", context->ContextFlags); + + if ((context->ContextFlags & (CONTEXT_FULL | CONTEXT_XSTATE)) != (CONTEXT_FULL | CONTEXT_XSTATE)) + goto done; + +#ifdef __x86_64__ + { + /* Unwind contexts do not inherit xstate information. */ + DISPATCHER_CONTEXT *dispatch = (DISPATCHER_CONTEXT *)dispatcher; + + ok(!(dispatch->ContextRecord->ContextFlags & 0x40), "Got unexpected ContextRecord->ContextFlags %#x.\n", + dispatch->ContextRecord->ContextFlags); + } +#endif + + ok(xctx->Legacy.Offset == -(int)(sizeof(CONTEXT)), "Got unexpected Legacy.Offset %d.\n", xctx->Legacy.Offset); + ok(xctx->Legacy.Length == sizeof(CONTEXT), "Got unexpected Legacy.Length %d.\n", xctx->Legacy.Length); + ok(xctx->All.Offset == -(int)sizeof(CONTEXT), "Got unexpected All.Offset %d.\n", xctx->All.Offset); + ok(xctx->All.Length == sizeof(CONTEXT) + xctx->XState.Offset + xctx->XState.Length, + "Got unexpected All.Offset %d.\n", xctx->All.Offset); + expected_min_offset = sizeof(void *) == 8 ? sizeof(CONTEXT_EX) + sizeof(EXCEPTION_RECORD) : sizeof(CONTEXT_EX); + ok(xctx->XState.Offset >= expected_min_offset, + "Got unexpected XState.Offset %d.\n", xctx->XState.Offset); + ok(xctx->XState.Length >= sizeof(XSTATE), "Got unexpected XState.Length %d.\n", xctx->XState.Length); + + xs = (XSTATE *)((char *)xctx + xctx->XState.Offset); + context_ymm_data = (unsigned int *)&xs->YmmContext; + ok(!((ULONG_PTR)xs % 64), "Got unexpected xs %p.\n", xs); + + ok((compaction && (xs->CompactionMask & (expected_compaction_mask | 3)) == expected_compaction_mask) + || (!compaction && !xs->CompactionMask), "Got unexpected CompactionMask %s, compaction %#x.\n", + wine_dbgstr_longlong(xs->CompactionMask), compaction); + + if (test_extended_context_modified_state) + { + ok((xs->Mask & 7) == 4, "Got unexpected Mask %s.\n", wine_dbgstr_longlong(xs->Mask)); + ok(!memcmp(context_ymm_data, test_extended_context_data + 4, sizeof(M128A)), + "Got unexpected context data.\n"); + } + else + { + ok(!xs->Mask, "Got unexpected Mask %s.\n", wine_dbgstr_longlong(xs->Mask)); + /* The save area has garbage in this case, the state should be restored to INIT_STATE + * without using these data. */ + memcpy(context_ymm_data, test_extended_context_spoil_data1 + 4, sizeof(M128A)); + } + +done: +#ifdef __GNUC__ + __asm__ volatile("vmovups %0,%%ymm0" : : "m"(test_extended_context_spoil_data2)); +#endif +#ifdef __x86_64__ + ++context->Rip; +#else + if (*(BYTE *)context->Eip == 0xcc) + ++context->Eip; +#endif + return ExceptionContinueExecution; +} + +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__ + 0x48, +#endif + 0xb8, /* mov imm,%ax */ + 0x00, 0x00, 0x00, 0x00, +#ifdef __x86_64__ + 0x00, 0x00, 0x00, 0x00, +#endif + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xc5, 0xf8, 0x77, /* vzeroupper */ + 0x0f, 0x57, 0xc0, /* xorps %xmm0,%xmm0 */ + 0xcc, /* int3 */ + 0xc5, 0xfc, 0x11, 0x00, /* vmovups %ymm0,(%ax) */ + 0xc3, /* ret */ + }; + unsigned int i, address_offset; + unsigned data[8]; + + address_offset = sizeof(void *) == 8 ? 2 : 1; + *(void **)(except_code_set_ymm0 + address_offset) = data; + *(void **)(except_code_reset_ymm_state + address_offset) = data; + + if (!pRtlGetEnabledExtendedFeatures || !(pRtlGetEnabledExtendedFeatures(~(ULONG64)0) & (1 << XSTATE_AVX))) + { + skip("AVX is not supported.\n"); + return; + } + + memset(data, 0xff, sizeof(data)); + test_extended_context_modified_state = FALSE; + run_exception_test(test_extended_context_handler, NULL, except_code_reset_ymm_state, + ARRAY_SIZE(except_code_reset_ymm_state), PAGE_EXECUTE_READ); + for (i = 0; i < 8; ++i) + { + /* Older Windows version do not reset AVX context to INIT_STATE on x86. */ + todo_wine_if(i >= 4) + ok(!data[i] || broken(i >= 4 && sizeof(void *) == 4 && data[i] == test_extended_context_spoil_data2[i]), + "Got unexpected data %#x, i %u.\n", data[i], i); + } + + memcpy(data, test_extended_context_data, sizeof(data)); + test_extended_context_modified_state = TRUE; + run_exception_test(test_extended_context_handler, NULL, except_code_set_ymm0, + ARRAY_SIZE(except_code_set_ymm0), PAGE_EXECUTE_READ); + + for (i = 0; i < 8; ++i) + todo_wine_if(i >= 4) + ok(data[i] == test_extended_context_data[i], "Got unexpected data %#x, i %u.\n", data[i], i); +} +#endif + START_TEST(exception) { HMODULE hntdll = GetModuleHandleA("ntdll.dll"); @@ -5500,6 +5657,7 @@ START_TEST(exception) X(NtResumeProcess); X(RtlGetUnloadEventTrace); X(RtlGetUnloadEventTraceEx); + X(RtlGetEnabledExtendedFeatures); #undef X
pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process"); @@ -5582,6 +5740,7 @@ START_TEST(exception) test_dpe_exceptions(); test_prot_fault(); test_kiuserexceptiondispatcher(); + test_extended_context();
#elif defined(__x86_64__)
@@ -5620,6 +5779,7 @@ START_TEST(exception) test_dynamic_unwind(); else skip( "Dynamic unwind functions not found\n" ); + test_extended_context(); #endif
test_debugger();
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/ntdll/signal_x86_64.c | 2 + dlls/ntdll/tests/exception.c | 3 +- dlls/ntdll/unix/signal_x86_64.c | 114 ++++++++++++++++++++++++++------ dlls/ntdll/unix/unix_private.h | 6 ++ dlls/ntdll/unixlib.h | 30 +++++++++ 5 files changed, 134 insertions(+), 21 deletions(-)
diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c index e1cf7f3e013..564b74b7be6 100644 --- a/dlls/ntdll/signal_x86_64.c +++ b/dlls/ntdll/signal_x86_64.c @@ -428,6 +428,8 @@ static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_contex NTSTATUS status;
context = *orig_context; + context.ContextFlags &= ~0x40; /* Clear xstate flag. */ + dispatch.TargetIp = 0; dispatch.ContextRecord = &context; dispatch.HistoryTable = &table; diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 460f0e9a03e..cf704093fce 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -5482,7 +5482,8 @@ static DWORD test_extended_context_handler(EXCEPTION_RECORD *rec, EXCEPTION_REGI /* Since we got xstates enabled by OS this cpuid level should be supported. */ __cpuidex(regs, 0xd, 1); compaction = regs[0] & 2; - todo_wine ok((context->ContextFlags & (CONTEXT_FULL | CONTEXT_XSTATE)) == (CONTEXT_FULL | CONTEXT_XSTATE), + todo_wine_if(sizeof(void *) == 4) + ok((context->ContextFlags & (CONTEXT_FULL | CONTEXT_XSTATE)) == (CONTEXT_FULL | CONTEXT_XSTATE), "Got unexpected ContextFlags %#x.\n", context->ContextFlags);
if ((context->ContextFlags & (CONTEXT_FULL | CONTEXT_XSTATE)) != (CONTEXT_FULL | CONTEXT_XSTATE)) diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 638ad5cab76..370f1f36fd7 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -78,6 +78,7 @@ #define WIN32_NO_STATUS #include "windef.h" #include "winternl.h" +#include "ddk/wdm.h" #include "wine/exception.h" #include "wine/list.h" #include "wine/asm.h" @@ -94,6 +95,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(seh); #include <asm/prctl.h> static inline int arch_prctl( int func, void *ptr ) { return syscall( __NR_arch_prctl, func, ptr ); }
+#ifndef FP_XSTATE_MAGIC1 +#define FP_XSTATE_MAGIC1 0x46505853 +#endif + #define RAX_sig(context) ((context)->uc_mcontext.gregs[REG_RAX]) #define RBX_sig(context) ((context)->uc_mcontext.gregs[REG_RBX]) #define RCX_sig(context) ((context)->uc_mcontext.gregs[REG_RCX]) @@ -118,6 +123,7 @@ static inline int arch_prctl( int func, void *ptr ) { return syscall( __NR_arch_ #define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO]) #define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR]) #define FPU_sig(context) ((XMM_SAVE_AREA32 *)((context)->uc_mcontext.fpregs)) +#define XState_sig(fpu) (((unsigned int *)fpu->Reserved4)[12] == FP_XSTATE_MAGIC1 ? (XSTATE *)(fpu + 1) : NULL)
#elif defined(__FreeBSD__) || defined (__FreeBSD_kernel__)
@@ -148,6 +154,7 @@ static inline int arch_prctl( int func, void *ptr ) { return syscall( __NR_arch_ #define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno) #define ERROR_sig(context) ((context)->uc_mcontext.mc_err) #define FPU_sig(context) ((XMM_SAVE_AREA32 *)((context)->uc_mcontext.mc_fpstate)) +#define XState_sig(context) NULL
#elif defined(__NetBSD__)
@@ -178,6 +185,7 @@ static inline int arch_prctl( int func, void *ptr ) { return syscall( __NR_arch_ #define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO]) #define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR]) #define FPU_sig(context) ((XMM_SAVE_AREA32 *)((context)->uc_mcontext.__fpregs)) +#define XState_sig(context) NULL
#elif defined (__APPLE__)
@@ -205,6 +213,7 @@ static inline int arch_prctl( int func, void *ptr ) { return syscall( __NR_arch_ #define TRAP_sig(context) ((context)->uc_mcontext->__es.__trapno) #define ERROR_sig(context) ((context)->uc_mcontext->__es.__err) #define FPU_sig(context) ((XMM_SAVE_AREA32 *)&(context)->uc_mcontext->__fs.__fpu_fcw) +#define XState_sig(context) NULL
#else #error You must define the signal context functions for your platform @@ -237,16 +246,21 @@ enum i386_trap_code struct stack_layout { CONTEXT context; - ULONG64 unknown[4]; + CONTEXT_EX context_ex; EXCEPTION_RECORD rec; ULONG64 rsi; ULONG64 rdi; ULONG64 rbp; ULONG64 rip; - ULONG64 red_zone[16]; + ULONG64 align; + char xstate[0]; /* If xstate is present it is allocated + * dynamically to provide 64 byte alignment. */ };
-C_ASSERT( sizeof(struct stack_layout) == 0x630 ); /* Should match the size in call_user_exception_dispatcher(). */ +C_ASSERT((offsetof(struct stack_layout, xstate) == sizeof(struct stack_layout))); + +C_ASSERT( sizeof(XSTATE) == 0x140 ); +C_ASSERT( sizeof(struct stack_layout) == 0x5b0 ); /* Should match the size in call_user_exception_dispatcher(). */
struct syscall_frame { @@ -1408,8 +1422,10 @@ static inline void set_sigcontext( const CONTEXT *context, ucontext_t *sigcontex * * Set the register values from a sigcontext. */ -static void save_context( CONTEXT *context, const ucontext_t *sigcontext ) +static void save_context( struct xcontext *xcontext, const ucontext_t *sigcontext ) { + CONTEXT *context = &xcontext->c; + context->ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_DEBUG_REGISTERS; context->Rax = RAX_sig(sigcontext); context->Rcx = RCX_sig(sigcontext); @@ -1458,6 +1474,11 @@ static void save_context( CONTEXT *context, const ucontext_t *sigcontext ) 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; } }
@@ -1467,8 +1488,10 @@ static void save_context( CONTEXT *context, const ucontext_t *sigcontext ) * * Build a sigcontext from the register values. */ -static void restore_context( const CONTEXT *context, ucontext_t *sigcontext ) +static void restore_context( const struct xcontext *xcontext, ucontext_t *sigcontext ) { + const CONTEXT *context = &xcontext->c; + amd64_thread_data()->dr0 = context->Dr0; amd64_thread_data()->dr1 = context->Dr1; amd64_thread_data()->dr2 = context->Dr2; @@ -1813,7 +1836,6 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) return STATUS_SUCCESS; }
- extern void CDECL raise_func_trampoline( void *dispatcher );
__ASM_GLOBAL_FUNC( raise_func_trampoline, @@ -1822,10 +1844,12 @@ __ASM_GLOBAL_FUNC( raise_func_trampoline, /*********************************************************************** * setup_raise_exception */ -static void setup_raise_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec, CONTEXT *context ) +static void setup_raise_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec, struct xcontext *xcontext ) { void *stack_ptr = (void *)(RSP_sig(sigcontext) & ~15); + CONTEXT *context = &xcontext->c; struct stack_layout *stack; + size_t stack_size; NTSTATUS status;
if (rec->ExceptionCode == EXCEPTION_SINGLE_STEP) @@ -1848,16 +1872,37 @@ static void setup_raise_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec status = send_debug_event( rec, context, TRUE ); if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED) { - restore_context( context, sigcontext ); + restore_context( xcontext, sigcontext ); return; }
/* fix up instruction pointer in context for EXCEPTION_BREAKPOINT */ if (rec->ExceptionCode == EXCEPTION_BREAKPOINT) context->Rip--;
- stack = virtual_setup_exception( stack_ptr, sizeof(*stack), rec ); + stack_size = sizeof(*stack); + if (xcontext->xstate) + { + stack_size += (ULONG_PTR)stack_ptr - (((ULONG_PTR)stack_ptr + - sizeof(XSTATE)) & ~(ULONG_PTR)63); + } + + stack = virtual_setup_exception( stack_ptr, stack_size, rec ); stack->rec = *rec; stack->context = *context; + if (xcontext->xstate) + { + XSTATE *dst_xs = (XSTATE *)stack->xstate; + + assert( !((ULONG_PTR)dst_xs & 63) ); + context_init_xstate( &stack->context, stack->xstate ); + dst_xs->CompactionMask = user_shared_data->XState.CompactionEnabled ? 0x8000000000000004 : 0; + if (xcontext->xstate->Mask & 4) + { + dst_xs->Mask = 4; + memcpy( &dst_xs->YmmContext, &xcontext->xstate->YmmContext, sizeof(dst_xs->YmmContext) ); + } + } + RIP_sig(sigcontext) = (ULONG_PTR)raise_func_trampoline; R8_sig(sigcontext) = (ULONG_PTR)pKiUserExceptionDispatcher; RSP_sig(sigcontext) = (ULONG_PTR)stack; @@ -1875,7 +1920,7 @@ static void setup_raise_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec */ static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec ) { - CONTEXT context; + struct xcontext context;
rec->ExceptionAddress = (void *)RIP_sig(sigcontext); save_context( &context, sigcontext ); @@ -1972,7 +2017,31 @@ void WINAPI do_call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *c { struct syscall_frame *frame = amd64_thread_data()->syscall_frame;
- memmove(&stack->context, context, sizeof(*context)); + if ((context->ContextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE) + { + CONTEXT_EX *xctx = (CONTEXT_EX *)context + 1; + XSTATE *xs, *src_xs, xs_buf; + + src_xs = xstate_from_context(context); + if ((CONTEXT *)src_xs >= &stack->context + 1 || src_xs + 1 <= (XSTATE *)&stack->context) + { + xs = src_xs; + } + else + { + xs = &xs_buf; + memcpy(xs, src_xs, sizeof(*xs)); + } + + memmove(&stack->context, context, sizeof(*context) + sizeof(*xctx)); + assert(!((ULONG_PTR)stack->xstate & 63)); + context_init_xstate(&stack->context, stack->xstate); + memcpy(stack->xstate, xs, sizeof(*xs)); + } + else + { + memmove(&stack->context, context, sizeof(*context)); + } memcpy(&stack->rec, rec, sizeof(*rec));
/* fix up instruction pointer in context for EXCEPTION_BREAKPOINT */ @@ -1985,7 +2054,11 @@ void WINAPI do_call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *c __ASM_GLOBAL_FUNC( call_user_exception_dispatcher, "movq 0x98(%rdx),%r9\n\t" /* context->Rsp */ "andq $~0xf,%r9\n\t" - "subq $0x630,%r9\n\t" /* sizeof(struct stack_layout) */ + "bt $6,0x30(%rdx)\n\t" /* context->ContextFlags, CONTEXT_XSTATE bit. */ + "jnc 1f\n\t" + "subq $0x140,%r9\n\t" /* sizeof(XSTATE) */ + "andq $~63,%r9\n\t" + "1:subq $0x5b0,%r9\n\t" /* sizeof(struct stack_layout) */ "cmpq %rsp,%r9\n\t" "cmovbq %r9,%rsp\n\t" "jmp " __ASM_NAME("do_call_user_exception_dispatcher") "\n\t") @@ -2187,8 +2260,10 @@ static void install_bpf(struct sigaction *sig_act) * * Handle an interrupt. */ -static inline BOOL handle_interrupt( ucontext_t *sigcontext, EXCEPTION_RECORD *rec, CONTEXT *context ) +static inline BOOL handle_interrupt( ucontext_t *sigcontext, EXCEPTION_RECORD *rec, struct xcontext *xcontext ) { + CONTEXT *context = &xcontext->c; + switch (ERROR_sig(sigcontext) >> 3) { case 0x2c: @@ -2213,11 +2288,10 @@ static inline BOOL handle_interrupt( ucontext_t *sigcontext, EXCEPTION_RECORD *r default: return FALSE; } - setup_raise_exception( sigcontext, rec, context ); + setup_raise_exception( sigcontext, rec, xcontext ); return TRUE; }
- /********************************************************************** * segv_handler * @@ -2226,7 +2300,7 @@ static inline BOOL handle_interrupt( ucontext_t *sigcontext, EXCEPTION_RECORD *r static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) { EXCEPTION_RECORD rec = { 0 }; - CONTEXT context; + struct xcontext context; ucontext_t *ucontext = sigcontext;
rec.ExceptionAddress = (void *)RIP_sig(ucontext); @@ -2250,7 +2324,7 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) case TRAP_x86_PROTFLT: /* General protection fault */ { WORD err = ERROR_sig(ucontext); - if (!err && (rec.ExceptionCode = is_privileged_instr( &context ))) break; + if (!err && (rec.ExceptionCode = is_privileged_instr( &context.c ))) break; if ((err & 7) == 2 && handle_interrupt( ucontext, &rec, &context )) return; rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION; rec.NumberParameters = 2; @@ -2293,7 +2367,7 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext ) { EXCEPTION_RECORD rec = { 0 }; - CONTEXT context; + struct xcontext context; ucontext_t *ucontext = sigcontext;
rec.ExceptionAddress = (void *)RIP_sig(ucontext); @@ -2412,10 +2486,10 @@ static void quit_handler( int signal, siginfo_t *siginfo, void *ucontext ) */ static void usr1_handler( int signal, siginfo_t *siginfo, void *ucontext ) { - CONTEXT context; + struct xcontext context;
save_context( &context, ucontext ); - wait_suspend( &context ); + wait_suspend( &context.c ); restore_context( &context, ucontext ); }
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index c9f8871fd26..68c60f78b7f 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -400,4 +400,10 @@ static inline int ntdll_wcsnicmp( const WCHAR *str1, const WCHAR *str2, int n ) #define towupper(c) ntdll_towupper(c) #define towlower(c) ntdll_towlower(c)
+struct xcontext +{ + CONTEXT c; + XSTATE *xstate; /* Points to xstate in sigcontext. */ +}; + #endif /* __NTDLL_UNIX_PRIVATE_H */ diff --git a/dlls/ntdll/unixlib.h b/dlls/ntdll/unixlib.h index 2f57873671c..70b6def530a 100644 --- a/dlls/ntdll/unixlib.h +++ b/dlls/ntdll/unixlib.h @@ -129,4 +129,34 @@ struct unix_funcs const char *function ); };
+static inline XSTATE *xstate_from_context( const CONTEXT *context ) +{ + CONTEXT_EX *xctx = (CONTEXT_EX *)(context + 1); + + if ((context->ContextFlags & CONTEXT_XSTATE) != CONTEXT_XSTATE) + return NULL; + + return (XSTATE *)((char *)(context + 1) + xctx->XState.Offset); +} + +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->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) ); +} + #endif /* __NTDLL_UNIXLIB_H */
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=77412
Your paranoid android.
=== w1064v1507 (testbot log) ===
An error occurred while waiting for the test to complete: the 3968 process does not exist or is not a child process
=== w1064v1809 (testbot log) ===
An error occurred while waiting for the test to complete: network read got a premature EOF (wait2/connect:AgentVersion.h:0/9)
=== w1064v1809_2scr (testbot log) ===
An error occurred while waiting for the test to complete: network read got a premature EOF (wait2/connect:AgentVersion.h:0/9)
=== w1064v1809_ar (testbot log) ===
An error occurred while waiting for the test to complete: network read got a premature EOF (wait2/connect:AgentVersion.h:0/9)
=== w1064v1809_he (testbot log) ===
An error occurred while waiting for the test to complete: the 5384 process does not exist or is not a child process
=== w1064v1809_ja (testbot log) ===
An error occurred while waiting for the test to complete: the 1152 process does not exist or is not a child process
=== w1064v1809_zh_CN (testbot log) ===
An error occurred while waiting for the test to complete: the 1436 process does not exist or is not a child process
=== w1064v1507 (testbot log) ===
An error occurred while waiting for the test to complete: the 3952 process does not exist or is not a child process
=== w1064v1809 (testbot log) ===
An error occurred while waiting for the test to complete: the 6156 process does not exist or is not a child process
=== debiant (32 bit WoW report) ===
ntdll: change.c:241: Test failed: should be ready
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/ntdll/tests/exception.c | 4 ++-- dlls/ntdll/unix/signal_x86_64.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index cf704093fce..1bbf9f4f912 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -5600,7 +5600,7 @@ static void test_extended_context(void) for (i = 0; i < 8; ++i) { /* Older Windows version do not reset AVX context to INIT_STATE on x86. */ - todo_wine_if(i >= 4) + todo_wine_if(i >= 4 && sizeof(void *) == 4) ok(!data[i] || broken(i >= 4 && sizeof(void *) == 4 && data[i] == test_extended_context_spoil_data2[i]), "Got unexpected data %#x, i %u.\n", data[i], i); } @@ -5611,7 +5611,7 @@ static void test_extended_context(void) ARRAY_SIZE(except_code_set_ymm0), PAGE_EXECUTE_READ);
for (i = 0; i < 8; ++i) - todo_wine_if(i >= 4) + todo_wine_if(i >= 4 && sizeof(void *) == 4) ok(data[i] == test_extended_context_data[i], "Got unexpected data %#x, i %u.\n", data[i], i); } #endif diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 370f1f36fd7..53b9d98e80c 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -1543,6 +1543,34 @@ __ASM_GLOBAL_FUNC( set_full_cpu_context, "iretq" );
+/*********************************************************************** + * restore_xstate + * + * Restore the XState context. + */ +static void restore_xstate( const CONTEXT *context ) +{ + XSAVE_FORMAT *xrstor_base; + XSTATE *xs; + + if (!(xs = xstate_from_context( context ))) + return; + + xrstor_base = (XSAVE_FORMAT *)xs - 1; + + if (!(xs->CompactionMask & ((ULONG64)1 << 63))) + { + /* Non-compacted xrstor will load Mxcsr regardless of the specified mask. Loading garbage there + * may lead to fault. We have only padding, no more used EXCEPTION_RECORD or unused context fields + * at the MxCsr restore location, so just put it there. */ + assert( (void *)&xrstor_base->MxCsr > (void *)context->VectorRegister ); + xrstor_base->MxCsr = context->u.FltSave.MxCsr; + xrstor_base->MxCsr_Mask = context->u.FltSave.MxCsr_Mask; + } + + __asm__ volatile("xor %%edx,%%edx; mov $4,%%eax; xrstor64 %0" : : "m"(*xrstor_base) : "eax", "edx"); +} + /*********************************************************************** * get_server_context_flags * @@ -1733,6 +1761,8 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context ) } }
+ restore_xstate( context ); + if (flags & CONTEXT_FULL) { if (!(flags & CONTEXT_CONTROL))
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=77413
Your paranoid android.
=== w1064v1507 (testbot log) ===
An error occurred while waiting for the test to complete: the 3944 process does not exist or is not a child process
=== w1064v1809 (testbot log) ===
An error occurred while waiting for the test to complete: the 6172 process does not exist or is not a child process
=== w1064v1809_2scr (testbot log) ===
An error occurred while waiting for the test to complete: network read got a premature EOF (wait2/connect:AgentVersion.h:0/9)
=== w1064v1809_ar (testbot log) ===
An error occurred while waiting for the test to complete: network read got a premature EOF (wait2/connect:AgentVersion.h:0/9)
=== w1064v1809_he (testbot log) ===
An error occurred while waiting for the test to complete: the 2140 process does not exist or is not a child process
=== w1064v1809_ja (testbot log) ===
An error occurred while waiting for the test to complete: the 5428 process does not exist or is not a child process
=== w1064v1809_zh_CN (testbot log) ===
An error occurred while waiting for the test to complete: the 1408 process does not exist or is not a child process
=== w1064v1507 (testbot log) ===
An error occurred while waiting for the test to complete: the 3952 process does not exist or is not a child process
=== w1064v1809 (testbot log) ===
An error occurred while waiting for the test to complete: network read got a premature EOF (wait2/connect:AgentVersion.h:0/9)
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/ntdll/tests/exception.c | 2 +- dlls/ntdll/unix/signal_i386.c | 146 ++++++++++++++++++++++++---------- 2 files changed, 106 insertions(+), 42 deletions(-)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 1bbf9f4f912..860221366ce 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -5482,7 +5482,7 @@ static DWORD test_extended_context_handler(EXCEPTION_RECORD *rec, EXCEPTION_REGI /* Since we got xstates enabled by OS this cpuid level should be supported. */ __cpuidex(regs, 0xd, 1); compaction = regs[0] & 2; - todo_wine_if(sizeof(void *) == 4) + ok((context->ContextFlags & (CONTEXT_FULL | CONTEXT_XSTATE)) == (CONTEXT_FULL | CONTEXT_XSTATE), "Got unexpected ContextFlags %#x.\n", context->ContextFlags);
diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index bc30dd34df8..791ffe90940 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -33,6 +33,7 @@ #include <stdarg.h> #include <stdio.h> #include <sys/types.h> +#include <assert.h> #ifdef HAVE_UNISTD_H # include <unistd.h> #endif @@ -56,6 +57,8 @@ #include "ntstatus.h" #define WIN32_NO_STATUS #include "windef.h" +#include "winternl.h" +#include "ddk/wdm.h" #include "wine/asm.h" #include "wine/exception.h" #include "unix_private.h" @@ -122,6 +125,10 @@ typedef struct ucontext } ucontext_t; #endif /* HAVE_SYS_UCONTEXT_H */
+#ifndef FP_XSTATE_MAGIC1 +#define FP_XSTATE_MAGIC1 0x46505853 +#endif + #define EAX_sig(context) ((context)->uc_mcontext.gregs[REG_EAX]) #define EBX_sig(context) ((context)->uc_mcontext.gregs[REG_EBX]) #define ECX_sig(context) ((context)->uc_mcontext.gregs[REG_ECX]) @@ -145,6 +152,7 @@ typedef struct ucontext
#define FPU_sig(context) ((FLOATING_SAVE_AREA*)((context)->uc_mcontext.fpregs)) #define FPUX_sig(context) (FPU_sig(context) && !((context)->uc_mcontext.fpregs->status >> 16) ? (XSAVE_FORMAT *)(FPU_sig(context) + 1) : NULL) +#define XState_sig(fpu) (((unsigned int *)fpu->Reserved4)[12] == FP_XSTATE_MAGIC1 ? (XSTATE *)(fpu + 1) : NULL)
#ifdef __ANDROID__ /* custom signal restorer since we may have unmapped the one in vdso, and bionic doesn't check for that */ @@ -208,6 +216,7 @@ static inline int set_thread_area( struct modify_ldt_s *ptr )
#define FPU_sig(context) NULL /* FIXME */ #define FPUX_sig(context) NULL /* FIXME */ +#define XState_sig(context) NULL /* FIXME */
#elif defined (__OpenBSD__)
@@ -238,6 +247,7 @@ static inline int set_thread_area( struct modify_ldt_s *ptr )
#define FPU_sig(context) NULL /* FIXME */ #define FPUX_sig(context) NULL /* FIXME */ +#define XState_sig(context) NULL /* FIXME */
#define T_MCHK T_MACHK #define T_XMMFLT T_XFTRAP @@ -283,6 +293,7 @@ static inline int set_thread_area( struct modify_ldt_s *ptr )
#define FPU_sig(context) NULL /* FIXME */ #define FPUX_sig(context) NULL /* FIXME */ +#define XState_sig(context) NULL /* FIXME */
#elif defined (__APPLE__)
@@ -310,6 +321,7 @@ static inline int set_thread_area( struct modify_ldt_s *ptr ) #define ERROR_sig(context) ((context)->uc_mcontext->__es.__err) #define FPU_sig(context) NULL #define FPUX_sig(context) ((XSAVE_FORMAT *)&(context)->uc_mcontext->__fs.__fpu_fcw) +#define XState_sig(context) NULL /* FIXME */ #else #define EAX_sig(context) ((context)->uc_mcontext->ss.eax) #define EBX_sig(context) ((context)->uc_mcontext->ss.ebx) @@ -331,6 +343,7 @@ static inline int set_thread_area( struct modify_ldt_s *ptr ) #define ERROR_sig(context) ((context)->uc_mcontext->es.err) #define FPU_sig(context) NULL #define FPUX_sig(context) ((XSAVE_FORMAT *)&(context)->uc_mcontext->fs.fpu_fcw) +#define XState_sig(context) NULL /* FIXME */ #endif
#elif defined(__NetBSD__) @@ -361,6 +374,7 @@ static inline int set_thread_area( struct modify_ldt_s *ptr )
#define FPU_sig(context) NULL #define FPUX_sig(context) ((XSAVE_FORMAT *)&((context)->uc_mcontext.__fpregs)) +#define XState_sig(context) NULL /* FIXME */
#define T_MCHK T_MCA #define T_XMMFLT T_XMM @@ -393,6 +407,7 @@ static inline int set_thread_area( struct modify_ldt_s *ptr )
#define FPU_sig(context) ((FLOATING_SAVE_AREA *)&(context)->uc_mcontext.fpregs.fp_reg_set.fpchip_state) #define FPUX_sig(context) NULL +#define XState_sig(context) NULL /* FIXME */
#else #error You must define the signal context functions for your platform @@ -752,10 +767,11 @@ static void fpux_to_fpu( FLOATING_SAVE_AREA *fpu, const XSAVE_FORMAT *fpux ) * * Build a context structure from the signal info. */ -static inline void save_context( CONTEXT *context, const ucontext_t *sigcontext ) +static inline void save_context( struct xcontext *xcontext, const ucontext_t *sigcontext ) { FLOATING_SAVE_AREA *fpu = FPU_sig(sigcontext); XSAVE_FORMAT *fpux = FPUX_sig(sigcontext); + CONTEXT *context = &xcontext->c;
memset(context, 0, sizeof(*context)); context->ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; @@ -792,6 +808,11 @@ static inline void save_context( CONTEXT *context, const ucontext_t *sigcontext 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 (!fpu && !fpux) save_fpu( context ); } @@ -802,10 +823,11 @@ static inline void save_context( CONTEXT *context, const ucontext_t *sigcontext * * Restore the signal info from the context. */ -static inline void restore_context( const CONTEXT *context, ucontext_t *sigcontext ) +static inline void restore_context( const struct xcontext *xcontext, ucontext_t *sigcontext ) { FLOATING_SAVE_AREA *fpu = FPU_sig(sigcontext); XSAVE_FORMAT *fpux = FPUX_sig(sigcontext); + const CONTEXT *context = &xcontext->c;
x86_thread_data()->dr0 = context->Dr0; x86_thread_data()->dr1 = context->Dr1; @@ -831,7 +853,18 @@ static inline void restore_context( const CONTEXT *context, ucontext_t *sigconte SS_sig(sigcontext) = context->SegSs;
if (fpu) *fpu = context->FloatSave; - if (fpux) memcpy( fpux, context->ExtendedRegisters, sizeof(*fpux) ); + if (fpux) + { + XSTATE *src_xs, *dst_xs; + + memcpy( fpux, context->ExtendedRegisters, sizeof(*fpux) ); + + if ((dst_xs = XState_sig(fpux)) && (src_xs = xstate_from_context( context ))) + { + memcpy( &dst_xs->YmmContext, &src_xs->YmmContext, sizeof(dst_xs->YmmContext) ); + dst_xs->Mask |= src_xs->Mask; + } + } if (!fpu && !fpux) restore_fpu( context ); }
@@ -1442,48 +1475,76 @@ static BOOL check_atl_thunk( ucontext_t *sigcontext, EXCEPTION_RECORD *rec, CONT * * Setup the exception record and context on the thread stack. */ -static void *setup_exception_record( ucontext_t *sigcontext, EXCEPTION_RECORD *rec, CONTEXT *context ) +static void *setup_exception_record( ucontext_t *sigcontext, EXCEPTION_RECORD *rec, struct xcontext *xcontext ) { void *stack = init_handler( sigcontext );
rec->ExceptionAddress = (void *)EIP_sig( sigcontext ); - save_context( context, sigcontext ); + save_context( xcontext, sigcontext ); return stack; }
- /*********************************************************************** * setup_raise_exception * * Change context to setup a call to a raise exception function. */ static void setup_raise_exception( ucontext_t *sigcontext, void *stack_ptr, - EXCEPTION_RECORD *rec, CONTEXT *context ) + EXCEPTION_RECORD *rec, struct xcontext *xcontext ) { - struct + CONTEXT *context = &xcontext->c; + size_t stack_size; + + struct stack_layout { EXCEPTION_RECORD *rec_ptr; /* first arg for KiUserExceptionDispatcher */ CONTEXT *context_ptr; /* second arg for KiUserExceptionDispatcher */ CONTEXT context; + CONTEXT_EX context_ex; EXCEPTION_RECORD rec; DWORD ebp; DWORD eip; + char xstate[0]; } *stack;
+C_ASSERT( (offsetof(struct stack_layout, xstate) == sizeof(struct stack_layout)) ); + NTSTATUS status = send_debug_event( rec, context, TRUE );
if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED) { - restore_context( context, sigcontext ); + restore_context( xcontext, sigcontext ); return; }
/* fix up instruction pointer in context for EXCEPTION_BREAKPOINT */ if (rec->ExceptionCode == EXCEPTION_BREAKPOINT) context->Eip--;
- stack = virtual_setup_exception( stack_ptr, sizeof(*stack), rec ); + stack_size = sizeof(*stack); + if (xcontext->xstate) + { + stack_size += (ULONG_PTR)stack_ptr - (((ULONG_PTR)stack_ptr + - sizeof(XSTATE)) & ~(ULONG_PTR)63); + } + + stack = virtual_setup_exception( stack_ptr, stack_size, rec ); stack->rec = *rec; stack->context = *context; + + if (xcontext->xstate) + { + XSTATE *dst_xs = (XSTATE *)stack->xstate; + + assert(!((ULONG_PTR)dst_xs & 63)); + context_init_xstate( &stack->context, stack->xstate ); + dst_xs->CompactionMask = user_shared_data->XState.CompactionEnabled ? 0x8000000000000004 : 0; + if (xcontext->xstate->Mask & 4) + { + dst_xs->Mask = 4; + memcpy( &dst_xs->YmmContext, &xcontext->xstate->YmmContext, sizeof(dst_xs->YmmContext) ); + } + } + stack->rec_ptr = &stack->rec; stack->context_ptr = &stack->context; ESP_sig(sigcontext) = (DWORD)stack; @@ -1506,9 +1567,10 @@ static void setup_raise_exception( ucontext_t *sigcontext, void *stack_ptr, */ static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec ) { - CONTEXT context; - void *stack = setup_exception_record( sigcontext, rec, &context ); - setup_raise_exception( sigcontext, stack, rec, &context ); + struct xcontext xcontext; + void *stack = setup_exception_record( sigcontext, rec, &xcontext ); + + setup_raise_exception( sigcontext, stack, rec, &xcontext ); }
@@ -1623,8 +1685,10 @@ static inline DWORD get_fpu_code( const CONTEXT *context ) * Handle an interrupt. */ static BOOL handle_interrupt( unsigned int interrupt, ucontext_t *sigcontext, void *stack, - EXCEPTION_RECORD *rec, CONTEXT *context ) + EXCEPTION_RECORD *rec, struct xcontext *xcontext ) { + CONTEXT *context = &xcontext->c; + switch(interrupt) { case 0x2d: @@ -1649,7 +1713,7 @@ static BOOL handle_interrupt( unsigned int interrupt, ucontext_t *sigcontext, vo rec->ExceptionInformation[0] = context->Eax; rec->ExceptionInformation[1] = context->Ecx; rec->ExceptionInformation[2] = context->Edx; - setup_raise_exception( sigcontext, stack, rec, context ); + setup_raise_exception( sigcontext, stack, rec, xcontext ); return TRUE; default: return FALSE; @@ -1665,9 +1729,9 @@ static BOOL handle_interrupt( unsigned int interrupt, ucontext_t *sigcontext, vo static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) { EXCEPTION_RECORD rec = { 0 }; - CONTEXT context; + struct xcontext xcontext; ucontext_t *ucontext = sigcontext; - void *stack = setup_exception_record( sigcontext, &rec, &context ); + void *stack = setup_exception_record( sigcontext, &rec, &xcontext );
switch (TRAP_sig(ucontext)) { @@ -1687,8 +1751,8 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) case TRAP_x86_PROTFLT: /* General protection fault */ { WORD err = ERROR_sig(ucontext); - if (!err && (rec.ExceptionCode = is_privileged_instr( &context ))) break; - if ((err & 7) == 2 && handle_interrupt( err >> 3, ucontext, stack, &rec, &context )) return; + if (!err && (rec.ExceptionCode = is_privileged_instr( &xcontext.c ))) break; + if ((err & 7) == 2 && handle_interrupt( err >> 3, ucontext, stack, &rec, &xcontext )) return; rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION; rec.NumberParameters = 2; rec.ExceptionInformation[0] = 0; @@ -1697,7 +1761,7 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) else { rec.ExceptionInformation[1] = 0xffffffff; - if (check_invalid_gs( ucontext, &context )) return; + if (check_invalid_gs( ucontext, &xcontext.c )) return; } } break; @@ -1714,7 +1778,7 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) NtQueryInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &flags, sizeof(flags), NULL ); if (!(flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION) && - check_atl_thunk( ucontext, &rec, &context )) + check_atl_thunk( ucontext, &rec, &xcontext.c )) return;
/* send EXCEPTION_EXECUTE_FAULT only if data execution prevention is enabled */ @@ -1723,7 +1787,7 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) break; case TRAP_x86_ALIGNFLT: /* Alignment check exception */ /* FIXME: pass through exception handler first? */ - if (context.EFlags & 0x00040000) + if (xcontext.c.EFlags & 0x00040000) { EFL_sig(ucontext) &= ~0x00040000; /* disable AC flag */ return; @@ -1742,7 +1806,7 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; break; } - setup_raise_exception( ucontext, stack, &rec, &context ); + setup_raise_exception( ucontext, stack, &rec, &xcontext ); }
@@ -1754,9 +1818,9 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext ) { EXCEPTION_RECORD rec = { 0 }; - CONTEXT context; + struct xcontext xcontext; ucontext_t *ucontext = sigcontext; - void *stack = setup_exception_record( sigcontext, &rec, &context ); + void *stack = setup_exception_record( sigcontext, &rec, &xcontext );
switch (TRAP_sig(ucontext)) { @@ -1765,15 +1829,15 @@ static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext ) /* when single stepping can't tell whether this is a hw bp or a * single step interrupt. try to avoid as much overhead as possible * and only do a server call if there is any hw bp enabled. */ - if (!(context.EFlags & 0x100) || (context.Dr7 & 0xff)) + if (!(xcontext.c.EFlags & 0x100) || (xcontext.c.Dr7 & 0xff)) { /* (possible) hardware breakpoint, fetch the debug registers */ - DWORD saved_flags = context.ContextFlags; - context.ContextFlags = CONTEXT_DEBUG_REGISTERS; - NtGetContextThread( GetCurrentThread(), &context ); - context.ContextFlags |= saved_flags; /* restore flags */ + DWORD saved_flags = xcontext.c.ContextFlags; + xcontext.c.ContextFlags = CONTEXT_DEBUG_REGISTERS; + NtGetContextThread( GetCurrentThread(), &xcontext.c ); + xcontext.c.ContextFlags |= saved_flags; /* restore flags */ } - context.EFlags &= ~0x100; /* clear single-step flag */ + xcontext.c.EFlags &= ~0x100; /* clear single-step flag */ break; case TRAP_x86_BPTFLT: /* Breakpoint exception */ rec.ExceptionAddress = (char *)rec.ExceptionAddress - 1; /* back up over the int3 instruction */ @@ -1786,7 +1850,7 @@ static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext ) rec.ExceptionInformation[2] = 0; /* FIXME */ break; } - setup_raise_exception( sigcontext, stack, &rec, &context ); + setup_raise_exception( sigcontext, stack, &rec, &xcontext ); }
@@ -1798,9 +1862,9 @@ static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext ) static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext ) { EXCEPTION_RECORD rec = { 0 }; - CONTEXT context; + struct xcontext xcontext; ucontext_t *ucontext = sigcontext; - void *stack = setup_exception_record( sigcontext, &rec, &context ); + void *stack = setup_exception_record( sigcontext, &rec, &xcontext );
switch (TRAP_sig(ucontext)) { @@ -1811,8 +1875,8 @@ static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext ) rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION; break; case TRAP_x86_ARITHTRAP: /* Floating point exception */ - rec.ExceptionCode = get_fpu_code( &context ); - rec.ExceptionAddress = (void *)context.FloatSave.ErrorOffset; + rec.ExceptionCode = get_fpu_code( &xcontext.c ); + rec.ExceptionAddress = (void *)xcontext.c.FloatSave.ErrorOffset; break; case TRAP_x86_CACHEFLT: /* SIMD exception */ /* TODO: @@ -1832,7 +1896,7 @@ static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext ) rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION; break; } - setup_raise_exception( sigcontext, stack, &rec, &context ); + setup_raise_exception( sigcontext, stack, &rec, &xcontext ); }
@@ -1880,12 +1944,12 @@ static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext ) */ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext ) { - CONTEXT context; + struct xcontext xcontext;
init_handler( sigcontext ); - save_context( &context, sigcontext ); - wait_suspend( &context ); - restore_context( &context, sigcontext ); + save_context( &xcontext, sigcontext ); + wait_suspend( &xcontext.c ); + restore_context( &xcontext, sigcontext ); }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=77414
Your paranoid android.
=== w1064v1507 (testbot log) ===
An error occurred while waiting for the test to complete: the 3960 process does not exist or is not a child process
=== w1064v1809 (testbot log) ===
An error occurred while waiting for the test to complete: network read got a premature EOF (wait2/connect:AgentVersion.h:0/9)
=== w1064v1809_2scr (testbot log) ===
An error occurred while waiting for the test to complete: network read got a premature EOF (wait2/connect:AgentVersion.h:0/9)
=== w1064v1809_ar (testbot log) ===
An error occurred while waiting for the test to complete: the 780 process does not exist or is not a child process
=== w1064v1809_he (testbot log) ===
An error occurred while waiting for the test to complete: the 1872 process does not exist or is not a child process
=== w1064v1809_ja (testbot log) ===
An error occurred while waiting for the test to complete: the 2532 process does not exist or is not a child process
=== w1064v1809_zh_CN (testbot log) ===
An error occurred while waiting for the test to complete: the 5136 process does not exist or is not a child process
=== w1064v1507 (testbot log) ===
An error occurred while waiting for the test to complete: the 3940 process does not exist or is not a child process
=== w1064v1809 (testbot log) ===
An error occurred while waiting for the test to complete: network read got a premature EOF (wait2/connect:AgentVersion.h:0/9)
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/ntdll/tests/exception.c | 2 -- dlls/ntdll/unix/signal_i386.c | 38 +++++++++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 4 deletions(-)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 860221366ce..9f93212acf6 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -5600,7 +5600,6 @@ static void test_extended_context(void) for (i = 0; i < 8; ++i) { /* Older Windows version do not reset AVX context to INIT_STATE on x86. */ - todo_wine_if(i >= 4 && sizeof(void *) == 4) ok(!data[i] || broken(i >= 4 && sizeof(void *) == 4 && data[i] == test_extended_context_spoil_data2[i]), "Got unexpected data %#x, i %u.\n", data[i], i); } @@ -5611,7 +5610,6 @@ static void test_extended_context(void) ARRAY_SIZE(except_code_set_ymm0), PAGE_EXECUTE_READ);
for (i = 0; i < 8; ++i) - todo_wine_if(i >= 4 && sizeof(void *) == 4) ok(data[i] == test_extended_context_data[i], "Got unexpected data %#x, i %u.\n", data[i], i); } #endif diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index 791ffe90940..e03cb4a517b 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -687,7 +687,7 @@ static inline void save_fpux( CONTEXT *context ) /*********************************************************************** * restore_fpu * - * Restore the FPU context to a sigcontext. + * Restore the x87 FPU context */ static inline void restore_fpu( const CONTEXT *context ) { @@ -701,7 +701,7 @@ static inline void restore_fpu( const CONTEXT *context ) /*********************************************************************** * restore_fpux * - * Restore the FPU extended context to a sigcontext. + * Restore the FPU extended context */ static inline void restore_fpux( const CONTEXT *context ) { @@ -715,6 +715,38 @@ static inline void restore_fpux( const CONTEXT *context ) __asm__ __volatile__( "fxrstor %0" : : "m" (*state) ); }
+/*********************************************************************** + * restore_xstate + * + * Restore the XState context + */ +static inline void restore_xstate( const CONTEXT *context ) +{ + XSAVE_FORMAT *xrstor_base; + XSTATE *xs; + + if (!(xs = xstate_from_context( context ))) + return; + + xrstor_base = (XSAVE_FORMAT *)xs - 1; + + if (!(xs->CompactionMask & ((ULONG64)1 << 63))) + { + /* Non-compacted xrstor will load Mxcsr regardless of the specified mask. Loading garbage there + * may lead to fault. FPUX state should be restored by now, so we can reuse some space in + * ExtendedRegisters. */ + XSAVE_FORMAT *fpux = (XSAVE_FORMAT *)context->ExtendedRegisters; + DWORD mxcsr, mxcsr_mask; + + mxcsr = fpux->MxCsr; + mxcsr_mask = fpux->MxCsr_Mask; + + assert( (void *)&xrstor_base->MxCsr > (void *)context->ExtendedRegisters ); + xrstor_base->MxCsr = mxcsr; + xrstor_base->MxCsr_Mask = mxcsr_mask; + } + __asm__ volatile("xor %%edx,%%edx; mov $4,%%eax; xrstor %0" : : "m"(*xrstor_base) : "eax", "edx"); +}
/*********************************************************************** * fpux_to_fpu @@ -1129,6 +1161,8 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context ) if (flags & CONTEXT_EXTENDED_REGISTERS) restore_fpux( context ); else if (flags & CONTEXT_FLOATING_POINT) restore_fpu( context );
+ restore_xstate( context ); + if (flags & CONTEXT_FULL) { if (!(flags & CONTEXT_CONTROL))
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=77415
Your paranoid android.
=== w1064v1507 (testbot log) ===
An error occurred while waiting for the test to complete: the 3976 process does not exist or is not a child process
=== w1064v1809 (testbot log) ===
An error occurred while waiting for the test to complete: the 5356 process does not exist or is not a child process
=== w1064v1809_2scr (testbot log) ===
An error occurred while waiting for the test to complete: network read got a premature EOF (wait2/connect:AgentVersion.h:0/9)
=== w1064v1809_ar (testbot log) ===
An error occurred while waiting for the test to complete: the 1448 process does not exist or is not a child process
=== w1064v1809_he (testbot log) ===
An error occurred while waiting for the test to complete: the 1560 process does not exist or is not a child process
=== w1064v1809_ja (testbot log) ===
An error occurred while waiting for the test to complete: the 1508 process does not exist or is not a child process
=== w1064v1809_zh_CN (testbot log) ===
An error occurred while waiting for the test to complete: the 5404 process does not exist or is not a child process
=== w1064v1507 (testbot log) ===
An error occurred while waiting for the test to complete: the 3952 process does not exist or is not a child process
=== w1064v1809 (testbot log) ===
An error occurred while waiting for the test to complete: network read got a premature EOF (wait2/connect:AgentVersion.h:0/9)
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=77411
Your paranoid android.
=== w1064v1507 (testbot log) ===
An error occurred while waiting for the test to complete: the 3952 process does not exist or is not a child process
=== w1064v1809 (testbot log) ===
An error occurred while waiting for the test to complete: network read got a premature EOF (wait2/connect:AgentVersion.h:0/9)
=== w1064v1809_2scr (testbot log) ===
An error occurred while waiting for the test to complete: network read got a premature EOF (wait2/connect:AgentVersion.h:0/9)
=== w1064v1809_ar (testbot log) ===
An error occurred while waiting for the test to complete: network read timed out (wait2/connect:AgentVersion.h:0/9)
=== w1064v1809_he (testbot log) ===
An error occurred while waiting for the test to complete: the 5540 process does not exist or is not a child process
=== w1064v1809_ja (testbot log) ===
An error occurred while waiting for the test to complete: the 4144 process does not exist or is not a child process
=== w1064v1809_zh_CN (testbot log) ===
An error occurred while waiting for the test to complete: the 2792 process does not exist or is not a child process
=== w1064v1507 (testbot log) ===
An error occurred while waiting for the test to complete: the 3948 process does not exist or is not a child process
=== w1064v1809 (testbot log) ===
An error occurred while waiting for the test to complete: network read got a premature EOF (wait2/connect:AgentVersion.h:0/9)