ntdll: Fix stack layout for KiUserExceptionDispatcher on i386.

This commit is contained in:
Alexandre Julliard 2023-11-30 17:39:08 +01:00
parent b5cd47f541
commit 58a00854c3
4 changed files with 91 additions and 57 deletions

View file

@ -1908,15 +1908,22 @@ static LONG WINAPI dbg_except_continue_vectored_handler(struct _EXCEPTION_POINTE
/* Use CDECL to leave arguments on stack. */
static void * CDECL hook_KiUserExceptionDispatcher(EXCEPTION_RECORD *rec, CONTEXT *context)
{
trace("rec %p, context %p.\n", rec, context);
trace("context->Eip %#lx, context->Esp %#lx, ContextFlags %#lx.\n",
context->Eip, context->Esp, context->ContextFlags);
CONTEXT_EX *xctx = (CONTEXT_EX *)(context + 1);
trace( "rec %p context %p context->Eip %#lx, context->Esp %#lx (%x), ContextFlags %#lx.\n",
rec, context, context->Eip, context->Esp,
(char *)context->Esp - (char *)&rec, context->ContextFlags);
trace( "xstate %lx = %p (%x) %lx\n", xctx->XState.Offset, (char *)xctx + xctx->XState.Offset,
(char *)xctx + xctx->XState.Offset - (char *)&rec, xctx->XState.Length );
ok( (char *)rec->ExceptionInformation <= (char *)context &&
(char *)(rec + 1) >= (char *)context, "wrong ptrs %p / %p\n", rec, context );
ok( xctx->All.Offset == -sizeof(CONTEXT), "wrong All.Offset %lx\n", xctx->All.Offset );
ok( xctx->All.Length >= sizeof(CONTEXT) + sizeof(CONTEXT_EX), "wrong All.Length %lx\n", xctx->All.Length );
ok( xctx->Legacy.Offset == -sizeof(CONTEXT), "wrong Legacy.Offset %lx\n", xctx->All.Offset );
ok( xctx->Legacy.Length == sizeof(CONTEXT), "wrong Legacy.Length %lx\n", xctx->All.Length );
hook_called = TRUE;
/* Broken on Win2008, probably rec offset in stack is different. */
ok(rec->ExceptionCode == 0x80000003 || broken(!rec->ExceptionCode),
"Got unexpected ExceptionCode %#lx.\n", rec->ExceptionCode);
hook_KiUserExceptionDispatcher_eip = (void *)context->Eip;
hook_exception_address = rec->ExceptionAddress;
memcpy(pKiUserExceptionDispatcher, saved_KiUserExceptionDispatcher_bytes,

View file

@ -435,6 +435,21 @@ enum i386_trap_code
#endif
};
/* stack layout when calling KiUserExceptionDispatcher */
struct exc_stack_layout
{
EXCEPTION_RECORD *rec_ptr; /* 000 first arg for KiUserExceptionDispatcher */
CONTEXT *context_ptr; /* 004 second arg for KiUserExceptionDispatcher */
EXCEPTION_RECORD rec; /* 008 */
CONTEXT context; /* 058 */
CONTEXT_EX context_ex; /* 324 */
BYTE xstate[sizeof(XSTATE)+64]; /* 33c extra space to allow for 64-byte alignment */
DWORD align; /* 4bc */
};
C_ASSERT( offsetof(struct exc_stack_layout, context) == 0x58 );
C_ASSERT( offsetof(struct exc_stack_layout, xstate) == 0x33c );
C_ASSERT( sizeof(struct exc_stack_layout) == 0x4c0 );
struct syscall_frame
{
WORD syscall_flags; /* 000 */
@ -1417,23 +1432,8 @@ static void setup_raise_exception( ucontext_t *sigcontext, void *stack_ptr,
EXCEPTION_RECORD *rec, struct xcontext *xcontext )
{
CONTEXT *context = &xcontext->c;
size_t stack_size;
XSTATE *src_xs;
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)) );
struct exc_stack_layout *stack;
NTSTATUS status = send_debug_event( rec, context, TRUE );
if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
@ -1445,23 +1445,17 @@ C_ASSERT( (offsetof(struct stack_layout, xstate) == sizeof(struct stack_layout))
/* fix up instruction pointer in context for EXCEPTION_BREAKPOINT */
if (rec->ExceptionCode == EXCEPTION_BREAKPOINT) context->Eip--;
stack_size = sizeof(*stack);
if ((src_xs = xstate_from_context( context )))
{
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 = virtual_setup_exception( stack_ptr, sizeof(*stack), rec );
stack->rec_ptr = &stack->rec;
stack->context_ptr = &stack->context;
stack->rec = *rec;
stack->context = *context;
if (src_xs)
if ((src_xs = xstate_from_context( context )))
{
XSTATE *dst_xs = (XSTATE *)stack->xstate;
XSTATE *dst_xs = (XSTATE *)(((ULONG_PTR)stack->xstate + 63) & ~63);
assert(!((ULONG_PTR)dst_xs & 63));
context_init_xstate( &stack->context, stack->xstate );
context_init_xstate( &stack->context, dst_xs );
memset( dst_xs, 0, offsetof(XSTATE, YmmContext) );
dst_xs->CompactionMask = xstate_compaction_enabled ? 0x8000000000000004 : 0;
if (src_xs->Mask & 4)
@ -1475,8 +1469,6 @@ C_ASSERT( (offsetof(struct stack_layout, xstate) == sizeof(struct stack_layout))
context_init_xstate( &stack->context, NULL );
}
stack->rec_ptr = &stack->rec;
stack->context_ptr = &stack->context;
ESP_sig(sigcontext) = (DWORD)stack;
EIP_sig(sigcontext) = (DWORD)pKiUserExceptionDispatcher;
/* clear single-step, direction, and align check flag */
@ -1560,11 +1552,35 @@ void call_raise_user_exception_dispatcher(void)
NTSTATUS call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context )
{
struct syscall_frame *frame = x86_thread_data()->syscall_frame;
void **stack = (void **)frame->esp;
ULONG esp = (frame->esp - sizeof(struct exc_stack_layout)) & ~3;
struct exc_stack_layout *stack = (struct exc_stack_layout *)esp;
XSTATE *src_xs;
if (rec->ExceptionCode == EXCEPTION_BREAKPOINT) context->Eip--;
*(--stack) = context;
*(--stack) = rec;
stack->rec_ptr = &stack->rec;
stack->context_ptr = &stack->context;
stack->rec = *rec;
stack->context = *context;
if ((src_xs = xstate_from_context( context )))
{
XSTATE *dst_xs = (XSTATE *)(((ULONG_PTR)stack->xstate + 63) & ~63);
context_init_xstate( &stack->context, dst_xs );
memset( dst_xs, 0, offsetof(XSTATE, YmmContext) );
dst_xs->CompactionMask = xstate_compaction_enabled ? 0x8000000000000004 : 0;
if (src_xs->Mask & 4)
{
dst_xs->Mask = 4;
memcpy( &dst_xs->YmmContext, &src_xs->YmmContext, sizeof(dst_xs->YmmContext) );
}
}
else
{
context_init_xstate( &stack->context, NULL );
}
frame->esp = (ULONG)stack;
frame->eip = (ULONG)pKiUserExceptionDispatcher;
return STATUS_SUCCESS;

View file

@ -73,6 +73,13 @@ typedef struct
ULONG DefaultNonPagedPoolCharge;
} OBJECT_TYPE_INFORMATION32;
typedef struct
{
CONTEXT_CHUNK All;
CONTEXT_CHUNK Legacy;
CONTEXT_CHUNK XState;
} CONTEXT_EX32;
typedef struct
{
UNICODE_STRING32 ObjectName;

View file

@ -190,16 +190,24 @@ static void call_user_exception_dispatcher( EXCEPTION_RECORD32 *rec, void *ctx32
{
case IMAGE_FILE_MACHINE_I386:
{
struct stack_layout
/* stack layout when calling 32-bit KiUserExceptionDispatcher */
struct exc_stack_layout32
{
ULONG rec_ptr; /* first arg for KiUserExceptionDispatcher */
ULONG context_ptr; /* second arg for KiUserExceptionDispatcher */
EXCEPTION_RECORD32 rec;
I386_CONTEXT context;
ULONG rec_ptr; /* 000 */
ULONG context_ptr; /* 004 */
EXCEPTION_RECORD32 rec; /* 008 */
I386_CONTEXT context; /* 058 */
CONTEXT_EX32 context_ex; /* 324 */
BYTE xstate[sizeof(XSTATE)+64]; /* 33c */
DWORD align; /* 4bc */
} *stack;
I386_CONTEXT *context, ctx = { CONTEXT_I386_ALL };
I386_CONTEXT ctx = { CONTEXT_I386_ALL };
CONTEXT_EX *context_ex, *src_ex = NULL;
ULONG size, flags;
ULONG flags;
C_ASSERT( offsetof(struct exc_stack_layout32, context) == 0x58 );
C_ASSERT( offsetof(struct exc_stack_layout32, xstate) == 0x33c );
C_ASSERT( sizeof(struct exc_stack_layout32) == 0x4c0 );
pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
@ -222,20 +230,16 @@ static void call_user_exception_dispatcher( EXCEPTION_RECORD32 *rec, void *ctx32
flags = ctx.ContextFlags;
if (src_ex) flags |= CONTEXT_I386_XSTATE;
RtlGetExtendedContextLength( flags, &size );
size = ((size + 15) & ~15) + offsetof(struct stack_layout,context);
stack = (struct stack_layout *)(ULONG_PTR)(ctx.Esp - size);
stack->rec_ptr = PtrToUlong( &stack->rec );
stack->rec = *rec;
stack = (struct exc_stack_layout32 *)ULongToPtr( ctx.Esp & ~3 ) - 1;
stack->rec_ptr = PtrToUlong( &stack->rec );
stack->context_ptr = PtrToUlong( &stack->context );
stack->rec = *rec;
stack->context = ctx;
RtlInitializeExtendedContext( &stack->context, flags, &context_ex );
context = RtlLocateLegacyContext( context_ex, NULL );
*context = ctx;
context->ContextFlags = flags;
/* adjust Eip for breakpoints in software emulation (hardware exceptions already adjust Rip) */
if (rec->ExceptionCode == EXCEPTION_BREAKPOINT && (wow64info->CpuFlags & WOW64_CPUFLAGS_SOFTWARE))
context->Eip--;
stack->context_ptr = PtrToUlong( context );
stack->context.Eip--;
if (src_ex)
{