Rafał Harabień : ntdll: Allow getting/setting x86_64 context of x86 processes in wine64.
Alexandre Julliard
julliard at winehq.org
Tue Mar 9 14:55:19 CST 2021
Module: wine
Branch: master
Commit: 77481d36d3a9ce87a213424aef65ad094b42b022
URL: https://source.winehq.org/git/wine.git/?a=commit;h=77481d36d3a9ce87a213424aef65ad094b42b022
Author: Rafał Harabień <rafalh92 at outlook.com>
Date: Mon Mar 1 00:42:28 2021 +0100
ntdll: Allow getting/setting x86_64 context of x86 processes in wine64.
WoW64 process has two separate contexts:
- x86 context used most of the time (e.g. by application code)
- x86_64 context used by system when it quits x86 emulation and jumps to
the kernel code
A notable exception are debug registers - their state is shared. Some
debuggers make use of that fact and sets/gets debug registers of x86
processes using x86_64 thread context.
Add support for setting and getting debug registers using x86_64
thread context. Getting other registers is allowed too and will return
values from x86 thread context.
Fixes hardware breakpoints in IDA 7.0 disassembler (x86_64 app) when
debugging x86 (32 bit) applications.
Signed-off-by: Rafał Harabień <rafalh92 at outlook.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/ntdll/tests/exception.c | 9 -------
dlls/ntdll/unix/signal_x86_64.c | 59 +++++++++++++++++++++++++++++++++++++++++
server/thread.c | 22 +++++++++++++--
3 files changed, 79 insertions(+), 11 deletions(-)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c
index 75765bee5a0..da88ca449fb 100644
--- a/dlls/ntdll/tests/exception.c
+++ b/dlls/ntdll/tests/exception.c
@@ -5841,7 +5841,6 @@ static void test_debug_registers_wow64(void)
ZeroMemory(&ctx, sizeof(ctx));
ctx.ContextFlags = CONTEXT_ALL;
bret = GetThreadContext(pi.hThread, &ctx);
- todo_wine
ok(bret, "GetThreadContext failed\n");
ctx.Dr0 = 0x12340000;
@@ -5850,14 +5849,12 @@ static void test_debug_registers_wow64(void)
ctx.Dr3 = 0x12340003;
ctx.Dr7 = 0x155; /* enable all breakpoints (local) */
bret = SetThreadContext(pi.hThread, &ctx);
- todo_wine
ok(bret, "SetThreadContext failed\n");
if (bret) {
ZeroMemory(&ctx, sizeof(ctx));
ctx.ContextFlags = CONTEXT_ALL;
bret = GetThreadContext(pi.hThread, &ctx);
- todo_wine
ok(bret, "GetThreadContext failed\n");
if (bret)
{
@@ -5896,22 +5893,16 @@ static void test_debug_registers_wow64(void)
ok(ret == STATUS_SUCCESS, "Wow64GetThreadContext failed with %lx\n", ret);
if (ret == STATUS_SUCCESS)
{
- todo_wine
ok(wow64_ctx.Dr0 == 0x56780000, "expected 0x56780000, got %lx\n", wow64_ctx.Dr0);
- todo_wine
ok(wow64_ctx.Dr1 == 0x56780001, "expected 0x56780001, got %lx\n", wow64_ctx.Dr1);
- todo_wine
ok(wow64_ctx.Dr2 == 0x56780002, "expected 0x56780002, got %lx\n", wow64_ctx.Dr2);
- todo_wine
ok(wow64_ctx.Dr3 == 0x56780003, "expected 0x56780003, got %lx\n", wow64_ctx.Dr3);
- todo_wine
ok(wow64_ctx.Dr7 == 0x101, "expected 0x101, got %lx\n", wow64_ctx.Dr7);
}
ZeroMemory(&ctx, sizeof(ctx));
ctx.ContextFlags = CONTEXT_ALL;
bret = GetThreadContext(pi.hThread, &ctx);
- todo_wine
ok(bret, "GetThreadContext failed\n");
if (bret)
{
diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c
index 2a030372fb7..7dab5fbf4ed 100644
--- a/dlls/ntdll/unix/signal_x86_64.c
+++ b/dlls/ntdll/unix/signal_x86_64.c
@@ -1707,6 +1707,65 @@ NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
*/
NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
{
+ if (from->cpu == CPU_x86)
+ {
+ /* convert the WoW64 context */
+ to->ContextFlags = CONTEXT_AMD64;
+ if (from->flags & SERVER_CTX_CONTROL)
+ {
+ to->ContextFlags |= CONTEXT_CONTROL;
+ to->Rbp = from->ctl.i386_regs.ebp;
+ to->Rip = from->ctl.i386_regs.eip;
+ to->Rsp = from->ctl.i386_regs.esp;
+ 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 |= CONTEXT_INTEGER;
+ to->Rax = from->integer.i386_regs.eax;
+ to->Rcx = from->integer.i386_regs.ecx;
+ to->Rdx = from->integer.i386_regs.edx;
+ to->Rbx = from->integer.i386_regs.ebx;
+ to->Rsi = from->integer.i386_regs.esi;
+ to->Rdi = from->integer.i386_regs.edi;
+ to->R8 = 0;
+ to->R9 = 0;
+ to->R10 = 0;
+ to->R11 = 0;
+ to->R12 = 0;
+ to->R13 = 0;
+ to->R14 = 0;
+ to->R15 = 0;
+ }
+ if (from->flags & SERVER_CTX_SEGMENTS)
+ {
+ to->ContextFlags |= 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 |= CONTEXT_FLOATING_POINT;
+ memset(&to->u.FltSave, 0, sizeof(to->u.FltSave));
+ }
+ if (from->flags & SERVER_CTX_DEBUG_REGISTERS)
+ {
+ to->ContextFlags |= 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;
+ }
+ return STATUS_SUCCESS;
+ }
+
if (from->cpu != CPU_x86_64) return STATUS_INVALID_PARAMETER;
to->ContextFlags = CONTEXT_AMD64 | (to->ContextFlags & 0x40);
diff --git a/server/thread.c b/server/thread.c
index dc02a1a9de3..e4abe4fab94 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -1890,8 +1890,7 @@ DECL_HANDLER(set_thread_context)
reply->self = (thread == current);
if (thread->state == TERMINATED) set_error( STATUS_UNSUCCESSFUL );
- else if (context->cpu != thread->process->cpu) set_error( STATUS_INVALID_PARAMETER );
- else
+ else if (context->cpu == thread->process->cpu)
{
unsigned int system_flags = get_context_system_regs(context->cpu) & context->flags;
@@ -1903,6 +1902,25 @@ DECL_HANDLER(set_thread_context)
thread->context->regs.flags |= context->flags;
}
}
+ else if (context->cpu == CPU_x86_64 && thread->process->cpu == CPU_x86)
+ {
+ /* convert the WoW64 context */
+ unsigned int system_flags = get_context_system_regs( context->cpu ) & context->flags;
+ if (system_flags)
+ {
+ set_thread_context( thread, context, system_flags );
+ if (thread->context && !get_error())
+ {
+ thread->context->regs.debug.i386_regs.dr0 = context->debug.x86_64_regs.dr0;
+ thread->context->regs.debug.i386_regs.dr1 = context->debug.x86_64_regs.dr1;
+ thread->context->regs.debug.i386_regs.dr2 = context->debug.x86_64_regs.dr2;
+ thread->context->regs.debug.i386_regs.dr3 = context->debug.x86_64_regs.dr3;
+ thread->context->regs.debug.i386_regs.dr6 = context->debug.x86_64_regs.dr6;
+ thread->context->regs.debug.i386_regs.dr7 = context->debug.x86_64_regs.dr7;
+ }
+ }
+ }
+ else set_error( STATUS_INVALID_PARAMETER );
release_object( thread );
}
More information about the wine-cvs
mailing list