From 419abd49a1f816e5a869dbf4cc81114cd516138b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 9 Oct 2020 16:03:54 +0300 Subject: [PATCH] ntdll: Support AVX registers for other thread in Nt{Get|Set}ContextThread(). Signed-off-by: Paul Gofman Signed-off-by: Alexandre Julliard --- 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 00b07c4270c..124032714c7 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 76523b9e11c..5e8d2c6c0a3 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 0026e8d8661..0226d8a70f7 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 1f1c681f180..86b78a3a66d 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)