Commit 061c612b authored by Alexandre Julliard's avatar Alexandre Julliard

ntdll: Add a machine frame to the KiUserExceptionDispatcher stack on x86-64.

parent 8164c708
...@@ -612,6 +612,29 @@ NTSTATUS WINAPI dispatch_exception( EXCEPTION_RECORD *rec, CONTEXT *context ) ...@@ -612,6 +612,29 @@ NTSTATUS WINAPI dispatch_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
* KiUserExceptionDispatcher (NTDLL.@) * KiUserExceptionDispatcher (NTDLL.@)
*/ */
__ASM_GLOBAL_FUNC( KiUserExceptionDispatcher, __ASM_GLOBAL_FUNC( KiUserExceptionDispatcher,
__ASM_SEH(".seh_pushframe\n\t")
__ASM_SEH(".seh_stackalloc 0x590\n\t")
__ASM_SEH(".seh_savereg %rbx,0x90\n\t")
__ASM_SEH(".seh_savereg %rbp,0xa0\n\t")
__ASM_SEH(".seh_savereg %rsi,0xa8\n\t")
__ASM_SEH(".seh_savereg %rdi,0xb0\n\t")
__ASM_SEH(".seh_savereg %r12,0xd8\n\t")
__ASM_SEH(".seh_savereg %r13,0xe0\n\t")
__ASM_SEH(".seh_savereg %r14,0xe8\n\t")
__ASM_SEH(".seh_savereg %r15,0xf0\n\t")
__ASM_SEH(".seh_endprologue\n\t")
__ASM_CFI(".cfi_signal_frame\n\t")
__ASM_CFI(".cfi_def_cfa_offset 0\n\t")
__ASM_CFI(".cfi_offset %rbx,0x90\n\t")
__ASM_CFI(".cfi_offset %rbp,0xa0\n\t")
__ASM_CFI(".cfi_offset %rsi,0xa8\n\t")
__ASM_CFI(".cfi_offset %rdi,0xb0\n\t")
__ASM_CFI(".cfi_offset %r12,0xd8\n\t")
__ASM_CFI(".cfi_offset %r13,0xe0\n\t")
__ASM_CFI(".cfi_offset %r14,0xe8\n\t")
__ASM_CFI(".cfi_offset %r15,0xf0\n\t")
__ASM_CFI(".cfi_offset %rip,0x590\n\t")
__ASM_CFI(".cfi_offset %rsp,0x5a8\n\t")
"cld\n\t" "cld\n\t"
/* some anticheats need this exact instruction here */ /* some anticheats need this exact instruction here */
"mov " __ASM_NAME("pWow64PrepareForException") "(%rip),%rax\n\t" "mov " __ASM_NAME("pWow64PrepareForException") "(%rip),%rax\n\t"
...@@ -620,30 +643,10 @@ __ASM_GLOBAL_FUNC( KiUserExceptionDispatcher, ...@@ -620,30 +643,10 @@ __ASM_GLOBAL_FUNC( KiUserExceptionDispatcher,
"mov %rsp,%rdx\n\t" /* context */ "mov %rsp,%rdx\n\t" /* context */
"lea 0x4f0(%rsp),%rcx\n\t" /* rec */ "lea 0x4f0(%rsp),%rcx\n\t" /* rec */
"call *%rax\n" "call *%rax\n"
"1:\tmov 0xf8(%rsp),%rdx\n\t" /* context->Rip */ "1:\tmov %rsp,%rdx\n\t" /* context */
"mov 0x98(%rsp),%rcx\n\t" /* context->Rsp */ "lea 0x4f0(%rsp),%rcx\n\t" /* rec */
"mov %rdx,-0x8(%rcx)\n\t"
"mov %rbp,-0x10(%rcx)\n\t"
"mov %rdi,-0x18(%rcx)\n\t"
"mov %rsi,-0x20(%rcx)\n\t"
"lea -0x20(%rcx),%rbp\n\t"
"mov %rsp,%rdx\n\t" /* context */
"lea 0x4f0(%rsp),%rcx\n\t" /* rec */
__ASM_SEH(".seh_pushreg %rbp\n\t")
__ASM_SEH(".seh_pushreg %rdi\n\t")
__ASM_SEH(".seh_pushreg %rsi\n\t")
__ASM_SEH(".seh_setframe %rbp,0\n\t")
__ASM_SEH(".seh_endprologue\n\t")
__ASM_CFI(".cfi_signal_frame\n\t")
__ASM_CFI(".cfi_adjust_cfa_offset 0x20\n\t")
__ASM_CFI(".cfi_def_cfa %rbp,0x20\n\t")
__ASM_CFI(".cfi_rel_offset %rip,0x18\n\t")
__ASM_CFI(".cfi_rel_offset %rbp,0x10\n\t")
__ASM_CFI(".cfi_rel_offset %rdi,0x8\n\t")
__ASM_CFI(".cfi_rel_offset %rsi,0\n\t")
"call " __ASM_NAME("dispatch_exception") "\n\t" "call " __ASM_NAME("dispatch_exception") "\n\t"
"int3") "int3" )
/******************************************************************* /*******************************************************************
......
...@@ -4644,6 +4644,15 @@ test_kiuserexceptiondispatcher_regs; ...@@ -4644,6 +4644,15 @@ test_kiuserexceptiondispatcher_regs;
static ULONG64 test_kiuserexceptiondispatcher_saved_r12; static ULONG64 test_kiuserexceptiondispatcher_saved_r12;
struct machine_frame
{
ULONG64 rip;
ULONG64 cs;
ULONG64 eflags;
ULONG64 rsp;
ULONG64 ss;
};
static DWORD dbg_except_continue_handler(EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, static DWORD dbg_except_continue_handler(EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher) CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher)
{ {
...@@ -4689,15 +4698,29 @@ static LONG WINAPI dbg_except_continue_vectored_handler(struct _EXCEPTION_POINTE ...@@ -4689,15 +4698,29 @@ static LONG WINAPI dbg_except_continue_vectored_handler(struct _EXCEPTION_POINTE
static void * WINAPI hook_KiUserExceptionDispatcher(EXCEPTION_RECORD *rec, CONTEXT *context) static void * WINAPI hook_KiUserExceptionDispatcher(EXCEPTION_RECORD *rec, CONTEXT *context)
{ {
struct machine_frame *frame = (struct machine_frame *)(((ULONG_PTR)(rec + 1) + 0x0f) & ~0x0f);
CONTEXT_EX *xctx = (CONTEXT_EX *)(context + 1);
trace("rec %p, context %p.\n", rec, context); trace("rec %p, context %p.\n", rec, context);
trace("context->Rip %#Ix, context->Rsp %#Ix, ContextFlags %#lx.\n", trace("context->Rip %#Ix, context->Rsp %#Ix, ContextFlags %#lx.\n",
context->Rip, context->Rsp, context->ContextFlags); context->Rip, context->Rsp, context->ContextFlags);
trace("machine frame %p: rip=%Ix cs=%Ix eflags=%Ix rsp=%Ix ss=%Ix\n",
frame, frame->rip, frame->cs, frame->eflags, frame->rsp, frame->ss);
hook_called = TRUE; hook_called = TRUE;
/* Broken on Win2008, probably rec offset in stack is different. */ /* Broken on Win2008, probably rec offset in stack is different. */
ok(rec->ExceptionCode == 0x80000003 || rec->ExceptionCode == 0xceadbeef || broken(!rec->ExceptionCode), ok(rec->ExceptionCode == 0x80000003 || rec->ExceptionCode == 0xceadbeef || broken(!rec->ExceptionCode),
"Got unexpected ExceptionCode %#lx.\n", rec->ExceptionCode); "Got unexpected ExceptionCode %#lx.\n", rec->ExceptionCode);
ok( !((ULONG_PTR)context & 15), "unaligned context %p\n", context );
ok( xctx->All.Offset == -sizeof(CONTEXT), "wrong All.Offset %lx\n", xctx->All.Offset );
ok( xctx->All.Length >= sizeof(CONTEXT) + offsetof(CONTEXT_EX, align), "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 );
ok( (void *)(xctx + 1) == (void *)rec, "wrong ptrs %p / %p\n", xctx, rec );
ok( frame->rip == context->Rip, "wrong rip %Ix / %Ix\n", frame->rip, context->Rip );
ok( frame->rsp == context->Rsp, "wrong rsp %Ix / %Ix\n", frame->rsp, context->Rsp );
hook_KiUserExceptionDispatcher_rip = (void *)context->Rip; hook_KiUserExceptionDispatcher_rip = (void *)context->Rip;
hook_exception_address = rec->ExceptionAddress; hook_exception_address = rec->ExceptionAddress;
memcpy(pKiUserExceptionDispatcher, saved_KiUserExceptionDispatcher_bytes, memcpy(pKiUserExceptionDispatcher, saved_KiUserExceptionDispatcher_bytes,
......
...@@ -341,21 +341,29 @@ enum i386_trap_code ...@@ -341,21 +341,29 @@ enum i386_trap_code
#endif #endif
}; };
/* stack layout when calling an exception raise function */ struct machine_frame
struct stack_layout
{ {
CONTEXT context; ULONG64 rip;
CONTEXT_EX context_ex; ULONG64 cs;
EXCEPTION_RECORD rec; ULONG64 eflags;
ULONG64 align; ULONG64 rsp;
char xstate[0]; /* If xstate is present it is allocated ULONG64 ss;
* dynamically to provide 64 byte alignment. */
}; };
C_ASSERT((offsetof(struct stack_layout, xstate) == sizeof(struct stack_layout))); /* stack layout when calling KiUserExceptionDispatcher */
struct exc_stack_layout
C_ASSERT( sizeof(XSTATE) == 0x140 ); {
C_ASSERT( sizeof(struct stack_layout) == 0x590 ); /* Should match the size in call_user_exception_dispatcher(). */ CONTEXT context; /* 000 */
CONTEXT_EX context_ex; /* 4d0 */
EXCEPTION_RECORD rec; /* 4f0 */
ULONG64 align; /* 588 */
struct machine_frame machine_frame; /* 590 */
ULONG64 align2; /* 5b8 */
XSTATE xstate; /* 5c0 */
};
C_ASSERT( offsetof(struct exc_stack_layout, rec) == 0x4f0 );
C_ASSERT( offsetof(struct exc_stack_layout, machine_frame) == 0x590 );
C_ASSERT( sizeof(struct exc_stack_layout) == 0x700 );
/* flags to control the behavior of the syscall dispatcher */ /* flags to control the behavior of the syscall dispatcher */
#define SYSCALL_HAVE_XSAVE 1 #define SYSCALL_HAVE_XSAVE 1
...@@ -1379,7 +1387,7 @@ static void setup_raise_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec ...@@ -1379,7 +1387,7 @@ static void setup_raise_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec
{ {
void *stack_ptr = (void *)(RSP_sig(sigcontext) & ~15); void *stack_ptr = (void *)(RSP_sig(sigcontext) & ~15);
CONTEXT *context = &xcontext->c; CONTEXT *context = &xcontext->c;
struct stack_layout *stack; struct exc_stack_layout *stack;
size_t stack_size; size_t stack_size;
NTSTATUS status; NTSTATUS status;
XSTATE *src_xs; XSTATE *src_xs;
...@@ -1411,28 +1419,23 @@ static void setup_raise_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec ...@@ -1411,28 +1419,23 @@ static void setup_raise_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec
/* fix up instruction pointer in context for EXCEPTION_BREAKPOINT */ /* fix up instruction pointer in context for EXCEPTION_BREAKPOINT */
if (rec->ExceptionCode == EXCEPTION_BREAKPOINT) context->Rip--; if (rec->ExceptionCode == EXCEPTION_BREAKPOINT) context->Rip--;
stack_size = sizeof(*stack) + 0x20; stack_size = (ULONG_PTR)stack_ptr - (((ULONG_PTR)stack_ptr - sizeof(*stack)) & ~(ULONG_PTR)63);
if ((src_xs = xstate_from_context( context )))
{
stack_size += (ULONG_PTR)stack_ptr - 0x20 - (((ULONG_PTR)stack_ptr - 0x20
- sizeof(XSTATE)) & ~(ULONG_PTR)63);
}
stack = virtual_setup_exception( stack_ptr, stack_size, rec ); stack = virtual_setup_exception( stack_ptr, stack_size, rec );
stack->rec = *rec; stack->rec = *rec;
stack->context = *context; stack->context = *context;
if (src_xs) stack->machine_frame.rip = context->Rip;
{ stack->machine_frame.rsp = context->Rsp;
XSTATE *dst_xs = (XSTATE *)stack->xstate;
assert( !((ULONG_PTR)dst_xs & 63) ); if ((src_xs = xstate_from_context( context )))
context_init_xstate( &stack->context, stack->xstate ); {
memset( dst_xs, 0, offsetof(XSTATE, YmmContext) ); assert( !((ULONG_PTR)&stack->xstate & 63) );
dst_xs->CompactionMask = xstate_compaction_enabled ? 0x8000000000000004 : 0; context_init_xstate( &stack->context, &stack->xstate );
memset( &stack->xstate, 0, offsetof(XSTATE, YmmContext) );
stack->xstate.CompactionMask = xstate_compaction_enabled ? 0x8000000000000004 : 0;
if (src_xs->Mask & 4) if (src_xs->Mask & 4)
{ {
dst_xs->Mask = 4; stack->xstate.Mask = 4;
memcpy( &dst_xs->YmmContext, &src_xs->YmmContext, sizeof(dst_xs->YmmContext) ); memcpy( &stack->xstate.YmmContext, &src_xs->YmmContext, sizeof(stack->xstate.YmmContext) );
} }
} }
else else
...@@ -1517,27 +1520,26 @@ void call_raise_user_exception_dispatcher(void) ...@@ -1517,27 +1520,26 @@ void call_raise_user_exception_dispatcher(void)
NTSTATUS call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context ) NTSTATUS call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context )
{ {
struct syscall_frame *frame = amd64_thread_data()->syscall_frame; struct syscall_frame *frame = amd64_thread_data()->syscall_frame;
struct stack_layout *stack; struct exc_stack_layout *stack;
ULONG64 rsp;
NTSTATUS status = NtSetContextThread( GetCurrentThread(), context ); NTSTATUS status = NtSetContextThread( GetCurrentThread(), context );
if (status) return status; if (status) return status;
rsp = (context->Rsp - 0x20) & ~15; stack = (struct exc_stack_layout *)((context->Rsp - sizeof(*stack)) & ~(ULONG_PTR)63);
stack = (struct stack_layout *)rsp - 1; memmove( &stack->context, context, sizeof(*context) );
if ((context->ContextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE) if ((context->ContextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE)
{ {
rsp = (rsp - sizeof(XSTATE)) & ~63; assert( !((ULONG_PTR)&stack->xstate & 63) );
stack = (struct stack_layout *)rsp - 1; context_init_xstate( &stack->context, &stack->xstate );
assert( !((ULONG_PTR)stack->xstate & 63) ); memcpy( &stack->xstate, &frame->xstate, sizeof(frame->xstate) );
memmove( &stack->context, context, sizeof(*context) );
context_init_xstate( &stack->context, stack->xstate );
memcpy( stack->xstate, &frame->xstate, sizeof(frame->xstate) );
} }
else memmove( &stack->context, context, sizeof(*context) ); else context_init_xstate( &stack->context, NULL );
stack->rec = *rec; stack->rec = *rec;
/* fix up instruction pointer in context for EXCEPTION_BREAKPOINT */ /* fix up instruction pointer in context for EXCEPTION_BREAKPOINT */
if (stack->rec.ExceptionCode == EXCEPTION_BREAKPOINT) stack->context.Rip--; if (stack->rec.ExceptionCode == EXCEPTION_BREAKPOINT) stack->context.Rip--;
stack->machine_frame.rip = stack->context.Rip;
stack->machine_frame.rsp = stack->context.Rsp;
frame->rbp = stack->context.Rbp; frame->rbp = stack->context.Rbp;
frame->rsp = (ULONG64)stack; frame->rsp = (ULONG64)stack;
frame->rip = (ULONG64)pKiUserExceptionDispatcher; frame->rip = (ULONG64)pKiUserExceptionDispatcher;
......
...@@ -386,6 +386,14 @@ NTSTATUS WINAPI BTCpuResetToConsistentState( EXCEPTION_POINTERS *ptrs ) ...@@ -386,6 +386,14 @@ NTSTATUS WINAPI BTCpuResetToConsistentState( EXCEPTION_POINTERS *ptrs )
{ {
CONTEXT *context = ptrs->ContextRecord; CONTEXT *context = ptrs->ContextRecord;
I386_CONTEXT wow_context; I386_CONTEXT wow_context;
struct machine_frame
{
ULONG64 rip;
ULONG64 cs;
ULONG64 eflags;
ULONG64 rsp;
ULONG64 ss;
} *machine_frame;
if (context->SegCs == cs64_sel) return STATUS_SUCCESS; /* exception in 64-bit code, nothing to do */ if (context->SegCs == cs64_sel) return STATUS_SUCCESS; /* exception in 64-bit code, nothing to do */
...@@ -397,6 +405,10 @@ NTSTATUS WINAPI BTCpuResetToConsistentState( EXCEPTION_POINTERS *ptrs ) ...@@ -397,6 +405,10 @@ NTSTATUS WINAPI BTCpuResetToConsistentState( EXCEPTION_POINTERS *ptrs )
context->Rip = (ULONG64)syscall_32to64; context->Rip = (ULONG64)syscall_32to64;
context->SegCs = cs64_sel; context->SegCs = cs64_sel;
context->Rsp = context->R14; context->Rsp = context->R14;
/* fixup machine frame */
machine_frame = (struct machine_frame *)(((ULONG_PTR)(ptrs->ExceptionRecord + 1) + 15) & ~15);
machine_frame->rip = context->Rip;
machine_frame->rsp = context->Rsp;
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment