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@outlook.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
bee9f0126f
commit
77481d36d3
|
@ -5841,7 +5841,6 @@ static void test_debug_registers_wow64(void)
|
||||||
ZeroMemory(&ctx, sizeof(ctx));
|
ZeroMemory(&ctx, sizeof(ctx));
|
||||||
ctx.ContextFlags = CONTEXT_ALL;
|
ctx.ContextFlags = CONTEXT_ALL;
|
||||||
bret = GetThreadContext(pi.hThread, &ctx);
|
bret = GetThreadContext(pi.hThread, &ctx);
|
||||||
todo_wine
|
|
||||||
ok(bret, "GetThreadContext failed\n");
|
ok(bret, "GetThreadContext failed\n");
|
||||||
|
|
||||||
ctx.Dr0 = 0x12340000;
|
ctx.Dr0 = 0x12340000;
|
||||||
|
@ -5850,14 +5849,12 @@ static void test_debug_registers_wow64(void)
|
||||||
ctx.Dr3 = 0x12340003;
|
ctx.Dr3 = 0x12340003;
|
||||||
ctx.Dr7 = 0x155; /* enable all breakpoints (local) */
|
ctx.Dr7 = 0x155; /* enable all breakpoints (local) */
|
||||||
bret = SetThreadContext(pi.hThread, &ctx);
|
bret = SetThreadContext(pi.hThread, &ctx);
|
||||||
todo_wine
|
|
||||||
ok(bret, "SetThreadContext failed\n");
|
ok(bret, "SetThreadContext failed\n");
|
||||||
|
|
||||||
if (bret) {
|
if (bret) {
|
||||||
ZeroMemory(&ctx, sizeof(ctx));
|
ZeroMemory(&ctx, sizeof(ctx));
|
||||||
ctx.ContextFlags = CONTEXT_ALL;
|
ctx.ContextFlags = CONTEXT_ALL;
|
||||||
bret = GetThreadContext(pi.hThread, &ctx);
|
bret = GetThreadContext(pi.hThread, &ctx);
|
||||||
todo_wine
|
|
||||||
ok(bret, "GetThreadContext failed\n");
|
ok(bret, "GetThreadContext failed\n");
|
||||||
if (bret)
|
if (bret)
|
||||||
{
|
{
|
||||||
|
@ -5896,22 +5893,16 @@ static void test_debug_registers_wow64(void)
|
||||||
ok(ret == STATUS_SUCCESS, "Wow64GetThreadContext failed with %lx\n", ret);
|
ok(ret == STATUS_SUCCESS, "Wow64GetThreadContext failed with %lx\n", ret);
|
||||||
if (ret == STATUS_SUCCESS)
|
if (ret == STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
todo_wine
|
|
||||||
ok(wow64_ctx.Dr0 == 0x56780000, "expected 0x56780000, got %lx\n", wow64_ctx.Dr0);
|
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);
|
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);
|
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);
|
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);
|
ok(wow64_ctx.Dr7 == 0x101, "expected 0x101, got %lx\n", wow64_ctx.Dr7);
|
||||||
}
|
}
|
||||||
|
|
||||||
ZeroMemory(&ctx, sizeof(ctx));
|
ZeroMemory(&ctx, sizeof(ctx));
|
||||||
ctx.ContextFlags = CONTEXT_ALL;
|
ctx.ContextFlags = CONTEXT_ALL;
|
||||||
bret = GetThreadContext(pi.hThread, &ctx);
|
bret = GetThreadContext(pi.hThread, &ctx);
|
||||||
todo_wine
|
|
||||||
ok(bret, "GetThreadContext failed\n");
|
ok(bret, "GetThreadContext failed\n");
|
||||||
if (bret)
|
if (bret)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1707,6 +1707,65 @@ NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
|
||||||
*/
|
*/
|
||||||
NTSTATUS context_from_server( CONTEXT *to, const context_t *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;
|
if (from->cpu != CPU_x86_64) return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
to->ContextFlags = CONTEXT_AMD64 | (to->ContextFlags & 0x40);
|
to->ContextFlags = CONTEXT_AMD64 | (to->ContextFlags & 0x40);
|
||||||
|
|
|
@ -1890,8 +1890,7 @@ DECL_HANDLER(set_thread_context)
|
||||||
reply->self = (thread == current);
|
reply->self = (thread == current);
|
||||||
|
|
||||||
if (thread->state == TERMINATED) set_error( STATUS_UNSUCCESSFUL );
|
if (thread->state == TERMINATED) set_error( STATUS_UNSUCCESSFUL );
|
||||||
else if (context->cpu != thread->process->cpu) set_error( STATUS_INVALID_PARAMETER );
|
else if (context->cpu == thread->process->cpu)
|
||||||
else
|
|
||||||
{
|
{
|
||||||
unsigned int system_flags = get_context_system_regs(context->cpu) & context->flags;
|
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;
|
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 );
|
release_object( thread );
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue