diff --git a/programs/winedbg/be_x86_64.c b/programs/winedbg/be_x86_64.c index 5b95cefa366..83cbb3c05ce 100644 --- a/programs/winedbg/be_x86_64.c +++ b/programs/winedbg/be_x86_64.c @@ -269,6 +269,9 @@ static struct dbg_internal_var be_x86_64_ctx[] = #define f_mod(b) ((b)>>6) #define f_reg(b) (((b)>>3)&0x7) #define f_rm(b) ((b)&0x7) +#define f_sib_b(b) ((b)&0x7) +#define f_sib_i(b) (((b)>>3)&0x7) +#define f_sib_s(b) ((b)>>6) static BOOL be_x86_64_is_step_over_insn(const void* insn) { @@ -371,6 +374,81 @@ static BOOL fetch_value(const char* addr, unsigned sz, int* value) return TRUE; } +static BOOL add_fixed_displacement(const void* insn, BYTE mod, DWORD64* addr) +{ + LONG delta = 0; + + if (mod == 1) + { + if (!fetch_value(insn, 1, &delta)) + return FALSE; + } + else if (mod == 2) + { + if (!fetch_value(insn, sizeof(delta), &delta)) + return FALSE; + } + *addr += delta; + return TRUE; +} + +static BOOL evaluate_sib_address(const void* insn, BYTE mod, DWORD64* addr) +{ + BYTE ch; + BYTE scale; + DWORD64 loc; + + if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE; + + switch (f_sib_b(ch)) + { + case 0x00: loc = dbg_context.ctx.Rax; break; + case 0x01: loc = dbg_context.ctx.Rcx; break; + case 0x02: loc = dbg_context.ctx.Rdx; break; + case 0x03: loc = dbg_context.ctx.Rbx; break; + case 0x04: loc = dbg_context.ctx.Rsp; break; + case 0x05: + loc = dbg_context.ctx.Rbp; + if (mod == 0) + { + loc = 0; + mod = 2; + } + break; + case 0x06: loc = dbg_context.ctx.Rsi; break; + case 0x07: loc = dbg_context.ctx.Rdi; break; + } + + scale = f_sib_s(ch); + switch (f_sib_i(ch)) + { + case 0x00: loc += dbg_context.ctx.Rax << scale; break; + case 0x01: loc += dbg_context.ctx.Rcx << scale; break; + case 0x02: loc += dbg_context.ctx.Rdx << scale; break; + case 0x03: loc += dbg_context.ctx.Rbx << scale; break; + case 0x04: break; + case 0x05: loc += dbg_context.ctx.Rbp << scale; break; + case 0x06: loc += dbg_context.ctx.Rsi << scale; break; + case 0x07: loc += dbg_context.ctx.Rdi << scale; break; + } + + if (!add_fixed_displacement((const char*)insn + 1, mod, &loc)) + return FALSE; + + *addr = loc; + return TRUE; +} + +static BOOL load_indirect_target(DWORD64* dst) +{ + ADDRESS64 addr; + + addr.Mode = AddrModeFlat; + addr.Segment = dbg_context.ctx.SegDs; + addr.Offset = *dst; + return dbg_read_memory(memory_to_linear_addr(&addr), &dst, sizeof(dst)); +} + static BOOL be_x86_64_is_func_call(const void* insn, ADDRESS64* callee) { BYTE ch; @@ -418,8 +496,12 @@ static BOOL be_x86_64_is_func_call(const void* insn, ADDRESS64* callee) case 0x04: case 0x44: case 0x84: - WINE_FIXME("Unsupported yet call insn (0xFF 0x%02x) (SIB bytes) at %p\n", ch, insn); - return FALSE; + { + evaluate_sib_address((const char*)insn + 2, f_mod(ch), &dst); + if (!load_indirect_target(&dst)) return FALSE; + callee->Offset = dst; + return TRUE; + } case 0x05: /* addr32 */ if (f_reg(ch) == 0x2) { @@ -446,12 +528,13 @@ static BOOL be_x86_64_is_func_call(const void* insn, ADDRESS64* callee) case 0x07: dst = dbg_context.ctx.Rdi; break; } if (f_mod(ch) != 0x03) - WINE_FIXME("Unsupported yet call insn (0xFF 0x%02x) at %p\n", ch, insn); - else { - callee->Offset = dst; + if (!add_fixed_displacement((const char*)insn + 2, f_mod(ch), &dst)) + return FALSE; + if (!load_indirect_target(&dst)) return FALSE; } - break; + callee->Offset = dst; + return TRUE; } else WINE_FIXME("Unsupported yet call insn (rex=0x%02x 0xFF 0x%02x) at %p\n", rex, ch, insn);