mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-14 18:37:17 +00:00
ntdll: Fix stack layout for KiUserExceptionDispatcher on i386.
This commit is contained in:
parent
b5cd47f541
commit
58a00854c3
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue