ntdll: Implement RtlWow64GetThreadContext().

Signed-off-by: Zebediah Figura <zfigura@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2018-06-06 13:30:17 -05:00 committed by Alexandre Julliard
parent 36371075f8
commit f135c81b31
3 changed files with 137 additions and 0 deletions

View File

@ -978,6 +978,7 @@
@ stdcall RtlWalkHeap(long ptr) @ stdcall RtlWalkHeap(long ptr)
@ stdcall RtlWow64EnableFsRedirection(long) @ stdcall RtlWow64EnableFsRedirection(long)
@ stdcall RtlWow64EnableFsRedirectionEx(long ptr) @ stdcall RtlWow64EnableFsRedirectionEx(long ptr)
@ stdcall -arch=x86_64 RtlWow64GetThreadContext(long ptr)
@ stub RtlWriteMemoryStream @ stub RtlWriteMemoryStream
@ stdcall RtlWriteRegistryValue(long ptr ptr long ptr long) @ stdcall RtlWriteRegistryValue(long ptr ptr long ptr long)
@ stub RtlZeroHeap @ stub RtlZeroHeap

View File

@ -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 ); extern void raise_func_trampoline( EXCEPTION_RECORD *rec, CONTEXT *context, raise_func func );
__ASM_GLOBAL_FUNC( raise_func_trampoline, __ASM_GLOBAL_FUNC( raise_func_trampoline,
__ASM_CFI(".cfi_signal_frame\n\t") __ASM_CFI(".cfi_signal_frame\n\t")

View File

@ -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 EXCEPTION_DISPOSITION (WINAPI *p__C_specific_handler)(EXCEPTION_RECORD*, ULONG64, CONTEXT*, DISPATCHER_CONTEXT*);
static VOID (WINAPI *pRtlCaptureContext)(CONTEXT*); static VOID (WINAPI *pRtlCaptureContext)(CONTEXT*);
static VOID (CDECL *pRtlRestoreContext)(CONTEXT*, EXCEPTION_RECORD*); 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 VOID (CDECL *pRtlUnwindEx)(VOID*, VOID*, EXCEPTION_RECORD*, VOID*, CONTEXT*, UNWIND_HISTORY_TABLE*);
static int (CDECL *p_setjmp)(_JUMP_BUFFER*); static int (CDECL *p_setjmp)(_JUMP_BUFFER*);
#endif #endif
@ -2490,6 +2491,38 @@ static void test_dpe_exceptions(void)
pRtlRemoveVectoredExceptionHandler(handler); 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__ */ #endif /* __x86_64__ */
#if defined(__i386__) || defined(__x86_64__) #if defined(__i386__) || defined(__x86_64__)
@ -3128,6 +3161,8 @@ START_TEST(exception)
"RtlRestoreContext" ); "RtlRestoreContext" );
pRtlUnwindEx = (void *)GetProcAddress( hntdll, pRtlUnwindEx = (void *)GetProcAddress( hntdll,
"RtlUnwindEx" ); "RtlUnwindEx" );
pRtlWow64GetThreadContext = (void *)GetProcAddress( hntdll,
"RtlWow64GetThreadContext" );
p_setjmp = (void *)GetProcAddress( hmsvcrt, p_setjmp = (void *)GetProcAddress( hmsvcrt,
"_setjmp" ); "_setjmp" );
@ -3143,6 +3178,7 @@ START_TEST(exception)
test_restore_context(); test_restore_context();
test_prot_fault(); test_prot_fault();
test_dpe_exceptions(); test_dpe_exceptions();
test_wow64_context();
if (pRtlAddFunctionTable && pRtlDeleteFunctionTable && pRtlInstallFunctionTableCallback && pRtlLookupFunctionEntry) if (pRtlAddFunctionTable && pRtlDeleteFunctionTable && pRtlInstallFunctionTableCallback && pRtlLookupFunctionEntry)
test_dynamic_unwind(); test_dynamic_unwind();