ntdll: Fix KiUserExceptionDispatcher ABI on x86.
Signed-off-by: Paul Gofman <pgofman@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
dfa48037ec
commit
c198390c78
|
@ -198,7 +198,7 @@ static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
* KiUserExceptionDispatcher (NTDLL.@)
|
* KiUserExceptionDispatcher (NTDLL.@)
|
||||||
*/
|
*/
|
||||||
NTSTATUS WINAPI KiUserExceptionDispatcher( EXCEPTION_RECORD *rec, CONTEXT *context )
|
NTSTATUS WINAPI dispatch_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
|
||||||
{
|
{
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
DWORD c;
|
DWORD c;
|
||||||
|
@ -243,6 +243,11 @@ NTSTATUS WINAPI KiUserExceptionDispatcher( EXCEPTION_RECORD *rec, CONTEXT *conte
|
||||||
return NtRaiseException( rec, context, FALSE );
|
return NtRaiseException( rec, context, FALSE );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__ASM_STDCALL_FUNC( KiUserExceptionDispatcher, 8,
|
||||||
|
"pushl 4(%esp)\n\t"
|
||||||
|
"pushl 4(%esp)\n\t"
|
||||||
|
"call " __ASM_STDCALL("dispatch_exception", 8) "\n\t"
|
||||||
|
"int3" )
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* save_fpu
|
* save_fpu
|
||||||
|
|
|
@ -1660,6 +1660,114 @@ static void test_thread_context(void)
|
||||||
#undef COMPARE
|
#undef COMPARE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BYTE saved_KiUserExceptionDispatcher_bytes[7];
|
||||||
|
static void *pKiUserExceptionDispatcher;
|
||||||
|
static BOOL hook_called;
|
||||||
|
static void *hook_KiUserExceptionDispatcher_eip;
|
||||||
|
static void *dbg_except_continue_handler_eip;
|
||||||
|
static void *hook_exception_address;
|
||||||
|
|
||||||
|
static DWORD dbg_except_continue_handler(EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
|
||||||
|
CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher)
|
||||||
|
{
|
||||||
|
ok(hook_called, "Hook was not called.\n");
|
||||||
|
got_exception = 1;
|
||||||
|
dbg_except_continue_handler_eip = (void *)context->Eip;
|
||||||
|
++context->Eip;
|
||||||
|
return ExceptionContinueExecution;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use CDECL to leave arguments on stack. */
|
||||||
|
void CDECL hook_KiUserExceptionDispatcher(EXCEPTION_RECORD *rec, CONTEXT *context)
|
||||||
|
{
|
||||||
|
trace("rec %p, context %p.\n", rec, context);
|
||||||
|
trace("context->Eip %#x, context->Esp %#x, ContextFlags %#x.\n",
|
||||||
|
context->Eip, context->Esp, context->ContextFlags);
|
||||||
|
|
||||||
|
hook_called = TRUE;
|
||||||
|
/* Broken on Win2008, probably rec offset in stack is different. */
|
||||||
|
ok(rec->ExceptionCode == 0x80000003 || broken(!rec->ExceptionCode),
|
||||||
|
"Got unexpected ExceptionCode %#x.\n", rec->ExceptionCode);
|
||||||
|
|
||||||
|
hook_KiUserExceptionDispatcher_eip = (void *)context->Eip;
|
||||||
|
hook_exception_address = rec->ExceptionAddress;
|
||||||
|
memcpy(pKiUserExceptionDispatcher, saved_KiUserExceptionDispatcher_bytes,
|
||||||
|
sizeof(saved_KiUserExceptionDispatcher_bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_kiuserexceptiondispatcher(void)
|
||||||
|
{
|
||||||
|
HMODULE hntdll = GetModuleHandleA("ntdll.dll");
|
||||||
|
static const BYTE except_code[] =
|
||||||
|
{
|
||||||
|
0xcc, /* int3 */
|
||||||
|
0xc3, /* ret */
|
||||||
|
};
|
||||||
|
static BYTE hook_trampoline[] =
|
||||||
|
{
|
||||||
|
0xff, 0x15,
|
||||||
|
/* offset: 2 bytes */
|
||||||
|
0x00, 0x00, 0x00, 0x00, /* callq *addr */ /* call hook implementation. */
|
||||||
|
|
||||||
|
0xff, 0x25,
|
||||||
|
/* offset: 8 bytes */
|
||||||
|
0x00, 0x00, 0x00, 0x00, /* jmpq *addr */ /* jump to original function. */
|
||||||
|
};
|
||||||
|
void *phook_KiUserExceptionDispatcher = hook_KiUserExceptionDispatcher;
|
||||||
|
void *phook_trampoline = hook_trampoline;
|
||||||
|
DWORD old_protect1, old_protect2;
|
||||||
|
BYTE *ptr;
|
||||||
|
BOOL ret;
|
||||||
|
|
||||||
|
pKiUserExceptionDispatcher = (void *)GetProcAddress(hntdll, "KiUserExceptionDispatcher");
|
||||||
|
if (!pKiUserExceptionDispatcher)
|
||||||
|
{
|
||||||
|
win_skip("KiUserExceptionDispatcher is not available.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*(unsigned int *)(hook_trampoline + 2) = (ULONG_PTR)&phook_KiUserExceptionDispatcher;
|
||||||
|
*(unsigned int *)(hook_trampoline + 8) = (ULONG_PTR)&pKiUserExceptionDispatcher;
|
||||||
|
|
||||||
|
ret = VirtualProtect(hook_trampoline, ARRAY_SIZE(hook_trampoline), PAGE_EXECUTE_READWRITE, &old_protect1);
|
||||||
|
ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
|
||||||
|
|
||||||
|
ret = VirtualProtect(pKiUserExceptionDispatcher, sizeof(saved_KiUserExceptionDispatcher_bytes),
|
||||||
|
PAGE_EXECUTE_READWRITE, &old_protect2);
|
||||||
|
ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
|
||||||
|
|
||||||
|
memcpy(saved_KiUserExceptionDispatcher_bytes, pKiUserExceptionDispatcher,
|
||||||
|
sizeof(saved_KiUserExceptionDispatcher_bytes));
|
||||||
|
ptr = (BYTE *)pKiUserExceptionDispatcher;
|
||||||
|
/* mov hook_trampoline, %eax */
|
||||||
|
*ptr++ = 0xa1;
|
||||||
|
*(void **)ptr = &phook_trampoline;
|
||||||
|
ptr += sizeof(void *);
|
||||||
|
/* jmp *eax */
|
||||||
|
*ptr++ = 0xff;
|
||||||
|
*ptr++ = 0xe0;
|
||||||
|
|
||||||
|
got_exception = 0;
|
||||||
|
run_exception_test(dbg_except_continue_handler, NULL, except_code, ARRAY_SIZE(except_code),
|
||||||
|
PAGE_EXECUTE_READ);
|
||||||
|
ok(got_exception, "Handler was not called.\n");
|
||||||
|
ok(hook_called, "Hook was not called.\n");
|
||||||
|
|
||||||
|
ok(hook_exception_address == code_mem || broken(!hook_exception_address) /* Win2008 */,
|
||||||
|
"Got unexpected exception address %p, expected %p.\n",
|
||||||
|
hook_exception_address, code_mem);
|
||||||
|
todo_wine ok(hook_KiUserExceptionDispatcher_eip == code_mem, "Got unexpected exception address %p, expected %p.\n",
|
||||||
|
hook_KiUserExceptionDispatcher_eip, code_mem);
|
||||||
|
ok(dbg_except_continue_handler_eip == code_mem, "Got unexpected exception address %p, expected %p.\n",
|
||||||
|
dbg_except_continue_handler_eip, code_mem);
|
||||||
|
|
||||||
|
ret = VirtualProtect(pKiUserExceptionDispatcher, sizeof(saved_KiUserExceptionDispatcher_bytes),
|
||||||
|
old_protect2, &old_protect2);
|
||||||
|
ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
|
||||||
|
ret = VirtualProtect(hook_trampoline, ARRAY_SIZE(hook_trampoline), old_protect1, &old_protect1);
|
||||||
|
ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
#elif defined(__x86_64__)
|
#elif defined(__x86_64__)
|
||||||
|
|
||||||
#define is_wow64 0
|
#define is_wow64 0
|
||||||
|
@ -3707,6 +3815,7 @@ START_TEST(exception)
|
||||||
test_suspend_thread();
|
test_suspend_thread();
|
||||||
test_suspend_process();
|
test_suspend_process();
|
||||||
test_unload_trace();
|
test_unload_trace();
|
||||||
|
test_kiuserexceptiondispatcher();
|
||||||
|
|
||||||
/* Call of Duty WWII writes to BeingDebugged then closes an invalid handle,
|
/* Call of Duty WWII writes to BeingDebugged then closes an invalid handle,
|
||||||
* crashing the game if an exception is raised. */
|
* crashing the game if an exception is raised. */
|
||||||
|
|
|
@ -531,9 +531,10 @@ static EXCEPTION_RECORD *setup_exception( ucontext_t *sigcontext, raise_func fun
|
||||||
return &stack->rec;
|
return &stack->rec;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WINAPI call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context )
|
extern void WINAPI call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context,
|
||||||
|
NTSTATUS (WINAPI *dispatcher)(EXCEPTION_RECORD*,CONTEXT*) )
|
||||||
{
|
{
|
||||||
pKiUserExceptionDispatcher( rec, context );
|
dispatcher( rec, context );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
|
|
|
@ -602,9 +602,10 @@ static void setup_raise_exception( ucontext_t *sigcontext, struct stack_layout *
|
||||||
REGn_sig(18, sigcontext) = (ULONG_PTR)NtCurrentTeb();
|
REGn_sig(18, sigcontext) = (ULONG_PTR)NtCurrentTeb();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WINAPI call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context )
|
void WINAPI call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context,
|
||||||
|
NTSTATUS (WINAPI *dispatcher)(EXCEPTION_RECORD*,CONTEXT*) )
|
||||||
{
|
{
|
||||||
pKiUserExceptionDispatcher( rec, context );
|
dispatcher( rec, context );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
|
|
|
@ -428,7 +428,6 @@ static inline int set_thread_area( struct modify_ldt_s *ptr )
|
||||||
/* stack layout when calling an exception raise function */
|
/* stack layout when calling an exception raise function */
|
||||||
struct stack_layout
|
struct stack_layout
|
||||||
{
|
{
|
||||||
void *ret_addr; /* return address from raise_generic_exception */
|
|
||||||
EXCEPTION_RECORD *rec_ptr; /* first arg for raise_generic_exception */
|
EXCEPTION_RECORD *rec_ptr; /* first arg for raise_generic_exception */
|
||||||
CONTEXT *context_ptr; /* second arg for raise_generic_exception */
|
CONTEXT *context_ptr; /* second arg for raise_generic_exception */
|
||||||
CONTEXT context;
|
CONTEXT context;
|
||||||
|
@ -1583,15 +1582,13 @@ static void setup_raise_exception( ucontext_t *sigcontext, struct stack_layout *
|
||||||
FS_sig(sigcontext) = get_fs();
|
FS_sig(sigcontext) = get_fs();
|
||||||
GS_sig(sigcontext) = get_gs();
|
GS_sig(sigcontext) = get_gs();
|
||||||
SS_sig(sigcontext) = get_ds();
|
SS_sig(sigcontext) = get_ds();
|
||||||
stack->ret_addr = (void *)0xdeadbabe; /* KiUserExceptionDispatcher must not return */
|
|
||||||
stack->rec_ptr = &stack->rec; /* arguments for KiUserExceptionDispatcher */
|
stack->rec_ptr = &stack->rec; /* arguments for KiUserExceptionDispatcher */
|
||||||
stack->context_ptr = &stack->context;
|
stack->context_ptr = &stack->context;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WINAPI call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context )
|
__ASM_GLOBAL_FUNC( call_user_exception_dispatcher,
|
||||||
{
|
"add $4,%esp\n\t"
|
||||||
pKiUserExceptionDispatcher( rec, context );
|
"jmp *8(%esp)")
|
||||||
}
|
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* get_fpu_code
|
* get_fpu_code
|
||||||
|
|
|
@ -1977,20 +1977,21 @@ __ASM_GLOBAL_FUNC( user_exception_dispatcher_trampoline,
|
||||||
"movq 0xb0(%rsp),%rdi\n\t"
|
"movq 0xb0(%rsp),%rdi\n\t"
|
||||||
"jmpq *%rdx")
|
"jmpq *%rdx")
|
||||||
|
|
||||||
void WINAPI do_call_user_exception_dispatcher(EXCEPTION_RECORD *rec, CONTEXT *context, struct stack_layout *stack)
|
void WINAPI do_call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context,
|
||||||
|
NTSTATUS (WINAPI *dispatcher)(EXCEPTION_RECORD*,CONTEXT*),
|
||||||
|
struct stack_layout *stack )
|
||||||
{
|
{
|
||||||
memmove(&stack->context, context, sizeof(*context));
|
memmove(&stack->context, context, sizeof(*context));
|
||||||
memcpy(&stack->rec, rec, sizeof(*rec));
|
memcpy(&stack->rec, rec, sizeof(*rec));
|
||||||
|
user_exception_dispatcher_trampoline( stack, dispatcher );
|
||||||
user_exception_dispatcher_trampoline( stack, pKiUserExceptionDispatcher );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__ASM_GLOBAL_FUNC( call_user_exception_dispatcher,
|
__ASM_GLOBAL_FUNC( call_user_exception_dispatcher,
|
||||||
"movq 0x98(%rdx),%r8\n\t" /* context->Rsp */
|
"movq 0x98(%rdx),%r9\n\t" /* context->Rsp */
|
||||||
"andq $~0xf,%r8\n\t"
|
"andq $~0xf,%r9\n\t"
|
||||||
"subq $0x630,%r8\n\t" /* sizeof(struct stack_layout) */
|
"subq $0x630,%r9\n\t" /* sizeof(struct stack_layout) */
|
||||||
"cmpq %r8,%rsp\n\t"
|
"cmpq %r9,%rsp\n\t"
|
||||||
"cmovbq %r8,%rsp\n\t"
|
"cmovbq %r9,%rsp\n\t"
|
||||||
"jmp " __ASM_NAME("do_call_user_exception_dispatcher") "\n\t")
|
"jmp " __ASM_NAME("do_call_user_exception_dispatcher") "\n\t")
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
|
|
|
@ -415,7 +415,7 @@ NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL
|
||||||
if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
|
if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
|
||||||
NtSetContextThread( GetCurrentThread(), context );
|
NtSetContextThread( GetCurrentThread(), context );
|
||||||
|
|
||||||
if (first_chance) call_user_exception_dispatcher( rec, context );
|
if (first_chance) call_user_exception_dispatcher( rec, context, pKiUserExceptionDispatcher );
|
||||||
|
|
||||||
if (rec->ExceptionFlags & EH_STACK_INVALID)
|
if (rec->ExceptionFlags & EH_STACK_INVALID)
|
||||||
ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
|
ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
|
||||||
|
|
|
@ -242,7 +242,8 @@ extern void init_cpu_info(void) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
extern void dbg_init(void) DECLSPEC_HIDDEN;
|
extern void dbg_init(void) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
extern void WINAPI call_user_exception_dispatcher(EXCEPTION_RECORD *rec, CONTEXT *context) DECLSPEC_HIDDEN;
|
extern void WINAPI call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context,
|
||||||
|
NTSTATUS (WINAPI *dispatcher)(EXCEPTION_RECORD*,CONTEXT*) ) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
#define TICKSPERSEC 10000000
|
#define TICKSPERSEC 10000000
|
||||||
#define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)86400)
|
#define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)86400)
|
||||||
|
|
Loading…
Reference in New Issue