mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-14 19:27:17 +00:00
ntdll: Fix stack layout and unwind information for KiUserCallbackDispatcher on ARM64.
This commit is contained in:
parent
060a8b4af2
commit
d6bd264460
|
@ -605,7 +605,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;
|
||||
|
||||
|
@ -623,6 +623,17 @@ void WINAPI KiUserCallbackDispatcher( ULONG id, void *args, ULONG len )
|
|||
|
||||
RtlRaiseStatus( status );
|
||||
}
|
||||
__ASM_GLOBAL_FUNC( KiUserCallbackDispatcher,
|
||||
__ASM_SEH(".seh_pushframe\n\t")
|
||||
"nop\n\t"
|
||||
__ASM_SEH(".seh_stackalloc 0x20\n\t")
|
||||
"nop\n\t"
|
||||
__ASM_SEH(".seh_save_reg lr, 0x18\n\t")
|
||||
__ASM_SEH(".seh_endprologue\n\t")
|
||||
"ldr x0, [sp]\n\t" /* args */
|
||||
"ldp w1, w2, [sp, #0x08]\n\t" /* len, id */
|
||||
"bl " __ASM_NAME("dispatch_callback") "\n\t"
|
||||
"brk #1" )
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
|
|
|
@ -8750,6 +8750,60 @@ static void test_KiUserApcDispatcher(void)
|
|||
VirtualProtect( pKiUserApcDispatcher, sizeof(saved_code), old_protect, &old_protect );
|
||||
}
|
||||
|
||||
static void WINAPI hook_KiUserCallbackDispatcher(void *sp)
|
||||
{
|
||||
struct
|
||||
{
|
||||
void *args;
|
||||
ULONG len;
|
||||
ULONG id;
|
||||
ULONG64 unknown;
|
||||
ULONG64 lr;
|
||||
ULONG64 sp;
|
||||
ULONG64 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 unk=%Ix lr=%Ix sp=%Ix pc=%Ix\n",
|
||||
stack, stack->len, stack->id, stack->unknown, stack->lr, stack->sp, stack->pc );
|
||||
|
||||
ok( stack->args == stack->args_data, "wrong args %p / %p\n", stack->args, stack->args_data );
|
||||
ok( redzone >= 16 && redzone <= 32, "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 %Ix 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;
|
||||
|
||||
ret = VirtualProtect( pKiUserCallbackDispatcher, sizeof(saved_code),
|
||||
PAGE_EXECUTE_READWRITE, &old_protect );
|
||||
ok( ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError() );
|
||||
|
||||
memcpy( saved_code, pKiUserCallbackDispatcher, sizeof(saved_code));
|
||||
*(void **)&patched_code[3] = hook_KiUserCallbackDispatcher;
|
||||
memcpy( pKiUserCallbackDispatcher, patched_code, sizeof(patched_code));
|
||||
FlushInstructionCache(GetCurrentProcess(), pKiUserCallbackDispatcher, sizeof(patched_code));
|
||||
|
||||
DestroyWindow( CreateWindowA( "Static", "test", 0, 0, 0, 0, 0, 0, 0, 0, 0 ));
|
||||
|
||||
memcpy( pKiUserCallbackDispatcher, saved_code, sizeof(saved_code));
|
||||
FlushInstructionCache(GetCurrentProcess(), pKiUserCallbackDispatcher, sizeof(saved_code));
|
||||
VirtualProtect( pKiUserCallbackDispatcher, sizeof(saved_code), old_protect, &old_protect );
|
||||
}
|
||||
|
||||
#endif /* __aarch64__ */
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
|
@ -12014,6 +12068,7 @@ START_TEST(exception)
|
|||
test_virtual_unwind();
|
||||
test_KiUserExceptionDispatcher();
|
||||
test_KiUserApcDispatcher();
|
||||
test_KiUserCallbackDispatcher();
|
||||
|
||||
#elif defined(__arm__)
|
||||
|
||||
|
|
|
@ -151,6 +151,21 @@ struct apc_stack_layout
|
|||
C_ASSERT( offsetof(struct apc_stack_layout, context) == 0x30 );
|
||||
C_ASSERT( sizeof(struct apc_stack_layout) == 0x3d0 );
|
||||
|
||||
/* stack layout when calling KiUserCallbackDispatcher */
|
||||
struct callback_stack_layout
|
||||
{
|
||||
void *args; /* 000 arguments */
|
||||
ULONG len; /* 008 arguments len */
|
||||
ULONG id; /* 00c function id */
|
||||
ULONG64 unknown; /* 010 */
|
||||
ULONG64 lr; /* 018 */
|
||||
ULONG64 sp; /* 020 sp+pc (machine frame) */
|
||||
ULONG64 pc; /* 028 */
|
||||
BYTE args_data[0]; /* 030 copied argument data*/
|
||||
};
|
||||
C_ASSERT( offsetof(struct callback_stack_layout, sp) == 0x20 );
|
||||
C_ASSERT( sizeof(struct callback_stack_layout) == 0x30 );
|
||||
|
||||
struct syscall_frame
|
||||
{
|
||||
ULONG64 x[29]; /* 000 */
|
||||
|
@ -1053,8 +1068,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( ULONG64 user_sp, void **ret_ptr, ULONG *ret_len,
|
||||
void *func, TEB *teb );
|
||||
__ASM_GLOBAL_FUNC( call_user_mode_callback,
|
||||
"stp x29, x30, [sp,#-0xc0]!\n\t"
|
||||
__ASM_CFI(".cfi_def_cfa_offset 0xc0\n\t")
|
||||
|
@ -1081,22 +1096,22 @@ __ASM_GLOBAL_FUNC( call_user_mode_callback,
|
|||
"stp d10, d11, [x29, #0x70]\n\t"
|
||||
"stp d12, d13, [x29, #0x80]\n\t"
|
||||
"stp d14, d15, [x29, #0x90]\n\t"
|
||||
"stp x3, x4, [x29, #0xa0]\n\t" /* ret_ptr, ret_len */
|
||||
"mov x18, x6\n\t" /* teb */
|
||||
"mrs x3, fpcr\n\t"
|
||||
"mrs x4, fpsr\n\t"
|
||||
"bfi x3, x4, #0, #32\n\t"
|
||||
"ldr x4, [x18]\n\t" /* teb->Tib.ExceptionList */
|
||||
"stp x3, x4, [x29, #0xb0]\n\t"
|
||||
"stp x1, x2, [x29, #0xa0]\n\t" /* ret_ptr, ret_len */
|
||||
"mov x18, x4\n\t" /* teb */
|
||||
"mrs x1, fpcr\n\t"
|
||||
"mrs x2, fpsr\n\t"
|
||||
"bfi x1, x2, #0, #32\n\t"
|
||||
"ldr x2, [x18]\n\t" /* teb->Tib.ExceptionList */
|
||||
"stp x1, x2, [x29, #0xb0]\n\t"
|
||||
|
||||
"ldr x7, [x18, #0x2f0]\n\t" /* arm64_thread_data()->syscall_frame */
|
||||
"sub x3, sp, #0x330\n\t" /* sizeof(struct syscall_frame) */
|
||||
"str x3, [x18, #0x2f0]\n\t" /* arm64_thread_data()->syscall_frame */
|
||||
"sub x1, sp, #0x330\n\t" /* sizeof(struct syscall_frame) */
|
||||
"str x1, [x18, #0x2f0]\n\t" /* arm64_thread_data()->syscall_frame */
|
||||
"add x8, x29, #0xc0\n\t"
|
||||
"stp x7, x8, [x3, #0x110]\n\t" /* frame->prev_frame,syscall_cfa */
|
||||
"stp x7, x8, [x1, #0x110]\n\t" /* frame->prev_frame,syscall_cfa */
|
||||
/* switch to user stack */
|
||||
"mov sp, x1\n\t" /* stack */
|
||||
"br x5" )
|
||||
"mov sp, x0\n\t" /* user_sp */
|
||||
"br x3" )
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -1186,14 +1201,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 = arm64_thread_data()->syscall_frame;
|
||||
void *args_data = (void *)((frame->sp - len) & ~15);
|
||||
ULONG64 sp = (frame->sp - offsetof( struct callback_stack_layout, args_data[len] ) - 16) & ~15;
|
||||
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() );
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue