diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 5a2e578f749..d493e4fb254 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -978,6 +978,7 @@ @ stdcall RtlWalkHeap(long ptr) @ stdcall RtlWow64EnableFsRedirection(long) @ stdcall RtlWow64EnableFsRedirectionEx(long ptr) +@ stdcall -arch=x86_64 RtlWow64GetThreadContext(long ptr) @ stub RtlWriteMemoryStream @ stdcall RtlWriteRegistryValue(long ptr ptr long ptr long) @ stub RtlZeroHeap diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c index 882ba1fdfe6..8d45ba8a699 100644 --- a/dlls/ntdll/signal_x86_64.c +++ b/dlls/ntdll/signal_x86_64.c @@ -2200,6 +2200,106 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) } +/*********************************************************************** + * wow64_get_server_context_flags + */ +static unsigned int wow64_get_server_context_flags( DWORD flags ) +{ + unsigned int ret = 0; + + flags &= ~WOW64_CONTEXT_i386; /* get rid of CPU id */ + if (flags & WOW64_CONTEXT_CONTROL) ret |= SERVER_CTX_CONTROL; + if (flags & WOW64_CONTEXT_INTEGER) ret |= SERVER_CTX_INTEGER; + if (flags & WOW64_CONTEXT_SEGMENTS) ret |= SERVER_CTX_SEGMENTS; + if (flags & WOW64_CONTEXT_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT; + if (flags & WOW64_CONTEXT_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS; + if (flags & WOW64_CONTEXT_EXTENDED_REGISTERS) ret |= SERVER_CTX_EXTENDED_REGISTERS; + return ret; +} + +/*********************************************************************** + * wow64_context_from_server + */ +static NTSTATUS wow64_context_from_server( WOW64_CONTEXT *to, const context_t *from ) +{ + if (from->cpu != CPU_x86) return STATUS_INVALID_PARAMETER; + + to->ContextFlags = WOW64_CONTEXT_i386; + if (from->flags & SERVER_CTX_CONTROL) + { + to->ContextFlags |= WOW64_CONTEXT_CONTROL; + to->Ebp = from->ctl.i386_regs.ebp; + to->Esp = from->ctl.i386_regs.esp; + to->Eip = from->ctl.i386_regs.eip; + to->SegCs = from->ctl.i386_regs.cs; + to->SegSs = from->ctl.i386_regs.ss; + to->EFlags = from->ctl.i386_regs.eflags; + } + if (from->flags & SERVER_CTX_INTEGER) + { + to->ContextFlags |= WOW64_CONTEXT_INTEGER; + to->Eax = from->integer.i386_regs.eax; + to->Ebx = from->integer.i386_regs.ebx; + to->Ecx = from->integer.i386_regs.ecx; + to->Edx = from->integer.i386_regs.edx; + to->Esi = from->integer.i386_regs.esi; + to->Edi = from->integer.i386_regs.edi; + } + if (from->flags & SERVER_CTX_SEGMENTS) + { + to->ContextFlags |= WOW64_CONTEXT_SEGMENTS; + to->SegDs = from->seg.i386_regs.ds; + to->SegEs = from->seg.i386_regs.es; + to->SegFs = from->seg.i386_regs.fs; + to->SegGs = from->seg.i386_regs.gs; + } + if (from->flags & SERVER_CTX_FLOATING_POINT) + { + to->ContextFlags |= WOW64_CONTEXT_FLOATING_POINT; + to->FloatSave.ControlWord = from->fp.i386_regs.ctrl; + to->FloatSave.StatusWord = from->fp.i386_regs.status; + to->FloatSave.TagWord = from->fp.i386_regs.tag; + to->FloatSave.ErrorOffset = from->fp.i386_regs.err_off; + to->FloatSave.ErrorSelector = from->fp.i386_regs.err_sel; + to->FloatSave.DataOffset = from->fp.i386_regs.data_off; + to->FloatSave.DataSelector = from->fp.i386_regs.data_sel; + to->FloatSave.Cr0NpxState = from->fp.i386_regs.cr0npx; + memcpy( to->FloatSave.RegisterArea, from->fp.i386_regs.regs, sizeof(to->FloatSave.RegisterArea) ); + } + if (from->flags & SERVER_CTX_DEBUG_REGISTERS) + { + to->ContextFlags |= WOW64_CONTEXT_DEBUG_REGISTERS; + to->Dr0 = from->debug.i386_regs.dr0; + to->Dr1 = from->debug.i386_regs.dr1; + to->Dr2 = from->debug.i386_regs.dr2; + to->Dr3 = from->debug.i386_regs.dr3; + to->Dr6 = from->debug.i386_regs.dr6; + to->Dr7 = from->debug.i386_regs.dr7; + } + if (from->flags & SERVER_CTX_EXTENDED_REGISTERS) + { + to->ContextFlags |= WOW64_CONTEXT_EXTENDED_REGISTERS; + memcpy( to->ExtendedRegisters, from->ext.i386_regs, sizeof(to->ExtendedRegisters) ); + } + return STATUS_SUCCESS; +} + + +/****************************************************************************** + * RtlWow64GetThreadContext (NTDLL.@) + */ +NTSTATUS WINAPI RtlWow64GetThreadContext( HANDLE handle, WOW64_CONTEXT *context ) +{ + BOOL self; + NTSTATUS ret; + context_t server_context; + unsigned int server_flags = wow64_get_server_context_flags( context->ContextFlags ); + + if ((ret = get_thread_context( handle, &server_context, server_flags, &self ))) return ret; + if (self) return STATUS_INVALID_PARAMETER; + return wow64_context_from_server( context, &server_context ); +} + extern void raise_func_trampoline( EXCEPTION_RECORD *rec, CONTEXT *context, raise_func func ); __ASM_GLOBAL_FUNC( raise_func_trampoline, __ASM_CFI(".cfi_signal_frame\n\t") diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index c47c8cb6f93..9310297e8fa 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -149,6 +149,7 @@ static PRUNTIME_FUNCTION (WINAPI *pRtlLookupFunctionEntry)(ULONG64, ULONG64*, UN static EXCEPTION_DISPOSITION (WINAPI *p__C_specific_handler)(EXCEPTION_RECORD*, ULONG64, CONTEXT*, DISPATCHER_CONTEXT*); static VOID (WINAPI *pRtlCaptureContext)(CONTEXT*); static VOID (CDECL *pRtlRestoreContext)(CONTEXT*, EXCEPTION_RECORD*); +static NTSTATUS (WINAPI *pRtlWow64GetThreadContext)(HANDLE, WOW64_CONTEXT *); static VOID (CDECL *pRtlUnwindEx)(VOID*, VOID*, EXCEPTION_RECORD*, VOID*, CONTEXT*, UNWIND_HISTORY_TABLE*); static int (CDECL *p_setjmp)(_JUMP_BUFFER*); #endif @@ -2490,6 +2491,38 @@ static void test_dpe_exceptions(void) pRtlRemoveVectoredExceptionHandler(handler); } +static void test_wow64_context(void) +{ + char cmdline[] = "C:\\windows\\syswow64\\notepad.exe"; + PROCESS_INFORMATION pi; + STARTUPINFOA si = {0}; + WOW64_CONTEXT ctx; + NTSTATUS ret; + + memset(&ctx, 0x55, sizeof(ctx)); + ctx.ContextFlags = WOW64_CONTEXT_ALL; + ret = pRtlWow64GetThreadContext( GetCurrentThread(), &ctx ); + ok(ret == STATUS_INVALID_PARAMETER || broken(ret == STATUS_PARTIAL_COPY), "got %#x\n", ret); + + CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi); + + ret = pRtlWow64GetThreadContext( pi.hThread, &ctx ); + ok(ret == STATUS_SUCCESS, "got %#x\n", ret); + ok(ctx.ContextFlags == WOW64_CONTEXT_ALL, "got context flags %#x\n", ctx.ContextFlags); + ok(!ctx.Ebp, "got ebp %08x\n", ctx.Ebp); + ok(!ctx.Ecx, "got ecx %08x\n", ctx.Ecx); + ok(!ctx.Edx, "got edx %08x\n", ctx.Edx); + ok(!ctx.Esi, "got esi %08x\n", ctx.Esi); + ok(!ctx.Edi, "got edi %08x\n", ctx.Edi); + ok((ctx.EFlags & ~2) == 0x200, "got eflags %08x\n", ctx.EFlags); + ok((WORD) ctx.FloatSave.ControlWord == 0x27f, "got control word %08x\n", + ctx.FloatSave.ControlWord); + ok(*(WORD *)ctx.ExtendedRegisters == 0x27f, "got SSE control word %04x\n", + *(WORD *)ctx.ExtendedRegisters); + + pNtTerminateProcess(pi.hProcess, 0); +} + #endif /* __x86_64__ */ #if defined(__i386__) || defined(__x86_64__) @@ -3128,6 +3161,8 @@ START_TEST(exception) "RtlRestoreContext" ); pRtlUnwindEx = (void *)GetProcAddress( hntdll, "RtlUnwindEx" ); + pRtlWow64GetThreadContext = (void *)GetProcAddress( hntdll, + "RtlWow64GetThreadContext" ); p_setjmp = (void *)GetProcAddress( hmsvcrt, "_setjmp" ); @@ -3143,6 +3178,7 @@ START_TEST(exception) test_restore_context(); test_prot_fault(); test_dpe_exceptions(); + test_wow64_context(); if (pRtlAddFunctionTable && pRtlDeleteFunctionTable && pRtlInstallFunctionTableCallback && pRtlLookupFunctionEntry) test_dynamic_unwind();