Eric Pouech : winedbg: Implement is_func_call on x86_64 CPU.
Alexandre Julliard
julliard at winehq.org
Thu Feb 4 11:11:01 CST 2010
Module: wine
Branch: master
Commit: b50e5719477ba95e39a8fdf88b647e2daee98049
URL: http://source.winehq.org/git/wine.git/?a=commit;h=b50e5719477ba95e39a8fdf88b647e2daee98049
Author: Eric Pouech <eric.pouech at orange.fr>
Date: Wed Feb 3 21:48:03 2010 +0100
winedbg: Implement is_func_call on x86_64 CPU.
---
programs/winedbg/be_x86_64.c | 117 +++++++++++++++++++++++++++++++++++++++++-
1 files changed, 115 insertions(+), 2 deletions(-)
diff --git a/programs/winedbg/be_x86_64.c b/programs/winedbg/be_x86_64.c
index a0e5637..682bd05 100644
--- a/programs/winedbg/be_x86_64.c
+++ b/programs/winedbg/be_x86_64.c
@@ -162,6 +162,10 @@ static const struct dbg_internal_var* be_x86_64_init_registers(CONTEXT* ctx)
return be_x86_64_ctx;
}
+#define f_mod(b) ((b)>>6)
+#define f_reg(b) (((b)>>3)&0x7)
+#define f_rm(b) ((b)&0x7)
+
static unsigned be_x86_64_is_step_over_insn(const void* insn)
{
BYTE ch;
@@ -233,10 +237,119 @@ static unsigned be_x86_64_is_break_insn(const void* insn)
return dbg_read_memory(insn, &c, sizeof(c)) && c == 0xCC;
}
+static BOOL fetch_value(const char* addr, unsigned sz, int* value)
+{
+ char value8;
+ short value16;
+
+ switch (sz)
+ {
+ case 8:
+ if (!dbg_read_memory(addr, &value8, sizeof(value8))) return FALSE;
+ *value = value8;
+ break;
+ case 16:
+ if (!dbg_read_memory(addr, &value16, sizeof(value16))) return FALSE;
+ *value = value16;
+ case 32:
+ if (!dbg_read_memory(addr, value, sizeof(*value))) return FALSE;
+ break;
+ default: return FALSE;
+ }
+ return TRUE;
+}
+
static unsigned be_x86_64_is_func_call(const void* insn, ADDRESS64* callee)
{
- dbg_printf("not done is_func_call\n");
- return FALSE;
+ BYTE ch;
+ LONG delta;
+ short segment;
+ unsigned op_size = 32, rex = 0;
+ DWORD64 dst;
+
+ /* we assume 64bit mode all over the place */
+ for (;;)
+ {
+ if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
+ if (ch == 0x66) op_size = 16;
+ else if (ch == 0x67) WINE_FIXME("prefix not supported %x\n", ch);
+ else if (ch >= 0x40 && ch <= 0x4f) rex = ch & 0xf;
+ else break;
+ insn = (const char*)insn + 1;
+ } while (0);
+
+ /* that's the only mode we support anyway */
+ callee->Mode = AddrModeFlat;
+ callee->Segment = dbg_context.SegCs;
+
+ switch (ch)
+ {
+ case 0xe8: /* relative near call */
+ assert(op_size == 32);
+ if (!fetch_value((const char*)insn + 1, sizeof(delta), &delta))
+ return FALSE;
+ callee->Offset = (DWORD_PTR)insn + 1 + 4 + delta;
+ return TRUE;
+
+ case 0xff:
+ if (!dbg_read_memory((const char*)insn + 1, &ch, sizeof(ch)))
+ return FALSE;
+ WINE_TRACE("Got 0xFF %x (&C7=%x) with rex=%x\n", ch, ch & 0xC7, rex);
+ /* keep only the CALL and LCALL insn:s */
+ switch (f_reg(ch))
+ {
+ case 0x02:
+ segment = dbg_context.SegCs;
+ break;
+ default: return FALSE;
+ }
+ if (rex == 0) switch (ch & 0xC7) /* keep Mod R/M only (skip reg) */
+ {
+ case 0x04:
+ case 0x44:
+ case 0x84:
+ WINE_FIXME("Unsupported yet call insn (0xFF 0x%02x) (SIB bytes) at %p\n", ch, insn);
+ return FALSE;
+ case 0x05: /* addr32 */
+ if (f_reg(ch) == 0x2)
+ {
+ /* rip-relative to next insn */
+ if (!dbg_read_memory((const char*)insn + 2, &delta, sizeof(delta)) ||
+ !dbg_read_memory((const char*)insn + 6 + delta, &dst, sizeof(dst)))
+ return FALSE;
+
+ callee->Offset = dst;
+ return TRUE;
+ }
+ WINE_FIXME("Unsupported yet call insn (0xFF 0x%02x) at %p\n", ch, insn);
+ return FALSE;
+ default:
+ switch (f_rm(ch))
+ {
+ case 0x00: dst = dbg_context.Rax; break;
+ case 0x01: dst = dbg_context.Rcx; break;
+ case 0x02: dst = dbg_context.Rdx; break;
+ case 0x03: dst = dbg_context.Rbx; break;
+ case 0x04: dst = dbg_context.Rsp; break;
+ case 0x05: dst = dbg_context.Rbp; break;
+ case 0x06: dst = dbg_context.Rsi; break;
+ case 0x07: dst = dbg_context.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;
+ }
+ break;
+ }
+ else
+ WINE_FIXME("Unsupported yet call insn (rex=0x%02x 0xFF 0x%02x) at %p\n", rex, ch, insn);
+ return FALSE;
+
+ default:
+ return FALSE;
+ }
}
extern void be_x86_64_disasm_one_insn(ADDRESS64* addr, int display);
More information about the wine-cvs
mailing list