[PATCH] [WineDbg]: i386 func call
Eric Pouech
eric.pouech at wanadoo.fr
Sat Oct 21 02:40:11 CDT 2006
- added a few more cases where we inspect if i386 insn:s are
actually calls
(based on previous work by Jeff L <lats at yless4u.com.au>)
A+
---
programs/winedbg/be_i386.c | 155 ++++++++++++++++++++++++++++++++++++++++----
1 files changed, 141 insertions(+), 14 deletions(-)
diff --git a/programs/winedbg/be_i386.c b/programs/winedbg/be_i386.c
index 696e125..b8b08a4 100644
--- a/programs/winedbg/be_i386.c
+++ b/programs/winedbg/be_i386.c
@@ -379,30 +379,157 @@ static unsigned be_i386_is_break_insn(co
return c == 0xCC;
}
+static unsigned get_size(ADDRESS_MODE am)
+{
+ if (am == AddrModeReal || am == AddrMode1616) return 16;
+ return 32;
+}
+
+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_i386_is_func_call(const void* insn, ADDRESS64* callee)
{
- BYTE ch;
- int delta;
+ BYTE ch;
+ int delta;
+ short segment;
+ unsigned dst;
+ unsigned operand_size;
+ ADDRESS_MODE cs_addr_mode;
+
+ cs_addr_mode = get_selector_type(dbg_curr_thread->handle, &dbg_context,
+ dbg_context.SegCs);
+ operand_size = get_size(cs_addr_mode);
+
+ /* get operand_size (also getting rid of the various prefixes */
+ do
+ {
+ if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
+ if (ch == 0x66)
+ {
+ operand_size = 48 - operand_size; /* 16 => 32, 32 => 16 */
+ insn = (const char*)insn + 1;
+ }
+ } while (ch == 0x66 || ch == 0x67);
- if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
switch (ch)
{
- case 0xe8:
- dbg_read_memory((const char*)insn + 1, &delta, sizeof(delta));
-
- callee->Mode = AddrModeFlat;
- callee->Offset = (DWORD)insn;
- be_i386_disasm_one_insn(callee, FALSE);
- callee->Offset += delta;
+ case 0xe8: /* relative near call */
+ callee->Mode = cs_addr_mode;
+ if (!fetch_value((const char*)insn + 1, operand_size, &delta))
+ return FALSE;
+ callee->Segment = dbg_context.SegCs;
+ callee->Offset = (DWORD)insn + 1 + (operand_size / 8) + delta;
+ return TRUE;
+ case 0x9a: /* absolute far call */
+ if (!dbg_read_memory((const char*)insn + 1 + operand_size / 8,
+ &segment, sizeof(segment)))
+ return FALSE;
+ callee->Mode = get_selector_type(dbg_curr_thread->handle, &dbg_context,
+ segment);
+ if (!fetch_value((const char*)insn + 1, operand_size, &delta))
+ return FALSE;
+ callee->Segment = segment;
+ callee->Offset = delta;
return TRUE;
+
case 0xff:
if (!dbg_read_memory((const char*)insn + 1, &ch, sizeof(ch)))
return FALSE;
- ch &= 0x38;
- if (ch != 0x10 && ch != 0x18) return FALSE;
- /* fall through */
- case 0x9a:
+ /* keep only the CALL and LCALL insn:s */
+ switch ((ch >> 3) & 0x07)
+ {
+ case 0x02:
+ segment = dbg_context.SegCs;
+ break;
+ case 0x03:
+ if (!dbg_read_memory((const char*)insn + 1 + operand_size / 8,
+ &segment, sizeof(segment)))
+ return FALSE;
+ break;
+ default: return FALSE;
+ }
+ /* FIXME: we only support the 32 bit far calls for now */
+ if (operand_size != 32)
+ {
+ WINE_FIXME("Unsupported yet call insn (0xFF 0x%02x) with 16 bit operand-size at %p\n", ch, insn);
+ return FALSE;
+ }
+ 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 */
+ WINE_FIXME("Unsupported yet call insn (0xFF 0x%02x) (addr32) at %p\n", ch, insn);
+ return FALSE;
+ default:
+ switch (ch & 0x07)
+ {
+ case 0x00: dst = dbg_context.Eax; break;
+ case 0x01: dst = dbg_context.Ecx; break;
+ case 0x02: dst = dbg_context.Edx; break;
+ case 0x03: dst = dbg_context.Ebx; break;
+ case 0x04: dst = dbg_context.Esp; break;
+ case 0x05: dst = dbg_context.Ebp; break;
+ case 0x06: dst = dbg_context.Esi; break;
+ case 0x07: dst = dbg_context.Edi; break;
+ }
+ if ((ch >> 6) != 0x03) /* indirect address */
+ {
+ if (ch >> 6) /* we got a displacement */
+ {
+ if (!fetch_value((const char*)insn + 2, (ch >> 6) == 0x01 ? 8 : 32, &delta))
+ return FALSE;
+ dst += delta;
+ }
+ if (((ch >> 3) & 0x07) == 0x03) /* LCALL */
+ {
+ if (!dbg_read_memory((const char*)dst + operand_size, &segment, sizeof(segment)))
+ return FALSE;
+ }
+ else segment = dbg_context.SegCs;
+ if (!dbg_read_memory((const char*)dst, &delta, sizeof(delta)))
+ return FALSE;
+ callee->Mode = get_selector_type(dbg_curr_thread->handle, &dbg_context,
+ segment);
+ callee->Segment = segment;
+ callee->Offset = delta;
+ }
+ else
+ {
+ callee->Mode = cs_addr_mode;
+ callee->Segment = dbg_context.SegCs;
+ callee->Offset = dst;
+ }
+ }
+ return TRUE;
+
case 0xCD:
WINE_FIXME("Unsupported yet call insn (0x%02x) at %p\n", ch, insn);
/* fall through */
More information about the wine-patches
mailing list