This bug was causing incorrect FPU state to be read under Wow64 on macOS.
This use of different mcontext structures is only documented in Apple's kernel source, most helpfully a test program for custom LDTs: https://github.com/apple-oss-distributions/xnu/blob/e7776783b89a353188416a9a...
From: Brendan Shanks bshanks@codeweavers.com
--- dlls/ntdll/unix/signal_x86_64.c | 54 ++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index d6f19dbfa84..8d85525b224 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -210,6 +210,42 @@ __ASM_GLOBAL_FUNC( alloc_fs_sel,
#include <i386/user_ldt.h>
+/* The 'full' structs were added in the macOS 10.14.6 SDK/Xcode 10.3. */ +#ifndef _STRUCT_X86_THREAD_FULL_STATE64 +#define _STRUCT_X86_THREAD_FULL_STATE64 struct __darwin_x86_thread_full_state64 +_STRUCT_X86_THREAD_FULL_STATE64 +{ + _STRUCT_X86_THREAD_STATE64 __ss64; + __uint64_t __ds; + __uint64_t __es; + __uint64_t __ss; + __uint64_t __gsbase; +}; + +#define _STRUCT_MCONTEXT64_FULL struct __darwin_mcontext64_full +_STRUCT_MCONTEXT64_FULL +{ + _STRUCT_X86_EXCEPTION_STATE64 __es; + _STRUCT_X86_THREAD_FULL_STATE64 __ss; + _STRUCT_X86_FLOAT_STATE64 __fs; +}; + +#define _STRUCT_MCONTEXT_AVX64_FULL struct __darwin_mcontext_avx64_full +_STRUCT_MCONTEXT_AVX64_FULL +{ + _STRUCT_X86_EXCEPTION_STATE64 __es; + _STRUCT_X86_THREAD_FULL_STATE64 __ss; + _STRUCT_X86_AVX_STATE64 __fs; +}; +#endif + +/* AVX512 structs were added in the macOS 10.13 SDK/Xcode 9. */ +#ifdef _STRUCT_MCONTEXT_AVX512_64_FULL +#define SIZEOF_STRUCT_MCONTEXT_AVX512_64_FULL sizeof(_STRUCT_MCONTEXT_AVX512_64_FULL) +#else +#define SIZEOF_STRUCT_MCONTEXT_AVX512_64_FULL 2664 +#endif + #define RAX_sig(context) ((context)->uc_mcontext->__ss.__rax) #define RBX_sig(context) ((context)->uc_mcontext->__ss.__rbx) #define RCX_sig(context) ((context)->uc_mcontext->__ss.__rcx) @@ -233,7 +269,23 @@ __ASM_GLOBAL_FUNC( alloc_fs_sel, #define RSP_sig(context) ((context)->uc_mcontext->__ss.__rsp) #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) + +/* Once a custom LDT is installed (i.e. Wow64), mcontext will point to a + * larger '_full' struct which includes DS, ES, SS, and GSbase. + * This changes the offset of the FPU state. + * Checking mcsize is the only way to determine which mcontext is in use. + */ +static inline XMM_SAVE_AREA32 *FPU_sig( const ucontext_t *context ) +{ + if (context->uc_mcsize == sizeof(_STRUCT_MCONTEXT64_FULL) || + context->uc_mcsize == sizeof(_STRUCT_MCONTEXT_AVX64_FULL) || + context->uc_mcsize == SIZEOF_STRUCT_MCONTEXT_AVX512_64_FULL) + { + return (XMM_SAVE_AREA32 *)&((_STRUCT_MCONTEXT64_FULL *)context->uc_mcontext)->__fs.__fpu_fcw; + } + return (XMM_SAVE_AREA32 *)&(context)->uc_mcontext->__fs.__fpu_fcw; +} + #define XState_sig(context) NULL
#else