Commit 8b24139f authored by Alexandre Julliard's avatar Alexandre Julliard

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

parent 061c612b
......@@ -652,30 +652,40 @@ __ASM_GLOBAL_FUNC( KiUserExceptionDispatcher,
/*******************************************************************
* KiUserApcDispatcher (NTDLL.@)
*/
void WINAPI dispatch_apc( CONTEXT *context, ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3,
void (CALLBACK *func)(ULONG_PTR,ULONG_PTR,ULONG_PTR,CONTEXT*) )
{
func( arg1, arg2, arg3, context );
NtContinue( context, TRUE );
}
__ASM_GLOBAL_FUNC( KiUserApcDispatcher,
"addq $0x8,%rsp\n\t"
"mov 0x98(%rcx),%r10\n\t" /* context->Rsp */
"mov 0xf8(%rcx),%r11\n\t" /* context->Rip */
"mov %r11,-0x8(%r10)\n\t"
"mov %rbp,-0x10(%r10)\n\t"
"lea -0x10(%r10),%rbp\n\t"
__ASM_SEH(".seh_pushreg %rbp\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 0x10\n\t")
__ASM_CFI(".cfi_def_cfa %rbp,0x10\n\t")
__ASM_CFI(".cfi_rel_offset %rip,0x8\n\t")
__ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
"call " __ASM_NAME("dispatch_apc") "\n\t"
"int3")
__ASM_SEH(".seh_pushframe\n\t")
__ASM_SEH(".seh_stackalloc 0x4d0\n\t") /* sizeof(CONTEXT) */
__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,0x4d0\n\t")
__ASM_CFI(".cfi_offset %rsp,0x4e8\n\t")
"movq 0x00(%rsp),%rcx\n\t" /* context->P1Home = arg1 */
"movq 0x08(%rsp),%rdx\n\t" /* context->P2Home = arg2 */
"movq 0x10(%rsp),%r8\n\t" /* context->P3Home = arg3 */
"movq 0x18(%rsp),%rax\n\t" /* context->P4Home = func */
"movq %rsp,%r9\n\t" /* context */
"callq *%rax\n\t"
"movq %rsp,%rcx\n\t" /* context */
"movl $1,%edx\n\t" /* alertable */
"call " __ASM_NAME("NtContinue") "\n\t"
"int3" )
/*******************************************************************
......
......@@ -79,6 +79,7 @@ static BOOL (WINAPI *pSetXStateFeaturesMask)(CONTEXT *context, DWORD64 feat
static BOOL (WINAPI *pGetXStateFeaturesMask)(CONTEXT *context, DWORD64 *feature_mask);
static BOOL (WINAPI *pWaitForDebugEventEx)(DEBUG_EVENT *, DWORD);
static void *pKiUserApcDispatcher;
static void *pKiUserExceptionDispatcher;
#define RTL_UNLOAD_EVENT_TRACE_NUMBER 64
......@@ -4930,6 +4931,94 @@ static void test_KiUserExceptionDispatcher(void)
ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
}
static BYTE saved_KiUserApcDispatcher[12];
static BOOL apc_called;
static void CALLBACK apc_func( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
{
ok( arg1 == 0x1234, "wrong arg1 %Ix\n", arg1 );
ok( arg2 == 0x5678, "wrong arg2 %Ix\n", arg2 );
ok( arg3 == 0xdeadbeef, "wrong arg3 %Ix\n", arg3 );
apc_called = TRUE;
}
static void * WINAPI hook_KiUserApcDispatcher(CONTEXT *context)
{
struct machine_frame *frame = (struct machine_frame *)(context + 1);
UINT i;
trace( "context %p, context->Rip %#Ix, context->Rsp %#Ix (%#Ix), ContextFlags %#lx.\n",
context, context->Rip, context->Rsp,
(char *)context->Rsp - (char *)context, context->ContextFlags );
ok( context->P1Home == 0x1234, "wrong p1 %#Ix\n", context->P1Home );
ok( context->P2Home == 0x5678, "wrong p2 %#Ix\n", context->P2Home );
ok( context->P3Home == 0xdeadbeef, "wrong p3 %#Ix\n", context->P3Home );
ok( context->P4Home == (ULONG_PTR)apc_func, "wrong p4 %#Ix / %p\n", context->P4Home, apc_func );
/* machine frame offset varies between Windows versions */
for (i = 0; i < 16; i++)
{
if (frame->rip == context->Rip) break;
frame = (struct machine_frame *)((ULONG64 *)frame + 2);
}
trace( "machine frame %p (%#Ix): rip=%#Ix cs=%#Ix eflags=%#Ix rsp=%#Ix ss=%#Ix\n",
frame, (char *)frame - (char *)context,
frame->rip, frame->cs, frame->eflags, frame->rsp, frame->ss );
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_called = TRUE;
memcpy( pKiUserApcDispatcher, saved_KiUserApcDispatcher, sizeof(saved_KiUserApcDispatcher));
return pKiUserApcDispatcher;
}
static void test_KiUserApcDispatcher(void)
{
BYTE hook_trampoline[] =
{
0x48, 0x89, 0xe1, /* mov %rsp,%rcx */
0x48, 0xb8, /* movabs hook_KiUserApcDispatcher,%rax */
0,0,0,0,0,0,0,0, /* offset 5 */
0xff, 0xd0, /* callq *rax */
0xff, 0xe0, /* jmpq *rax */
};
BYTE patched_KiUserApcDispatcher[12];
DWORD old_protect;
BYTE *ptr;
BOOL ret;
*(ULONG_PTR *)(hook_trampoline + 5) = (ULONG_PTR)hook_KiUserApcDispatcher;
memcpy(code_mem, hook_trampoline, sizeof(hook_trampoline));
ret = VirtualProtect( pKiUserApcDispatcher, sizeof(saved_KiUserApcDispatcher),
PAGE_EXECUTE_READWRITE, &old_protect );
ok( ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError() );
memcpy( saved_KiUserApcDispatcher, pKiUserApcDispatcher, sizeof(saved_KiUserApcDispatcher) );
ptr = patched_KiUserApcDispatcher;
/* mov $code_mem, %rax */
*ptr++ = 0x48;
*ptr++ = 0xb8;
*(void **)ptr = code_mem;
ptr += sizeof(ULONG64);
/* jmp *rax */
*ptr++ = 0xff;
*ptr++ = 0xe0;
memcpy( pKiUserApcDispatcher, patched_KiUserApcDispatcher, sizeof(patched_KiUserApcDispatcher) );
hook_called = FALSE;
apc_called = FALSE;
pNtQueueApcThread( GetCurrentThread(), apc_func, 0x1234, 0x5678, 0xdeadbeef );
SleepEx( 0, TRUE );
ok( apc_called, "APC was not called\n" );
ok( hook_called, "hook was not called\n" );
VirtualProtect( pKiUserApcDispatcher, sizeof(saved_KiUserApcDispatcher), old_protect, &old_protect );
}
static BOOL got_nested_exception, got_prev_frame_exception;
static void *nested_exception_initial_frame;
......@@ -11476,6 +11565,7 @@ START_TEST(exception)
X(RtlGetExtendedFeaturesMask);
X(RtlCopyContext);
X(RtlCopyExtendedContext);
X(KiUserApcDispatcher);
X(KiUserExceptionDispatcher);
#undef X
......@@ -11637,6 +11727,7 @@ START_TEST(exception)
test_dpe_exceptions();
test_wow64_context();
test_KiUserExceptionDispatcher();
test_KiUserApcDispatcher();
test_nested_exception();
test_collided_unwind();
......
......@@ -365,6 +365,16 @@ 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 );
/* stack layout when calling KiUserApcDispatcher */
struct apc_stack_layout
{
CONTEXT context; /* 000 */
struct machine_frame machine_frame; /* 4d0 */
ULONG64 align; /* 4f8 */
};
C_ASSERT( offsetof(struct apc_stack_layout, machine_frame) == 0x4d0 );
C_ASSERT( sizeof(struct apc_stack_layout) == 0x500 );
/* flags to control the behavior of the syscall dispatcher */
#define SYSCALL_HAVE_XSAVE 1
#define SYSCALL_HAVE_XSAVEC 2
......@@ -373,18 +383,6 @@ C_ASSERT( sizeof(struct exc_stack_layout) == 0x700 );
static unsigned int syscall_flags;
/* stack layout when calling an user apc function.
* FIXME: match Windows ABI. */
struct apc_stack_layout
{
ULONG64 save_regs[4];
void *func;
ULONG64 align;
CONTEXT context;
ULONG64 rbp;
ULONG64 rip;
};
struct syscall_frame
{
ULONG64 rax; /* 0000 */
......@@ -1492,15 +1490,16 @@ NTSTATUS call_user_apc_dispatcher( CONTEXT *context, ULONG_PTR arg1, ULONG_PTR a
NtGetContextThread( GetCurrentThread(), &stack->context );
stack->context.Rax = status;
}
stack->context.P1Home = arg1;
stack->context.P2Home = arg2;
stack->context.P3Home = arg3;
stack->context.P4Home = (ULONG64)func;
stack->machine_frame.rip = stack->context.Rip;
stack->machine_frame.rsp = stack->context.Rsp;
frame->rbp = stack->context.Rbp;
frame->rsp = (ULONG64)stack - 8;
frame->rsp = (ULONG64)stack;
frame->rip = (ULONG64)pKiUserApcDispatcher;
frame->rcx = (ULONG64)&stack->context;
frame->rdx = arg1;
frame->r8 = arg2;
frame->r9 = arg3;
stack->func = func;
frame->restore_flags |= CONTEXT_CONTROL | CONTEXT_INTEGER;
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