Module: wine Branch: master Commit: e5e857c290352f41ce48935c3925aba68e87e873 URL: https://source.winehq.org/git/wine.git/?a=commit;h=e5e857c290352f41ce48935c3...
Author: Alexandre Julliard julliard@winehq.org Date: Wed Dec 1 11:27:51 2021 +0100
ntdll: Add support for dispatching exception from 32-bit code in Wow64 mode.
Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/ntdll/loader.c | 3 +++ dlls/ntdll/ntdll_misc.h | 1 + dlls/ntdll/signal_x86_64.c | 25 ++++++++++++++++++++++++- dlls/ntdll/unix/signal_x86_64.c | 1 + 4 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 3cc522af4d8..86aec79dbfc 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -3855,6 +3855,8 @@ static void load_global_options(void)
static void (WINAPI *pWow64LdrpInitialize)( CONTEXT *ctx );
+void (WINAPI *pWow64PrepareForException)( EXCEPTION_RECORD *rec, CONTEXT *context ) = NULL; + static void init_wow64( CONTEXT *context ) { if (!imports_fixup_done) @@ -3874,6 +3876,7 @@ static void init_wow64( CONTEXT *context ) if (!(p ## name = RtlFindExportedRoutineByName( wow64, #name ))) ERR( "failed to load %s\n", #name )
GET_PTR( Wow64LdrpInitialize ); + GET_PTR( Wow64PrepareForException ); #undef GET_PTR imports_fixup_done = TRUE; } diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index 34af6b780cf..d7c5ade5bc1 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -52,6 +52,7 @@ extern void WINAPI LdrInitializeThunk(CONTEXT*,ULONG_PTR,ULONG_PTR,ULONG_PTR) DE extern NTSTATUS WINAPI KiUserExceptionDispatcher(EXCEPTION_RECORD*,CONTEXT*) DECLSPEC_HIDDEN; extern void WINAPI KiUserApcDispatcher(CONTEXT*,ULONG_PTR,ULONG_PTR,ULONG_PTR,PNTAPCFUNC) DECLSPEC_HIDDEN; extern void WINAPI KiUserCallbackDispatcher(ULONG,void*,ULONG) DECLSPEC_HIDDEN; +extern void (WINAPI *pWow64PrepareForException)( EXCEPTION_RECORD *rec, CONTEXT *context ) DECLSPEC_HIDDEN;
#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) extern RUNTIME_FUNCTION *lookup_function_info( ULONG_PTR pc, ULONG_PTR *base, LDR_DATA_TABLE_ENTRY **module ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c index ef32eba68b7..e0372b111fd 100644 --- a/dlls/ntdll/signal_x86_64.c +++ b/dlls/ntdll/signal_x86_64.c @@ -566,12 +566,35 @@ 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 ); + pWow64PrepareForException( &rec, context ); + return dispatch_exception( &rec, context ); +} + + /******************************************************************* * KiUserExceptionDispatcher (NTDLL.@) */ __ASM_GLOBAL_FUNC( KiUserExceptionDispatcher, "mov 0x98(%rsp),%rcx\n\t" /* context->Rsp */ - "mov 0xf8(%rsp),%rdx\n\t" /* context->Rip */ + "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" + "1:\tmov 0xf8(%rsp),%rdx\n\t" /* context->Rip */ "mov %rdx,-0x8(%rcx)\n\t" "mov %rbp,-0x10(%rcx)\n\t" "mov %rdi,-0x18(%rcx)\n\t" diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 0085bd42410..9972faf799c 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -2171,6 +2171,7 @@ static void setup_raise_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec } }
+ CS_sig(sigcontext) = cs64_sel; RIP_sig(sigcontext) = (ULONG_PTR)pKiUserExceptionDispatcher; RSP_sig(sigcontext) = (ULONG_PTR)stack; /* clear single-step, direction, and align check flag */