[PATCH 2/2] winedbg: Add support for x86_64 indirect function call targets.

Conor McCarthy cmccarthy at codeweavers.com
Fri Nov 22 09:15:56 CST 2019


I have tested this with all address types that will be seen in the wild.

Signed-off-by: Conor McCarthy <cmccarthy at codeweavers.com>
---
 programs/winedbg/be_x86_64.c | 95 +++++++++++++++++++++++++++++++++---
 1 file changed, 89 insertions(+), 6 deletions(-)

diff --git a/programs/winedbg/be_x86_64.c b/programs/winedbg/be_x86_64.c
index 5b95cefa..83cbb3c0 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);
-- 
2.24.0




More information about the wine-devel mailing list