mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-03 00:55:17 +00:00
ntdll: Fix stack layout for KiUserApcDispatcher on ARM.
This commit is contained in:
parent
89f3c59739
commit
75d0d466ec
|
@ -547,12 +547,29 @@ __ASM_GLOBAL_FUNC( KiUserExceptionDispatcher,
|
|||
/*******************************************************************
|
||||
* KiUserApcDispatcher (NTDLL.@)
|
||||
*/
|
||||
void WINAPI KiUserApcDispatcher( CONTEXT *context, ULONG_PTR ctx, ULONG_PTR arg1, ULONG_PTR arg2,
|
||||
PNTAPCFUNC func )
|
||||
{
|
||||
func( ctx, arg1, arg2 );
|
||||
NtContinue( context, TRUE );
|
||||
}
|
||||
__ASM_GLOBAL_FUNC( KiUserApcDispatcher,
|
||||
__ASM_SEH(".seh_custom 0xee,0x02\n\t") /* MSFT_OP_CONTEXT */
|
||||
"nop\n\t"
|
||||
__ASM_SEH(".seh_stackalloc 0x18\n\t")
|
||||
__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 #0x2c\n\t") /* Skip past args, ContextFlags and R0-R3 */
|
||||
"ldr r0, [sp, #0x04]\n\t" /* arg1 */
|
||||
"ldr r1, [sp, #0x08]\n\t" /* arg2 */
|
||||
"ldr r2, [sp, #0x0c]\n\t" /* arg3 */
|
||||
"ldr ip, [sp]\n\t" /* func */
|
||||
"blx ip\n\t"
|
||||
"add r0, sp, #0x18\n\t" /* context */
|
||||
"ldr r1, [sp, #0x10]\n\t" /* alertable */
|
||||
"bl " __ASM_NAME("NtContinue") "\n\t"
|
||||
"udf #1" )
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
|
|
|
@ -7445,6 +7445,98 @@ static void test_KiUserExceptionDispatcher(void)
|
|||
VirtualProtect(code_ptr, sizeof(saved_code), old_protect, &old_protect);
|
||||
}
|
||||
|
||||
static UINT apc_count;
|
||||
static UINT alertable_supported;
|
||||
|
||||
static void CALLBACK apc_func( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
|
||||
{
|
||||
ok( arg1 == 0x1234 + apc_count, "wrong arg1 %Ix\n", arg1 );
|
||||
ok( arg2 == 0x5678, "wrong arg2 %Ix\n", arg2 );
|
||||
ok( arg3 == 0xdeadbeef, "wrong arg3 %Ix\n", arg3 );
|
||||
apc_count++;
|
||||
}
|
||||
|
||||
static void * WINAPI hook_KiUserApcDispatcher(void *stack)
|
||||
{
|
||||
struct
|
||||
{
|
||||
void *func;
|
||||
ULONG args[3];
|
||||
ULONG alertable;
|
||||
ULONG align;
|
||||
CONTEXT context;
|
||||
} *args = stack;
|
||||
CONTEXT *context = &args->context;
|
||||
|
||||
if (args->alertable == 1) alertable_supported = TRUE;
|
||||
else context = (CONTEXT *)&args->alertable;
|
||||
|
||||
trace( "stack=%p func=%p args=%lx,%lx,%lx alertable=%lx context=%p pc=%lx sp=%lx (%lx)\n",
|
||||
args, args->func, args->args[0], args->args[1], args->args[2],
|
||||
args->alertable, context, context->Pc, context->Sp,
|
||||
context->Sp - (ULONG_PTR)stack );
|
||||
|
||||
ok( args->func == apc_func, "wrong func %p / %p\n", args->func, apc_func );
|
||||
ok( args->args[0] == 0x1234 + apc_count, "wrong arg1 %lx\n", args->args[0] );
|
||||
ok( args->args[1] == 0x5678, "wrong arg2 %lx\n", args->args[1] );
|
||||
ok( args->args[2] == 0xdeadbeef, "wrong arg3 %lx\n", args->args[2] );
|
||||
|
||||
if (apc_count && alertable_supported) args->alertable = FALSE;
|
||||
pNtQueueApcThread( GetCurrentThread(), apc_func, 0x1234 + apc_count + 1, 0x5678, 0xdeadbeef );
|
||||
|
||||
hook_called = TRUE;
|
||||
memcpy( code_ptr, saved_code, sizeof(saved_code));
|
||||
FlushInstructionCache( GetCurrentProcess(), code_ptr, sizeof(saved_code));
|
||||
return pKiUserApcDispatcher;
|
||||
}
|
||||
|
||||
static void test_KiUserApcDispatcher(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_KiUserApcDispatcher */
|
||||
};
|
||||
DWORD old_protect;
|
||||
BOOL ret;
|
||||
|
||||
code_ptr = (void *)(((ULONG_PTR)pKiUserApcDispatcher) & ~1); /* mask thumb bit */
|
||||
*(void **)&hook_trampoline[5] = hook_KiUserApcDispatcher;
|
||||
memcpy(code_mem, 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 *)code_mem + 1; /* thumb */
|
||||
memcpy( code_ptr, patched_code, sizeof(patched_code) );
|
||||
FlushInstructionCache( GetCurrentProcess(), code_ptr, sizeof(patched_code));
|
||||
|
||||
hook_called = FALSE;
|
||||
apc_count = 0;
|
||||
pNtQueueApcThread( GetCurrentThread(), apc_func, 0x1234, 0x5678, 0xdeadbeef );
|
||||
SleepEx( 0, TRUE );
|
||||
ok( apc_count == 2, "APC count %u\n", apc_count );
|
||||
ok( hook_called, "hook was not called\n" );
|
||||
|
||||
memcpy( code_ptr, patched_code, sizeof(patched_code) );
|
||||
FlushInstructionCache( GetCurrentProcess(), code_ptr, sizeof(patched_code));
|
||||
pNtQueueApcThread( GetCurrentThread(), apc_func, 0x1234 + apc_count, 0x5678, 0xdeadbeef );
|
||||
SleepEx( 0, TRUE );
|
||||
if (alertable_supported)
|
||||
{
|
||||
ok( apc_count == 3, "APC count %u\n", apc_count );
|
||||
SleepEx( 0, TRUE );
|
||||
}
|
||||
ok( apc_count == 4, "APC count %u\n", apc_count );
|
||||
|
||||
VirtualProtect( code_ptr, sizeof(saved_code), old_protect, &old_protect );
|
||||
}
|
||||
|
||||
#elif defined(__aarch64__)
|
||||
|
||||
#define UNW_FLAG_NHANDLER 0
|
||||
|
@ -12348,6 +12440,7 @@ START_TEST(exception)
|
|||
|
||||
test_virtual_unwind();
|
||||
test_KiUserExceptionDispatcher();
|
||||
test_KiUserApcDispatcher();
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -184,6 +184,19 @@ struct exc_stack_layout
|
|||
C_ASSERT( offsetof(struct exc_stack_layout, rec) == 0x1a0 );
|
||||
C_ASSERT( sizeof(struct exc_stack_layout) == 0x1f8 );
|
||||
|
||||
/* stack layout when calling KiUserApcDispatcher */
|
||||
struct apc_stack_layout
|
||||
{
|
||||
void *func; /* 000 APC to call*/
|
||||
ULONG args[3]; /* 004 function arguments */
|
||||
ULONG alertable; /* 010 */
|
||||
ULONG align; /* 014 */
|
||||
CONTEXT context; /* 018 */
|
||||
ULONG redzone[2]; /* 1b8 */
|
||||
};
|
||||
C_ASSERT( offsetof(struct apc_stack_layout, context) == 0x18 );
|
||||
C_ASSERT( sizeof(struct apc_stack_layout) == 0x1c0 );
|
||||
|
||||
struct syscall_frame
|
||||
{
|
||||
UINT r0; /* 000 */
|
||||
|
@ -1071,14 +1084,9 @@ NTSTATUS call_user_apc_dispatcher( CONTEXT *context, ULONG_PTR arg1, ULONG_PTR a
|
|||
{
|
||||
struct syscall_frame *frame = arm_thread_data()->syscall_frame;
|
||||
ULONG sp = context ? context->Sp : frame->sp;
|
||||
struct apc_stack_layout
|
||||
{
|
||||
void *func;
|
||||
void *align;
|
||||
CONTEXT context;
|
||||
} *stack;
|
||||
struct apc_stack_layout *stack;
|
||||
|
||||
sp &= ~15;
|
||||
sp &= ~7;
|
||||
stack = (struct apc_stack_layout *)sp - 1;
|
||||
if (context)
|
||||
{
|
||||
|
@ -1091,14 +1099,14 @@ NTSTATUS call_user_apc_dispatcher( CONTEXT *context, ULONG_PTR arg1, ULONG_PTR a
|
|||
NtGetContextThread( GetCurrentThread(), &stack->context );
|
||||
stack->context.R0 = status;
|
||||
}
|
||||
stack->func = func;
|
||||
stack->args[0] = arg1;
|
||||
stack->args[1] = arg2;
|
||||
stack->args[2] = arg3;
|
||||
|
||||
frame->sp = (DWORD)stack;
|
||||
frame->pc = (DWORD)pKiUserApcDispatcher;
|
||||
frame->r0 = (DWORD)&stack->context;
|
||||
frame->r1 = arg1;
|
||||
frame->r2 = arg2;
|
||||
frame->r3 = arg3;
|
||||
stack->func = func;
|
||||
frame->restore_flags |= CONTEXT_CONTROL | CONTEXT_INTEGER;
|
||||
frame->restore_flags |= CONTEXT_CONTROL;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue