Commit 5b068472 authored by Alexandre Julliard's avatar Alexandre Julliard

ntdll: Fix stack layout for KiUserCallbackDispatcher on ARM.

parent 75d0d466
......@@ -575,7 +575,7 @@ __ASM_GLOBAL_FUNC( KiUserApcDispatcher,
/*******************************************************************
* KiUserCallbackDispatcher (NTDLL.@)
*/
void WINAPI KiUserCallbackDispatcher( ULONG id, void *args, ULONG len )
void WINAPI dispatch_callback( void *args, ULONG len, ULONG id )
{
NTSTATUS status;
......@@ -593,6 +593,21 @@ void WINAPI KiUserCallbackDispatcher( ULONG id, void *args, ULONG len )
RtlRaiseStatus( status );
}
__ASM_GLOBAL_FUNC( KiUserCallbackDispatcher,
__ASM_SEH(".seh_custom 0xee,0x01\n\t") /* MSFT_OP_MACHINE_FRAME */
"nop\n\t"
__ASM_SEH(".seh_save_regs {lr}\n\t")
"nop\n\t"
__ASM_SEH(".seh_stackalloc 0xc\n\t")
__ASM_SEH(".seh_endprologue\n\t")
__ASM_EHABI(".save {sp, pc}\n\t")
__ASM_EHABI(".save {lr}\n\t")
__ASM_EHABI(".pad #0x0c\n\t")
"ldr r0, [sp]\n\t" /* args */
"ldr r1, [sp, #0x04]\n\t" /* len */
"ldr r2, [sp, #0x08]\n\t" /* id */
"bl " __ASM_NAME("dispatch_callback") "\n\t"
"udf #1" )
/***********************************************************************
......
......@@ -7537,6 +7537,61 @@ static void test_KiUserApcDispatcher(void)
VirtualProtect( code_ptr, sizeof(saved_code), old_protect, &old_protect );
}
static void WINAPI hook_KiUserCallbackDispatcher(void *sp)
{
struct
{
void *args;
ULONG len;
ULONG id;
ULONG lr;
ULONG sp;
ULONG pc;
BYTE args_data[0];
} *stack = sp;
ULONG_PTR redzone = (BYTE *)stack->sp - &stack->args_data[stack->len];
NTSTATUS (WINAPI *func)(void *, ULONG) = ((void **)NtCurrentTeb()->Peb->KernelCallbackTable)[stack->id];
trace( "stack=%p len=%lx id=%lx lr=%lx sp=%lx pc=%lx\n",
stack, stack->len, stack->id, stack->lr, stack->sp, stack->pc );
NtCallbackReturn( NULL, 0, 0 );
ok( stack->args == stack->args_data, "wrong args %p / %p\n", stack->args, stack->args_data );
ok( redzone >= 8 && redzone <= 16, "wrong sp %p / %p (%Iu)\n",
(void *)stack->sp, stack->args_data, redzone );
if (pRtlPcToFileHeader)
{
void *mod, *win32u = GetModuleHandleA("win32u.dll");
pRtlPcToFileHeader( (void *)stack->pc, &mod );
ok( mod == win32u, "pc %lx not in win32u %p\n", stack->pc, win32u );
}
NtCallbackReturn( NULL, 0, func( stack->args, stack->len ));
}
void test_KiUserCallbackDispatcher(void)
{
DWORD old_protect;
BOOL ret;
code_ptr = (void *)(((ULONG_PTR)pKiUserCallbackDispatcher) & ~1); /* mask thumb bit */
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] = hook_KiUserCallbackDispatcher;
memcpy( code_ptr, patched_code, sizeof(patched_code));
FlushInstructionCache(GetCurrentProcess(), code_ptr, sizeof(patched_code));
DestroyWindow( CreateWindowA( "Static", "test", 0, 0, 0, 0, 0, 0, 0, 0, 0 ));
memcpy( code_ptr, saved_code, sizeof(saved_code));
FlushInstructionCache(GetCurrentProcess(), code_ptr, sizeof(saved_code));
VirtualProtect( code_ptr, sizeof(saved_code), old_protect, &old_protect );
}
#elif defined(__aarch64__)
#define UNW_FLAG_NHANDLER 0
......@@ -12372,9 +12427,6 @@ START_TEST(exception)
test_fpu_exceptions();
test_dpe_exceptions();
test_prot_fault();
test_KiUserExceptionDispatcher();
test_KiUserApcDispatcher();
test_KiUserCallbackDispatcher();
test_extended_context();
test_copy_context();
test_set_live_context();
......@@ -12411,9 +12463,6 @@ START_TEST(exception)
test_prot_fault();
test_dpe_exceptions();
test_wow64_context();
test_KiUserExceptionDispatcher();
test_KiUserApcDispatcher();
test_KiUserCallbackDispatcher();
test_nested_exception();
test_collided_unwind();
......@@ -12432,18 +12481,16 @@ START_TEST(exception)
test_continue();
test_virtual_unwind();
test_KiUserExceptionDispatcher();
test_KiUserApcDispatcher();
test_KiUserCallbackDispatcher();
#elif defined(__arm__)
test_virtual_unwind();
test_KiUserExceptionDispatcher();
test_KiUserApcDispatcher();
#endif
test_KiUserExceptionDispatcher();
test_KiUserApcDispatcher();
test_KiUserCallbackDispatcher();
test_debugger(DBG_EXCEPTION_HANDLED, FALSE);
test_debugger(DBG_CONTINUE, FALSE);
test_debugger(DBG_EXCEPTION_HANDLED, TRUE);
......
......@@ -197,6 +197,19 @@ struct apc_stack_layout
C_ASSERT( offsetof(struct apc_stack_layout, context) == 0x18 );
C_ASSERT( sizeof(struct apc_stack_layout) == 0x1c0 );
/* stack layout when calling KiUserCallbackDispatcher */
struct callback_stack_layout
{
void *args; /* 000 arguments */
ULONG len; /* 004 arguments len */
ULONG id; /* 008 function id */
ULONG lr; /* 00c */
ULONG sp; /* 010 */
ULONG pc; /* 014 */
BYTE args_data[0]; /* 018 copied argument data*/
};
C_ASSERT( sizeof(struct callback_stack_layout) == 0x18 );
struct syscall_frame
{
UINT r0; /* 000 */
......@@ -1143,8 +1156,8 @@ NTSTATUS call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context
/***********************************************************************
* call_user_mode_callback
*/
extern NTSTATUS call_user_mode_callback( ULONG id, void *args, ULONG len, void **ret_ptr,
ULONG *ret_len, void *func, TEB *teb );
extern NTSTATUS call_user_mode_callback( ULONG user_sp, void **ret_ptr, ULONG *ret_len,
void *func, TEB *teb );
__ASM_GLOBAL_FUNC( call_user_mode_callback,
"push {r4-r12,lr}\n\t"
"add r7, sp, #0x28\n\t" /* syscall_cfa */
......@@ -1159,10 +1172,9 @@ __ASM_GLOBAL_FUNC( call_user_mode_callback,
__ASM_CFI(".cfi_offset r11,-0x0c\n\t")
__ASM_CFI(".cfi_offset r12,-0x08\n\t")
__ASM_CFI(".cfi_offset lr,-0x04\n\t")
"ldr ip, [sp, #0x2c]\n\t" /* func */
"ldr r4, [sp, #0x30]\n\t" /* teb */
"ldr r4, [sp, #0x28]\n\t" /* teb */
"ldr r5, [r4]\n\t" /* teb->Tib.ExceptionList */
"push {r3, r5}\n\t"
"push {r1,r2,r4,r5}\n\t" /* ret_ptr, ret_len, teb, exception_list */
#ifndef __SOFTFP__
"sub sp, sp, #0x90\n\t"
"mov r5, sp\n\t"
......@@ -1176,8 +1188,8 @@ __ASM_GLOBAL_FUNC( call_user_mode_callback,
"str r7, [sp, #0x50]\n\t" /* frame->syscall_cfa */
"str sp, [r4, #0x1d8]\n\t" /* arm_thread_data()->syscall_frame */
/* switch to user stack */
"mov sp, r1\n\t"
"bx ip" )
"mov sp, r0\n\t"
"bx r3" )
/***********************************************************************
......@@ -1197,11 +1209,10 @@ __ASM_GLOBAL_FUNC( user_mode_callback_return,
"add r5, r5, #0x90\n\t"
#endif
"mov sp, r5\n\t"
"pop {r5, r7}\n\t"
"ldr r6, [sp, #0x28]\n\t" /* ret_len */
"pop {r4-r7}\n\t" /* ret_ptr, ret_len, teb, exception_list */
"str r7, [r3]\n\t" /* teb->Tib.ExceptionList */
"str r0, [r5]\n\t" /* ret_ptr */
"str r1, [r6]\n\t" /* ret_len */
"str r0, [r4]\n\t" /* ret_ptr */
"str r1, [r5]\n\t" /* ret_len */
"mov r0, r2\n\t" /* status */
"pop {r4-r12,pc}" )
......@@ -1236,14 +1247,20 @@ __ASM_GLOBAL_FUNC( user_mode_abort_thread,
NTSTATUS KeUserModeCallback( ULONG id, const void *args, ULONG len, void **ret_ptr, ULONG *ret_len )
{
struct syscall_frame *frame = arm_thread_data()->syscall_frame;
void *args_data = (void *)((frame->sp - len) & ~15);
ULONG sp = (frame->sp - offsetof( struct callback_stack_layout, args_data[len] ) - 8) & ~7;
struct callback_stack_layout *stack = (struct callback_stack_layout *)sp;
if ((char *)ntdll_get_thread_data()->kernel_stack + min_kernel_stack > (char *)&frame)
return STATUS_STACK_OVERFLOW;
memcpy( args_data, args, len );
return call_user_mode_callback( id, args_data, len, ret_ptr, ret_len,
pKiUserCallbackDispatcher, NtCurrentTeb() );
stack->args = stack->args_data;
stack->len = len;
stack->id = id;
stack->lr = frame->lr;
stack->sp = frame->sp;
stack->pc = frame->pc;
memcpy( stack->args_data, args, len );
return call_user_mode_callback( sp, ret_ptr, ret_len, pKiUserCallbackDispatcher, NtCurrentTeb() );
}
......
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