Commit 89f3c597 authored by Alexandre Julliard's avatar Alexandre Julliard

ntdll: Fix stack layout for KiUserExceptionDispatcher on ARM.

parent 42046a24
......@@ -463,7 +463,7 @@ static NTSTATUS call_function_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_con
/*******************************************************************
* KiUserExceptionDispatcher (NTDLL.@)
*/
NTSTATUS WINAPI KiUserExceptionDispatcher( EXCEPTION_RECORD *rec, CONTEXT *context )
NTSTATUS WINAPI dispatch_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
{
NTSTATUS status;
DWORD c;
......@@ -526,6 +526,22 @@ NTSTATUS WINAPI KiUserExceptionDispatcher( EXCEPTION_RECORD *rec, CONTEXT *conte
if (status != STATUS_UNHANDLED_EXCEPTION) RtlRaiseStatus( status );
return NtRaiseException( rec, context, FALSE );
}
__ASM_GLOBAL_FUNC( KiUserExceptionDispatcher,
__ASM_SEH(".seh_custom 0xee,0x02\n\t") /* MSFT_OP_CONTEXT */
__ASM_SEH(".seh_endprologue\n\t")
__ASM_EHABI(".save {sp}\n\t") /* Restore Sp last */
__ASM_EHABI(".pad #-(0x80 + 0x0c + 0x0c)\n\t") /* Move back across D0-D15, Cpsr, Fpscr, Padding, Pc, Lr and Sp */
__ASM_EHABI(".vsave {d8-d15}\n\t")
__ASM_EHABI(".pad #0x40\n\t") /* Skip past D0-D7 */
__ASM_EHABI(".pad #0x0c\n\t") /* Skip past Cpsr, Fpscr and Padding */
__ASM_EHABI(".save {lr, pc}\n\t")
__ASM_EHABI(".pad #0x08\n\t") /* Skip past R12 and Sp - Sp is restored last */
__ASM_EHABI(".save {r4-r11}\n\t")
__ASM_EHABI(".pad #0x14\n\t") /* Skip past ContextFlags and R0-R3 */
"add r0, sp, #0x1a0\n\t" /* rec (context + 1) */
"mov r1, sp\n\t" /* context */
"bl " __ASM_NAME("dispatch_exception") "\n\t"
"udf #1" )
/*******************************************************************
......
......@@ -7343,6 +7343,108 @@ static void test_debug_service(DWORD numexc)
/* not supported */
}
static BOOL hook_called;
static BOOL got_exception;
static void *code_ptr;
static WORD patched_code[] =
{
0x4668, /* mov r0, sp */
0xf8df, 0xc004, /* ldr.w ip, [pc, #0x4] */
0x4760, /* bx ip */
0, 0, /* 1: hook_trampoline */
};
static WORD saved_code[ARRAY_SIZE(patched_code)];
static LONG WINAPI dbg_except_continue_vectored_handler(struct _EXCEPTION_POINTERS *ptrs)
{
EXCEPTION_RECORD *rec = ptrs->ExceptionRecord;
CONTEXT *context = ptrs->ContextRecord;
trace("dbg_except_continue_vectored_handler, code %#lx, pc %#lx.\n", rec->ExceptionCode, context->Pc);
got_exception = TRUE;
ok(rec->ExceptionCode == 0x80000003, "Got unexpected exception code %#lx.\n", rec->ExceptionCode);
return EXCEPTION_CONTINUE_EXECUTION;
}
static void * WINAPI hook_KiUserExceptionDispatcher(void *stack)
{
CONTEXT *context = stack;
EXCEPTION_RECORD *rec = (EXCEPTION_RECORD *)(context + 1);
trace( "rec %p context %p pc %#lx sp %#lx flags %#lx\n",
rec, context, context->Pc, context->Sp, context->ContextFlags );
ok( !((ULONG_PTR)stack & 7), "unaligned stack %p\n", stack );
ok( rec->ExceptionCode == 0x80000003, "Got unexpected ExceptionCode %#lx.\n", rec->ExceptionCode );
hook_called = TRUE;
memcpy(code_ptr, saved_code, sizeof(saved_code));
FlushInstructionCache( GetCurrentProcess(), code_ptr, sizeof(saved_code));
return pKiUserExceptionDispatcher;
}
static void test_KiUserExceptionDispatcher(void)
{
WORD hook_trampoline[] =
{
0x4668, /* mov r0, sp */
0xf8df, 0xc006, /* ldr.w r12, [pc, #0x6] */
0x47e0, /* blx r12 */
0x4700, /* bx r0 */
0, 0, /* 1: hook_KiUserExceptionDispatcher */
};
EXCEPTION_RECORD record = { EXCEPTION_BREAKPOINT };
void *trampoline_ptr, *vectored_handler;
DWORD old_protect;
BOOL ret;
code_ptr = (void *)(((ULONG_PTR)pKiUserExceptionDispatcher) & ~1); /* mask thumb bit */
*(void **)&hook_trampoline[5] = hook_KiUserExceptionDispatcher;
trampoline_ptr = (char *)code_mem + 1024;
memcpy( trampoline_ptr, hook_trampoline, sizeof(hook_trampoline));
ret = VirtualProtect( code_ptr, sizeof(saved_code),
PAGE_EXECUTE_READWRITE, &old_protect );
ok( ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError() );
memcpy( saved_code, code_ptr, sizeof(saved_code) );
*(void **)&patched_code[4] = (char *)trampoline_ptr + 1; /* thumb */
vectored_handler = AddVectoredExceptionHandler(TRUE, dbg_except_continue_vectored_handler);
memcpy( code_ptr, patched_code, sizeof(patched_code) );
FlushInstructionCache( GetCurrentProcess(), code_ptr, sizeof(patched_code));
got_exception = FALSE;
hook_called = FALSE;
pRtlRaiseException(&record);
ok(got_exception, "Handler was not called.\n");
todo_wine
ok(!hook_called, "Hook was called.\n");
memcpy( code_ptr, patched_code, sizeof(patched_code) );
FlushInstructionCache( GetCurrentProcess(), code_ptr, sizeof(patched_code));
got_exception = 0;
hook_called = FALSE;
NtCurrentTeb()->Peb->BeingDebugged = 1;
pRtlRaiseException(&record);
ok(got_exception, "Handler was not called.\n");
ok(hook_called, "Hook was not called.\n");
NtCurrentTeb()->Peb->BeingDebugged = 0;
RemoveVectoredExceptionHandler(vectored_handler);
VirtualProtect(code_ptr, sizeof(saved_code), old_protect, &old_protect);
}
#elif defined(__aarch64__)
#define UNW_FLAG_NHANDLER 0
......@@ -12245,6 +12347,7 @@ START_TEST(exception)
#elif defined(__arm__)
test_virtual_unwind();
test_KiUserExceptionDispatcher();
#endif
......
......@@ -174,6 +174,16 @@ enum arm_trap_code
TRAP_ARM_ALIGNFLT = 17, /* Alignment check exception */
};
/* stack layout when calling KiUserExceptionDispatcher */
struct exc_stack_layout
{
CONTEXT context; /* 000 */
EXCEPTION_RECORD rec; /* 1a0 */
ULONG redzone[2]; /* 1f0 */
};
C_ASSERT( offsetof(struct exc_stack_layout, rec) == 0x1a0 );
C_ASSERT( sizeof(struct exc_stack_layout) == 0x1f8 );
struct syscall_frame
{
UINT r0; /* 000 */
......@@ -1019,25 +1029,6 @@ NTSTATUS get_thread_wow64_context( HANDLE handle, void *ctx, ULONG size )
}
__ASM_GLOBAL_FUNC( raise_func_trampoline,
"push {r12,lr}\n\t" /* (Padding +) Pc in the original frame */
"ldr r3, [r1, #0x38]\n\t" /* context->Sp */
"push {r3}\n\t" /* Original Sp */
__ASM_CFI_CFA_IS_AT1(sp, 0x04)
__ASM_CFI_REG_IS_AT1(lr, sp, 0x0c)
__ASM_EHABI(".save {sp}\n\t")
__ASM_EHABI(".pad #-12\n\t")
__ASM_EHABI(".save {pc}\n\t")
__ASM_EHABI(".pad #8\n\t")
__ASM_EHABI(".save {lr}\n\t")
/* We can't express restoring both Pc and Lr with CFI
* directives, but we manually load Lr from the stack
* in unwind_builtin_dll above. */
"ldr r3, [r1, #0x3c]\n\t" /* context->Lr */
"push {r3}\n\t" /* Original Lr */
"blx r2\n\t"
"udf #0")
/***********************************************************************
* setup_exception
*
......@@ -1045,13 +1036,8 @@ __ASM_GLOBAL_FUNC( raise_func_trampoline,
*/
static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec )
{
struct
{
CONTEXT context;
EXCEPTION_RECORD rec;
} *stack;
void *stack_ptr = (void *)(SP_sig(sigcontext) & ~3);
struct exc_stack_layout *stack;
void *stack_ptr = (void *)(SP_sig(sigcontext) & ~7);
CONTEXT context;
NTSTATUS status;
......@@ -1071,13 +1057,9 @@ static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec )
/* now modify the sigcontext to return to the raise function */
SP_sig(sigcontext) = (DWORD)stack;
LR_sig(sigcontext) = context.Pc;
PC_sig(sigcontext) = (DWORD)raise_func_trampoline;
PC_sig(sigcontext) = (DWORD)pKiUserExceptionDispatcher;
if (PC_sig(sigcontext) & 1) CPSR_sig(sigcontext) |= 0x20;
else CPSR_sig(sigcontext) &= ~0x20;
REGn_sig(0, sigcontext) = (DWORD)&stack->rec; /* first arg for KiUserExceptionDispatcher */
REGn_sig(1, sigcontext) = (DWORD)&stack->context; /* second arg for KiUserExceptionDispatcher */
REGn_sig(2, sigcontext) = (DWORD)pKiUserExceptionDispatcher;
}
......@@ -1135,18 +1117,17 @@ void call_raise_user_exception_dispatcher(void)
*/
NTSTATUS call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context )
{
struct exc_stack_layout *stack;
struct syscall_frame *frame = arm_thread_data()->syscall_frame;
DWORD lr = frame->lr;
DWORD sp = frame->sp;
NTSTATUS status = NtSetContextThread( GetCurrentThread(), context );
if (status) return status;
frame->r0 = (DWORD)rec;
frame->r1 = (DWORD)context;
stack = (struct exc_stack_layout *)(context->Sp & ~7) - 1;
memmove( &stack->context, context, sizeof(*context) );
memmove( &stack->rec, rec, sizeof(*rec) );
frame->pc = (DWORD)pKiUserExceptionDispatcher;
frame->lr = lr;
frame->sp = sp;
frame->restore_flags |= CONTEXT_INTEGER | CONTEXT_CONTROL;
frame->sp = (DWORD)stack;
frame->restore_flags |= CONTEXT_CONTROL;
return status;
}
......
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