ntdll: Always copy context in call_user_apc_dispatcher() on x86.
Signed-off-by: Paul Gofman <pgofman@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
73281bf132
commit
175a3649ba
|
@ -2001,6 +2001,53 @@ static void test_kiuserexceptiondispatcher(void)
|
||||||
ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
|
ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BOOL test_apc_called;
|
||||||
|
|
||||||
|
static void CALLBACK test_apc(ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3)
|
||||||
|
{
|
||||||
|
test_apc_called = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_user_apc(void)
|
||||||
|
{
|
||||||
|
NTSTATUS status;
|
||||||
|
CONTEXT context;
|
||||||
|
int pass;
|
||||||
|
|
||||||
|
if (!pNtQueueApcThread)
|
||||||
|
{
|
||||||
|
win_skip("NtQueueApcThread is not available.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pass = 0;
|
||||||
|
InterlockedIncrement(&pass);
|
||||||
|
RtlCaptureContext(&context);
|
||||||
|
InterlockedIncrement(&pass);
|
||||||
|
|
||||||
|
if (pass == 2)
|
||||||
|
{
|
||||||
|
/* Try to make sure context data is far enough below context.Esp. */
|
||||||
|
CONTEXT c[4];
|
||||||
|
|
||||||
|
c[0] = context;
|
||||||
|
|
||||||
|
test_apc_called = FALSE;
|
||||||
|
status = pNtQueueApcThread(GetCurrentThread(), test_apc, 0, 0, 0);
|
||||||
|
ok(!status, "Got unexpected status %#x.\n", status);
|
||||||
|
SleepEx(0, TRUE);
|
||||||
|
ok(test_apc_called, "Test user APC was not called.\n");
|
||||||
|
test_apc_called = FALSE;
|
||||||
|
status = pNtQueueApcThread(GetCurrentThread(), test_apc, 0, 0, 0);
|
||||||
|
ok(!status, "Got unexpected status %#x.\n", status);
|
||||||
|
status = NtContinue(&c[0], TRUE );
|
||||||
|
|
||||||
|
/* Broken before Win7, in that case NtContinue returns here instead of restoring context after calling APC. */
|
||||||
|
ok(0, "Should not get here, status %#x.\n", status);
|
||||||
|
}
|
||||||
|
ok(pass == 3, "Got unexpected pass %d.\n", pass);
|
||||||
|
ok(test_apc_called, "Test user APC was not called.\n");
|
||||||
|
}
|
||||||
#elif defined(__x86_64__)
|
#elif defined(__x86_64__)
|
||||||
|
|
||||||
#define UNW_FLAG_NHANDLER 0
|
#define UNW_FLAG_NHANDLER 0
|
||||||
|
@ -8253,6 +8300,7 @@ START_TEST(exception)
|
||||||
test_kiuserexceptiondispatcher();
|
test_kiuserexceptiondispatcher();
|
||||||
test_extended_context();
|
test_extended_context();
|
||||||
test_copy_context();
|
test_copy_context();
|
||||||
|
test_user_apc();
|
||||||
|
|
||||||
#elif defined(__x86_64__)
|
#elif defined(__x86_64__)
|
||||||
|
|
||||||
|
|
|
@ -1665,6 +1665,42 @@ static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec )
|
||||||
setup_raise_exception( sigcontext, stack, rec, &xcontext );
|
setup_raise_exception( sigcontext, stack, rec, &xcontext );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* stack layout when calling an user apc function.
|
||||||
|
* FIXME: match Windows ABI. */
|
||||||
|
struct apc_stack_layout
|
||||||
|
{
|
||||||
|
void *context_ptr;
|
||||||
|
void *ctx;
|
||||||
|
void *arg1;
|
||||||
|
void *arg2;
|
||||||
|
void *func;
|
||||||
|
CONTEXT context;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct apc_stack_layout * WINAPI setup_user_apc_dispatcher_stack( CONTEXT *context, struct apc_stack_layout *stack,
|
||||||
|
void *ctx, void *arg1, void *arg2, void *func )
|
||||||
|
{
|
||||||
|
CONTEXT c;
|
||||||
|
|
||||||
|
if (!context)
|
||||||
|
{
|
||||||
|
c.ContextFlags = CONTEXT_FULL;
|
||||||
|
NtGetContextThread( GetCurrentThread(), &c );
|
||||||
|
context = &c;
|
||||||
|
}
|
||||||
|
memmove( &stack->context, context, sizeof(stack->context) );
|
||||||
|
stack->context_ptr = &stack->context;
|
||||||
|
stack->ctx = ctx;
|
||||||
|
stack->arg1 = arg1;
|
||||||
|
stack->arg2 = arg2;
|
||||||
|
stack->func = func;
|
||||||
|
stack->context.Eax = STATUS_USER_APC;
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
C_ASSERT( sizeof(struct apc_stack_layout) == 0x2e0 );
|
||||||
|
C_ASSERT( offsetof(struct syscall_frame, ret_addr) == 0x14 );
|
||||||
|
C_ASSERT( offsetof(struct apc_stack_layout, context) == 20 );
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* call_user_apc_dispatcher
|
* call_user_apc_dispatcher
|
||||||
|
@ -1672,41 +1708,27 @@ static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec )
|
||||||
__ASM_GLOBAL_FUNC( call_user_apc_dispatcher,
|
__ASM_GLOBAL_FUNC( call_user_apc_dispatcher,
|
||||||
"movl 4(%esp),%esi\n\t" /* context_ptr */
|
"movl 4(%esp),%esi\n\t" /* context_ptr */
|
||||||
"movl 24(%esp),%edi\n\t" /* dispatcher */
|
"movl 24(%esp),%edi\n\t" /* dispatcher */
|
||||||
|
"leal 4(%esp),%ebp\n\t"
|
||||||
"test %esi,%esi\n\t"
|
"test %esi,%esi\n\t"
|
||||||
"jz 1f\n\t"
|
"jz 1f\n\t"
|
||||||
"movl 0xc4(%esi),%eax\n\t" /* context_ptr->Rsp */
|
"movl 0xc4(%esi),%eax\n\t" /* context_ptr->Esp */
|
||||||
"leal -0x2f8(%eax),%eax\n\t" /* sizeof(CONTEXT) + offsetof(frame,ret_addr) + params */
|
"jmp 2f\n\t"
|
||||||
"movl 20(%esp),%ecx\n\t" /* func */
|
|
||||||
"movl %ecx,20(%eax)\n\t"
|
|
||||||
"movl 8(%esp),%ebx\n\t" /* ctx */
|
|
||||||
"movl 12(%esp),%edx\n\t" /* arg1 */
|
|
||||||
"movl 16(%esp),%ecx\n\t" /* arg2 */
|
|
||||||
"leal 4(%eax),%esp\n\t"
|
|
||||||
"jmp 2f\n"
|
|
||||||
"1:\tmovl %fs:0x1f8,%eax\n\t" /* x86_thread_data()->syscall_frame */
|
"1:\tmovl %fs:0x1f8,%eax\n\t" /* x86_thread_data()->syscall_frame */
|
||||||
"leal -0x2cc(%eax),%esi\n\t"
|
"leal 0x14(%eax),%eax\n\t" /* &x86_thread_data()->syscall_frame->ret_addr */
|
||||||
"movl %esp,%ebx\n\t"
|
"2:\tsubl $0x2e0,%eax\n\t" /* sizeof(struct apc_stack_layout) */
|
||||||
"cmpl %esp,%esi\n\t"
|
"movl %ebp,%esp\n\t" /* pop return address */
|
||||||
"cmovbl %esi,%esp\n\t"
|
"cmpl %esp,%eax\n\t"
|
||||||
"pushl 20(%ebx)\n\t" /* func */
|
"cmovbl %eax,%esp\n\t"
|
||||||
"pushl 16(%ebx)\n\t" /* arg2 */
|
"pushl 16(%ebp)\n\t" /* func */
|
||||||
"pushl 12(%ebx)\n\t" /* arg1 */
|
"pushl 12(%ebp)\n\t" /* arg2 */
|
||||||
"movl 8(%ebx),%ebx\n\t" /* ctx */
|
"pushl 8(%ebp)\n\t" /* arg1 */
|
||||||
"movl $0x00010007,(%esi)\n\t" /* context.ContextFlags = CONTEXT_FULL */
|
"pushl 4(%ebp)\n\t" /* ctx */
|
||||||
"pushl %esi\n\t" /* context */
|
"pushl %eax\n\t"
|
||||||
"pushl $0xfffffffe\n\t"
|
"pushl %esi\n\t"
|
||||||
"call " __ASM_STDCALL("NtGetContextThread",8) "\n\t"
|
"call " __ASM_STDCALL("setup_user_apc_dispatcher_stack",24) "\n\t"
|
||||||
"movl $0xc0,0xb0(%esi)\n" /* context.Eax = STATUS_USER_APC */
|
|
||||||
"popl %edx\n\t"
|
|
||||||
"popl %ecx\n\t"
|
|
||||||
"popl %eax\n\t"
|
|
||||||
"leal -20(%esi),%esp\n\t"
|
|
||||||
"movl %eax,16(%esp)\n" /* func */
|
|
||||||
"2:\tmovl %ecx,12(%esp)\n\t" /* arg2 */
|
|
||||||
"movl %edx,8(%esp)\n\t" /* arg1 */
|
|
||||||
"movl %ebx,4(%esp)\n\t" /* ctx */
|
|
||||||
"movl %esi,(%esp)\n\t" /* context */
|
|
||||||
"movl $0,%fs:0x1f8\n\t" /* x86_thread_data()->syscall_frame = NULL */
|
"movl $0,%fs:0x1f8\n\t" /* x86_thread_data()->syscall_frame = NULL */
|
||||||
|
"movl %eax,%esp\n\t"
|
||||||
|
"leal 20(%eax),%esi\n\t"
|
||||||
"movl 0xb4(%esi),%ebp\n\t" /* context.Ebp */
|
"movl 0xb4(%esi),%ebp\n\t" /* context.Ebp */
|
||||||
"pushl 0xb8(%esi)\n\t" /* context.Eip */
|
"pushl 0xb8(%esi)\n\t" /* context.Eip */
|
||||||
"jmp *%edi\n" )
|
"jmp *%edi\n" )
|
||||||
|
|
Loading…
Reference in New Issue