mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-14 21:27:19 +00:00
ntdll: Add a machine frame to the KiUserApcDispatcher stack on x86-64.
This commit is contained in:
parent
061c612b5e
commit
8b24139fa7
|
@ -652,30 +652,40 @@ __ASM_GLOBAL_FUNC( KiUserExceptionDispatcher,
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
* KiUserApcDispatcher (NTDLL.@)
|
* 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,
|
__ASM_GLOBAL_FUNC( KiUserApcDispatcher,
|
||||||
"addq $0x8,%rsp\n\t"
|
__ASM_SEH(".seh_pushframe\n\t")
|
||||||
"mov 0x98(%rcx),%r10\n\t" /* context->Rsp */
|
__ASM_SEH(".seh_stackalloc 0x4d0\n\t") /* sizeof(CONTEXT) */
|
||||||
"mov 0xf8(%rcx),%r11\n\t" /* context->Rip */
|
__ASM_SEH(".seh_savereg %rbx,0x90\n\t")
|
||||||
"mov %r11,-0x8(%r10)\n\t"
|
__ASM_SEH(".seh_savereg %rbp,0xa0\n\t")
|
||||||
"mov %rbp,-0x10(%r10)\n\t"
|
__ASM_SEH(".seh_savereg %rsi,0xa8\n\t")
|
||||||
"lea -0x10(%r10),%rbp\n\t"
|
__ASM_SEH(".seh_savereg %rdi,0xb0\n\t")
|
||||||
__ASM_SEH(".seh_pushreg %rbp\n\t")
|
__ASM_SEH(".seh_savereg %r12,0xd8\n\t")
|
||||||
__ASM_SEH(".seh_setframe %rbp,0\n\t")
|
__ASM_SEH(".seh_savereg %r13,0xe0\n\t")
|
||||||
__ASM_SEH(".seh_endprologue\n\t")
|
__ASM_SEH(".seh_savereg %r14,0xe8\n\t")
|
||||||
__ASM_CFI(".cfi_signal_frame\n\t")
|
__ASM_SEH(".seh_savereg %r15,0xf0\n\t")
|
||||||
__ASM_CFI(".cfi_adjust_cfa_offset 0x10\n\t")
|
__ASM_SEH(".seh_endprologue\n\t")
|
||||||
__ASM_CFI(".cfi_def_cfa %rbp,0x10\n\t")
|
__ASM_CFI(".cfi_signal_frame\n\t")
|
||||||
__ASM_CFI(".cfi_rel_offset %rip,0x8\n\t")
|
__ASM_CFI(".cfi_def_cfa_offset 0\n\t")
|
||||||
__ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
|
__ASM_CFI(".cfi_offset %rbx,0x90\n\t")
|
||||||
"call " __ASM_NAME("dispatch_apc") "\n\t"
|
__ASM_CFI(".cfi_offset %rbp,0xa0\n\t")
|
||||||
"int3")
|
__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 *pGetXStateFeaturesMask)(CONTEXT *context, DWORD64 *feature_mask);
|
||||||
static BOOL (WINAPI *pWaitForDebugEventEx)(DEBUG_EVENT *, DWORD);
|
static BOOL (WINAPI *pWaitForDebugEventEx)(DEBUG_EVENT *, DWORD);
|
||||||
|
|
||||||
|
static void *pKiUserApcDispatcher;
|
||||||
static void *pKiUserExceptionDispatcher;
|
static void *pKiUserExceptionDispatcher;
|
||||||
|
|
||||||
#define RTL_UNLOAD_EVENT_TRACE_NUMBER 64
|
#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());
|
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 BOOL got_nested_exception, got_prev_frame_exception;
|
||||||
static void *nested_exception_initial_frame;
|
static void *nested_exception_initial_frame;
|
||||||
|
|
||||||
|
@ -11476,6 +11565,7 @@ START_TEST(exception)
|
||||||
X(RtlGetExtendedFeaturesMask);
|
X(RtlGetExtendedFeaturesMask);
|
||||||
X(RtlCopyContext);
|
X(RtlCopyContext);
|
||||||
X(RtlCopyExtendedContext);
|
X(RtlCopyExtendedContext);
|
||||||
|
X(KiUserApcDispatcher);
|
||||||
X(KiUserExceptionDispatcher);
|
X(KiUserExceptionDispatcher);
|
||||||
#undef X
|
#undef X
|
||||||
|
|
||||||
|
@ -11637,6 +11727,7 @@ START_TEST(exception)
|
||||||
test_dpe_exceptions();
|
test_dpe_exceptions();
|
||||||
test_wow64_context();
|
test_wow64_context();
|
||||||
test_KiUserExceptionDispatcher();
|
test_KiUserExceptionDispatcher();
|
||||||
|
test_KiUserApcDispatcher();
|
||||||
test_nested_exception();
|
test_nested_exception();
|
||||||
test_collided_unwind();
|
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( offsetof(struct exc_stack_layout, machine_frame) == 0x590 );
|
||||||
C_ASSERT( sizeof(struct exc_stack_layout) == 0x700 );
|
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 */
|
/* flags to control the behavior of the syscall dispatcher */
|
||||||
#define SYSCALL_HAVE_XSAVE 1
|
#define SYSCALL_HAVE_XSAVE 1
|
||||||
#define SYSCALL_HAVE_XSAVEC 2
|
#define SYSCALL_HAVE_XSAVEC 2
|
||||||
|
@ -373,18 +383,6 @@ C_ASSERT( sizeof(struct exc_stack_layout) == 0x700 );
|
||||||
|
|
||||||
static unsigned int syscall_flags;
|
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
|
struct syscall_frame
|
||||||
{
|
{
|
||||||
ULONG64 rax; /* 0000 */
|
ULONG64 rax; /* 0000 */
|
||||||
|
@ -1492,15 +1490,16 @@ NTSTATUS call_user_apc_dispatcher( CONTEXT *context, ULONG_PTR arg1, ULONG_PTR a
|
||||||
NtGetContextThread( GetCurrentThread(), &stack->context );
|
NtGetContextThread( GetCurrentThread(), &stack->context );
|
||||||
stack->context.Rax = status;
|
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->rbp = stack->context.Rbp;
|
||||||
frame->rsp = (ULONG64)stack - 8;
|
frame->rsp = (ULONG64)stack;
|
||||||
frame->rip = (ULONG64)pKiUserApcDispatcher;
|
frame->rip = (ULONG64)pKiUserApcDispatcher;
|
||||||
frame->rcx = (ULONG64)&stack->context;
|
frame->restore_flags |= CONTEXT_CONTROL;
|
||||||
frame->rdx = arg1;
|
|
||||||
frame->r8 = arg2;
|
|
||||||
frame->r9 = arg3;
|
|
||||||
stack->func = func;
|
|
||||||
frame->restore_flags |= CONTEXT_CONTROL | CONTEXT_INTEGER;
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue