mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-30 05:08:30 +00:00
ntdll: Call Wow64PrepareForException directly from KiUserExceptionDispatcher.
This requires moving the stack switch to Wow64PrepareForException. Based on a patch by Paul Gofman.
This commit is contained in:
parent
ae32b2f452
commit
334f54c255
|
@ -546,8 +546,6 @@ NTSTATUS WINAPI dispatch_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
|
|||
NTSTATUS status;
|
||||
DWORD c;
|
||||
|
||||
if (pWow64PrepareForException) pWow64PrepareForException( rec, context );
|
||||
|
||||
TRACE_(seh)( "code=%lx flags=%lx addr=%p ip=%Ix\n",
|
||||
rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, context->Rip );
|
||||
for (c = 0; c < min( EXCEPTION_MAXIMUM_PARAMETERS, rec->NumberParameters ); c++)
|
||||
|
@ -610,34 +608,20 @@ NTSTATUS WINAPI dispatch_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
|
|||
}
|
||||
|
||||
|
||||
NTSTATUS WINAPI dispatch_wow_exception( EXCEPTION_RECORD *rec_ptr, CONTEXT *context_ptr )
|
||||
{
|
||||
char buffer[sizeof(CONTEXT) + sizeof(CONTEXT_EX) + sizeof(XSTATE) + 128];
|
||||
CONTEXT *context;
|
||||
CONTEXT_EX *context_ex;
|
||||
EXCEPTION_RECORD rec = *rec_ptr;
|
||||
|
||||
RtlInitializeExtendedContext( buffer, context_ptr->ContextFlags, &context_ex );
|
||||
context = RtlLocateLegacyContext( context_ex, NULL );
|
||||
RtlCopyContext( context, context_ptr->ContextFlags, context_ptr );
|
||||
return dispatch_exception( &rec, context );
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* KiUserExceptionDispatcher (NTDLL.@)
|
||||
*/
|
||||
__ASM_GLOBAL_FUNC( KiUserExceptionDispatcher,
|
||||
"mov 0x98(%rsp),%rcx\n\t" /* context->Rsp */
|
||||
"movw %cs,%ax\n\t"
|
||||
"cmpw %ax,0x38(%rsp)\n\t" /* context->SegCs */
|
||||
"je 1f\n\t"
|
||||
"mov %rsp,%rdx\n\t" /* context */
|
||||
"lea 0x4f0(%rsp),%rcx\n\t" /* rec */
|
||||
"movq %r14,%rsp\n\t" /* switch to 64-bit stack */
|
||||
"call " __ASM_NAME("dispatch_wow_exception") "\n\t"
|
||||
"int3\n"
|
||||
"cld\n\t"
|
||||
/* some anticheats need this exact instruction here */
|
||||
"mov " __ASM_NAME("pWow64PrepareForException") "(%rip),%rax\n\t"
|
||||
"test %rax,%rax\n\t"
|
||||
"jz 1f\n\t"
|
||||
"mov %rsp,%rdx\n\t" /* context */
|
||||
"lea 0x4f0(%rsp),%rcx\n\t" /* rec */
|
||||
"call *%rax\n"
|
||||
"1:\tmov 0xf8(%rsp),%rdx\n\t" /* context->Rip */
|
||||
"mov 0x98(%rsp),%rcx\n\t" /* context->Rsp */
|
||||
"mov %rdx,-0x8(%rcx)\n\t"
|
||||
"mov %rbp,-0x10(%rcx)\n\t"
|
||||
"mov %rdi,-0x18(%rcx)\n\t"
|
||||
|
|
|
@ -35,6 +35,7 @@ static NTSTATUS (WINAPI *pRtlWow64GetThreadContext)(HANDLE,WOW64_CONTEXT*);
|
|||
static NTSTATUS (WINAPI *pRtlWow64IsWowGuestMachineSupported)(USHORT,BOOLEAN*);
|
||||
static NTSTATUS (WINAPI *pNtMapViewOfSectionEx)(HANDLE,HANDLE,PVOID*,const LARGE_INTEGER*,SIZE_T*,ULONG,ULONG,MEM_EXTENDED_PARAMETER*,ULONG);
|
||||
#ifdef _WIN64
|
||||
static NTSTATUS (WINAPI *pKiUserExceptionDispatcher)(EXCEPTION_RECORD*,CONTEXT*);
|
||||
static NTSTATUS (WINAPI *pRtlWow64GetCpuAreaInfo)(WOW64_CPURESERVED*,ULONG,WOW64_CPU_AREA_INFO*);
|
||||
static NTSTATUS (WINAPI *pRtlWow64GetThreadSelectorEntry)(HANDLE,THREAD_DESCRIPTOR_INFORMATION*,ULONG,ULONG*);
|
||||
static CROSS_PROCESS_WORK_ENTRY * (WINAPI *pRtlWow64PopAllCrossProcessWorkFromWorkList)(CROSS_PROCESS_WORK_HDR*,BOOLEAN*);
|
||||
|
@ -100,6 +101,7 @@ static void init(void)
|
|||
GET_PROC( RtlWow64GetThreadContext );
|
||||
GET_PROC( RtlWow64IsWowGuestMachineSupported );
|
||||
#ifdef _WIN64
|
||||
GET_PROC( KiUserExceptionDispatcher );
|
||||
GET_PROC( RtlWow64GetCpuAreaInfo );
|
||||
GET_PROC( RtlWow64GetThreadSelectorEntry );
|
||||
GET_PROC( RtlWow64PopAllCrossProcessWorkFromWorkList );
|
||||
|
@ -909,6 +911,7 @@ static void test_peb_teb(void)
|
|||
|
||||
static void test_selectors(void)
|
||||
{
|
||||
#ifndef __arm__
|
||||
THREAD_DESCRIPTOR_INFORMATION info;
|
||||
NTSTATUS status;
|
||||
ULONG base, limit, sel, retlen;
|
||||
|
@ -1043,6 +1046,7 @@ static void test_selectors(void)
|
|||
}
|
||||
}
|
||||
#undef GET_ENTRY
|
||||
#endif /* __arm__ */
|
||||
}
|
||||
|
||||
static void test_image_mappings(void)
|
||||
|
@ -1384,6 +1388,20 @@ static void test_cpu_area(void)
|
|||
else win_skip( "RtlWow64GetCpuAreaInfo not supported\n" );
|
||||
}
|
||||
|
||||
static void test_exception_dispatcher(void)
|
||||
{
|
||||
#ifdef __x86_64__
|
||||
BYTE *code = (BYTE *)pKiUserExceptionDispatcher;
|
||||
void **hook;
|
||||
|
||||
/* cld; mov xxx(%rip),%rax */
|
||||
ok( code[0] == 0xfc && code[1] == 0x48 && code[2] == 0x8b && code[3] == 0x05,
|
||||
"wrong opcodes %02x %02x %02x %02x\n", code[0], code[1], code[2], code[3] );
|
||||
hook = (void **)(code + 8 + *(int *)(code + 4));
|
||||
ok( !*hook, "hook %p set to %p\n", hook, *hook );
|
||||
#endif
|
||||
}
|
||||
|
||||
#else /* _WIN64 */
|
||||
|
||||
static const BYTE call_func64_code[] =
|
||||
|
@ -2122,6 +2140,40 @@ static void test_cpu_area(void)
|
|||
|
||||
}
|
||||
|
||||
static void test_exception_dispatcher(void)
|
||||
{
|
||||
ULONG64 ptr, hook_ptr, hook, expect, res;
|
||||
NTSTATUS status;
|
||||
BYTE code[8];
|
||||
|
||||
if (!is_wow64) return;
|
||||
if (!code_mem) return;
|
||||
if (!ntdll_module) return;
|
||||
|
||||
ptr = get_proc_address64( ntdll_module, "KiUserExceptionDispatcher" );
|
||||
ok( ptr, "KiUserExceptionDispatcher not found\n" );
|
||||
|
||||
if (pNtWow64ReadVirtualMemory64)
|
||||
{
|
||||
HANDLE process = OpenProcess( PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId() );
|
||||
|
||||
ok( process != 0, "failed to open current process %lu\n", GetLastError() );
|
||||
status = pNtWow64ReadVirtualMemory64( process, ptr, &code, sizeof(code), &res );
|
||||
ok( !status, "NtWow64ReadVirtualMemory64 failed %lx\n", status );
|
||||
|
||||
/* cld; mov xxx(%rip),%rax */
|
||||
ok( code[0] == 0xfc && code[1] == 0x48 && code[2] == 0x8b && code[3] == 0x05,
|
||||
"wrong opcodes %02x %02x %02x %02x\n", code[0], code[1], code[2], code[3] );
|
||||
hook_ptr = ptr + 8 + *(int *)(code + 4);
|
||||
status = pNtWow64ReadVirtualMemory64( process, hook_ptr, &hook, sizeof(hook), &res );
|
||||
ok( !status, "NtWow64ReadVirtualMemory64 failed %lx\n", status );
|
||||
|
||||
expect = get_proc_address64( wow64_module, "Wow64PrepareForException" );
|
||||
ok( hook == expect, "hook %I64x set to %I64x / %I64x\n", hook_ptr, hook, expect );
|
||||
NtClose( process );
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _WIN64 */
|
||||
|
||||
|
||||
|
@ -2142,4 +2194,5 @@ START_TEST(wow64)
|
|||
test_syscalls();
|
||||
#endif
|
||||
test_cpu_area();
|
||||
test_exception_dispatcher();
|
||||
}
|
||||
|
|
|
@ -101,7 +101,6 @@ static void (WINAPI *pBTCpuProcessInit)(void);
|
|||
static NTSTATUS (WINAPI *pBTCpuSetContext)(HANDLE,HANDLE,void *,void *);
|
||||
static void (WINAPI *pBTCpuThreadInit)(void);
|
||||
static void (WINAPI *pBTCpuSimulate)(void);
|
||||
static NTSTATUS (WINAPI *pBTCpuResetToConsistentState)( EXCEPTION_POINTERS * );
|
||||
static void * (WINAPI *p__wine_get_unix_opcode)(void);
|
||||
static void * (WINAPI *pKiRaiseUserExceptionDispatcher)(void);
|
||||
void (WINAPI *pBTCpuNotifyFlushInstructionCache2)( const void *, SIZE_T ) = NULL;
|
||||
|
@ -111,6 +110,7 @@ void (WINAPI *pBTCpuNotifyMemoryDirty)( void *, SIZE_T ) = NULL;
|
|||
void (WINAPI *pBTCpuNotifyMemoryFree)( void *, SIZE_T, ULONG ) = NULL;
|
||||
void (WINAPI *pBTCpuNotifyMemoryProtect)( void *, SIZE_T, ULONG ) = NULL;
|
||||
void (WINAPI *pBTCpuNotifyUnmapViewOfSection)( void * ) = NULL;
|
||||
NTSTATUS (WINAPI *pBTCpuResetToConsistentState)( EXCEPTION_POINTERS * ) = NULL;
|
||||
void (WINAPI *pBTCpuUpdateProcessorInformation)( SYSTEM_CPU_INFORMATION * ) = NULL;
|
||||
void (WINAPI *pBTCpuThreadTerm)( HANDLE ) = NULL;
|
||||
|
||||
|
@ -1154,12 +1154,45 @@ void WINAPI Wow64LdrpInitialize( CONTEXT *context )
|
|||
/**********************************************************************
|
||||
* Wow64PrepareForException (wow64.@)
|
||||
*/
|
||||
#ifdef __x86_64__
|
||||
__ASM_GLOBAL_FUNC( Wow64PrepareForException,
|
||||
"sub $0x38,%rsp\n\t"
|
||||
"mov %rcx,%r10\n\t" /* rec */
|
||||
"movw %cs,%ax\n\t"
|
||||
"cmpw %ax,0x38(%rdx)\n\t" /* context->SegCs */
|
||||
"je 1f\n\t" /* already in 64-bit mode? */
|
||||
/* copy arguments to 64-bit stack */
|
||||
"mov %rsp,%rsi\n\t"
|
||||
"mov 0x98(%rdx),%rcx\n\t" /* context->Rsp */
|
||||
"sub %rsi,%rcx\n\t" /* stack size */
|
||||
"sub %rcx,%r14\n\t" /* reserve same size on 64-bit stack */
|
||||
"and $~0x0f,%r14\n\t"
|
||||
"mov %r14,%rdi\n\t"
|
||||
"shr $3,%rcx\n\t"
|
||||
"rep; movsq\n\t"
|
||||
/* update arguments to point to the new stack */
|
||||
"mov %r14,%rax\n\t"
|
||||
"sub %rsp,%rax\n\t"
|
||||
"add %rax,%r10\n\t" /* rec */
|
||||
"add %rax,%rdx\n\t" /* context */
|
||||
/* switch to 64-bit stack */
|
||||
"mov %r14,%rsp\n"
|
||||
/* build EXCEPTION_POINTERS structure and call BTCpuResetToConsistentState */
|
||||
"1:\tlea 0x20(%rsp),%rcx\n\t" /* pointers */
|
||||
"mov %r10,(%rcx)\n\t" /* rec */
|
||||
"mov %rdx,8(%rcx)\n\t" /* context */
|
||||
"mov " __ASM_NAME("pBTCpuResetToConsistentState") "(%rip),%rax\n\t"
|
||||
"call *%rax\n\t"
|
||||
"add $0x38,%rsp\n\t"
|
||||
"ret" )
|
||||
#else
|
||||
void WINAPI Wow64PrepareForException( EXCEPTION_RECORD *rec, CONTEXT *context )
|
||||
{
|
||||
EXCEPTION_POINTERS ptrs = { rec, context };
|
||||
|
||||
pBTCpuResetToConsistentState( &ptrs );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
@ stub Wow64NotifyUnsimulateComplete
|
||||
@ stdcall Wow64PassExceptionToGuest(ptr)
|
||||
@ stub Wow64PrepareForDebuggerAttach
|
||||
@ stdcall Wow64PrepareForException(ptr ptr)
|
||||
@ stdcall -norelay Wow64PrepareForException(ptr ptr)
|
||||
@ stdcall Wow64ProcessPendingCrossProcessItems()
|
||||
@ stdcall Wow64RaiseException(long ptr)
|
||||
@ stub Wow64ShallowThunkAllocObjectAttributes32TO64_FNC
|
||||
|
|
Loading…
Reference in a new issue