mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-14 19:27:17 +00:00
ntdll: Fix stack layout for KiUserApcDispatcher on i386.
This commit is contained in:
parent
58a00854c3
commit
3774b00f31
|
@ -255,12 +255,14 @@ __ASM_STDCALL_FUNC( KiUserExceptionDispatcher, 8,
|
|||
/*******************************************************************
|
||||
* 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_STDCALL_FUNC( KiUserApcDispatcher, 20,
|
||||
"leal 0x14(%esp),%ebx\n\t" /* context */
|
||||
"pop %eax\n\t" /* func */
|
||||
"call *%eax\n\t"
|
||||
"pushl -4(%ebx)\n\t" /* alertable */
|
||||
"pushl %ebx\n\t" /* context */
|
||||
"call " __ASM_STDCALL("NtContinue", 8) "\n\t"
|
||||
"int3" )
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
|
|
|
@ -2070,6 +2070,111 @@ static void test_KiUserExceptionDispatcher(void)
|
|||
ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
|
||||
}
|
||||
|
||||
static BYTE saved_KiUserApcDispatcher[7];
|
||||
static UINT apc_count;
|
||||
|
||||
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 * CDECL hook_KiUserApcDispatcher( void *func, ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
|
||||
{
|
||||
CONTEXT *context = (CONTEXT *)((ULONG_PTR)&arg3 + sizeof(ULONG));
|
||||
|
||||
ok( func == apc_func, "wrong function %p / %p\n", func, apc_func );
|
||||
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 );
|
||||
|
||||
if (context->ContextFlags != 1)
|
||||
{
|
||||
trace( "context %p eip %lx ebp %lx esp %lx (%x)\n",
|
||||
context, context->Eip, context->Ebp, context->Esp, (char *)context->Esp - (char *)&func );
|
||||
}
|
||||
else /* new style with alertable arg and CONTEXT_EX */
|
||||
{
|
||||
CONTEXT_EX *xctx;
|
||||
ULONG *alertable = (ULONG *)context;
|
||||
|
||||
context = (CONTEXT *)(alertable + 1);
|
||||
xctx = (CONTEXT_EX *)(context + 1);
|
||||
|
||||
trace( "alertable %lx context %p eip %lx ebp %lx esp %lx (%x)\n", *alertable,
|
||||
context, context->Eip, context->Ebp, context->Esp, (char *)context->Esp - (char *)&func );
|
||||
if ((void *)(xctx + 1) < (void *)context->Esp)
|
||||
{
|
||||
ok( xctx->All.Offset == -sizeof(CONTEXT), "wrong All.Offset %lx\n", xctx->All.Offset );
|
||||
ok( xctx->All.Length >= sizeof(CONTEXT) + sizeof(CONTEXT_EX), "wrong All.Length %lx\n", xctx->All.Length );
|
||||
ok( xctx->Legacy.Offset == -sizeof(CONTEXT), "wrong Legacy.Offset %lx\n", xctx->All.Offset );
|
||||
ok( xctx->Legacy.Length == sizeof(CONTEXT), "wrong Legacy.Length %lx\n", xctx->All.Length );
|
||||
}
|
||||
|
||||
if (apc_count) *alertable = 0;
|
||||
pNtQueueApcThread( GetCurrentThread(), apc_func, 0x1234 + apc_count + 1, 0x5678, 0xdeadbeef );
|
||||
}
|
||||
|
||||
hook_called = TRUE;
|
||||
memcpy( pKiUserApcDispatcher, saved_KiUserApcDispatcher, sizeof(saved_KiUserApcDispatcher));
|
||||
return pKiUserApcDispatcher;
|
||||
}
|
||||
|
||||
static void test_KiUserApcDispatcher(void)
|
||||
{
|
||||
BYTE hook_trampoline[] =
|
||||
{
|
||||
0xff, 0x15,
|
||||
/* offset: 2 bytes */
|
||||
0x00, 0x00, 0x00, 0x00, /* call *addr */ /* call hook implementation. */
|
||||
0xff, 0xe0, /* jmp *%eax */
|
||||
};
|
||||
|
||||
BYTE patched_KiUserApcDispatcher[7];
|
||||
void *phook_KiUserApcDispatcher = hook_KiUserApcDispatcher;
|
||||
DWORD old_protect;
|
||||
BYTE *ptr;
|
||||
BOOL ret;
|
||||
|
||||
*(ULONG_PTR *)(hook_trampoline + 2) = (ULONG_PTR)&phook_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 $hook_trampoline, %eax */
|
||||
*ptr++ = 0xb8;
|
||||
*(void **)ptr = code_mem;
|
||||
ptr += sizeof(void *);
|
||||
/* jmp *eax */
|
||||
*ptr++ = 0xff;
|
||||
*ptr++ = 0xe0;
|
||||
memcpy( pKiUserApcDispatcher, patched_KiUserApcDispatcher, sizeof(patched_KiUserApcDispatcher) );
|
||||
|
||||
apc_count = 0;
|
||||
hook_called = FALSE;
|
||||
pNtQueueApcThread( GetCurrentThread(), apc_func, 0x1234, 0x5678, 0xdeadbeef );
|
||||
SleepEx( 0, TRUE );
|
||||
ok( apc_count == 1 || apc_count == 2, "APC count %u\n", apc_count );
|
||||
ok( hook_called, "hook was not called\n" );
|
||||
|
||||
if (apc_count == 2)
|
||||
{
|
||||
memcpy( pKiUserApcDispatcher, patched_KiUserApcDispatcher, sizeof(patched_KiUserApcDispatcher) );
|
||||
pNtQueueApcThread( GetCurrentThread(), apc_func, 0x1234 + apc_count, 0x5678, 0xdeadbeef );
|
||||
SleepEx( 0, TRUE );
|
||||
ok( apc_count == 3, "APC count %u\n", apc_count );
|
||||
SleepEx( 0, TRUE );
|
||||
ok( apc_count == 4, "APC count %u\n", apc_count );
|
||||
}
|
||||
VirtualProtect( pKiUserApcDispatcher, sizeof(saved_KiUserApcDispatcher), old_protect, &old_protect );
|
||||
}
|
||||
|
||||
#elif defined(__x86_64__)
|
||||
|
||||
#define UNW_FLAG_NHANDLER 0
|
||||
|
@ -12015,6 +12120,7 @@ START_TEST(exception)
|
|||
test_dpe_exceptions();
|
||||
test_prot_fault();
|
||||
test_KiUserExceptionDispatcher();
|
||||
test_KiUserApcDispatcher();
|
||||
test_extended_context();
|
||||
test_copy_context();
|
||||
test_set_live_context();
|
||||
|
|
|
@ -450,6 +450,21 @@ C_ASSERT( offsetof(struct exc_stack_layout, context) == 0x58 );
|
|||
C_ASSERT( offsetof(struct exc_stack_layout, xstate) == 0x33c );
|
||||
C_ASSERT( sizeof(struct exc_stack_layout) == 0x4c0 );
|
||||
|
||||
/* stack layout when calling KiUserApcDispatcher */
|
||||
struct apc_stack_layout
|
||||
{
|
||||
PNTAPCFUNC func; /* 000 */
|
||||
UINT arg1; /* 004 */
|
||||
UINT arg2; /* 008 */
|
||||
UINT arg3; /* 00c */
|
||||
UINT alertable; /* 010 */
|
||||
CONTEXT context; /* 014 */
|
||||
CONTEXT_EX xctx; /* 2e0 */
|
||||
UINT unk2[4]; /* 2f8 */
|
||||
};
|
||||
C_ASSERT( offsetof(struct apc_stack_layout, context) == 0x14 );
|
||||
C_ASSERT( sizeof(struct apc_stack_layout) == 0x308 );
|
||||
|
||||
struct syscall_frame
|
||||
{
|
||||
WORD syscall_flags; /* 000 */
|
||||
|
@ -1495,17 +1510,6 @@ static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec )
|
|||
setup_raise_exception( sigcontext, stack, rec, &xcontext );
|
||||
}
|
||||
|
||||
/* stack layout when calling an user apc function.
|
||||
* FIXME: match Windows ABI. */
|
||||
struct apc_stack_layout
|
||||
{
|
||||
CONTEXT *context_ptr;
|
||||
ULONG_PTR arg1;
|
||||
ULONG_PTR arg2;
|
||||
ULONG_PTR arg3;
|
||||
PNTAPCFUNC func;
|
||||
CONTEXT context;
|
||||
};
|
||||
|
||||
/***********************************************************************
|
||||
* call_user_apc_dispatcher
|
||||
|
@ -1525,13 +1529,14 @@ NTSTATUS call_user_apc_dispatcher( CONTEXT *context, ULONG_PTR arg1, ULONG_PTR a
|
|||
}
|
||||
else memmove( &stack->context, context, sizeof(stack->context) );
|
||||
|
||||
stack->context_ptr = &stack->context;
|
||||
stack->arg1 = arg1;
|
||||
stack->arg2 = arg2;
|
||||
stack->arg3 = arg3;
|
||||
stack->func = func;
|
||||
context_init_xstate( &stack->context, NULL );
|
||||
stack->func = func;
|
||||
stack->arg1 = arg1;
|
||||
stack->arg2 = arg2;
|
||||
stack->arg3 = arg3;
|
||||
stack->alertable = TRUE;
|
||||
frame->ebp = stack->context.Ebp;
|
||||
frame->esp = (ULONG)stack - 4;
|
||||
frame->esp = (ULONG)stack;
|
||||
frame->eip = (ULONG)pKiUserApcDispatcher;
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -1000,26 +1000,39 @@ void WINAPI Wow64ApcRoutine( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3, CON
|
|||
{
|
||||
case IMAGE_FILE_MACHINE_I386:
|
||||
{
|
||||
struct apc_stack_layout
|
||||
/* stack layout when calling 32-bit KiUserApcDispatcher */
|
||||
struct apc_stack_layout32
|
||||
{
|
||||
ULONG ret;
|
||||
ULONG context_ptr;
|
||||
ULONG arg1;
|
||||
ULONG arg2;
|
||||
ULONG arg3;
|
||||
ULONG func;
|
||||
I386_CONTEXT context;
|
||||
ULONG func; /* 000 */
|
||||
UINT arg1; /* 004 */
|
||||
UINT arg2; /* 008 */
|
||||
UINT arg3; /* 00c */
|
||||
UINT alertable; /* 010 */
|
||||
I386_CONTEXT context; /* 014 */
|
||||
CONTEXT_EX32 xctx; /* 2e0 */
|
||||
UINT unk2[4]; /* 2f8 */
|
||||
} *stack;
|
||||
I386_CONTEXT ctx = { CONTEXT_I386_FULL };
|
||||
|
||||
C_ASSERT( offsetof(struct apc_stack_layout32, context) == 0x14 );
|
||||
C_ASSERT( sizeof(struct apc_stack_layout32) == 0x308 );
|
||||
|
||||
pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
|
||||
stack = (struct apc_stack_layout *)ULongToPtr( ctx.Esp & ~3 ) - 1;
|
||||
stack->context_ptr = PtrToUlong( &stack->context );
|
||||
stack->func = arg1 >> 32;
|
||||
stack->arg1 = arg1;
|
||||
stack->arg2 = arg2;
|
||||
stack->arg3 = arg3;
|
||||
stack->context = ctx;
|
||||
|
||||
stack = (struct apc_stack_layout32 *)ULongToPtr( ctx.Esp & ~3 ) - 1;
|
||||
stack->func = arg1 >> 32;
|
||||
stack->arg1 = arg1;
|
||||
stack->arg2 = arg2;
|
||||
stack->arg3 = arg3;
|
||||
stack->alertable = TRUE;
|
||||
stack->context = ctx;
|
||||
stack->xctx.Legacy.Offset = -(LONG)sizeof(stack->context);
|
||||
stack->xctx.Legacy.Length = sizeof(stack->context);
|
||||
stack->xctx.All.Offset = -(LONG)sizeof(stack->context);
|
||||
stack->xctx.All.Length = sizeof(stack->context) + sizeof(stack->xctx);
|
||||
stack->xctx.XState.Offset = 25;
|
||||
stack->xctx.XState.Length = 0;
|
||||
|
||||
ctx.Esp = PtrToUlong( stack );
|
||||
ctx.Eip = pLdrSystemDllInitBlock->pKiUserApcDispatcher;
|
||||
frame.wow_context = &stack->context;
|
||||
|
|
Loading…
Reference in a new issue