Jeff L wrote:
Fixes some things Eric pointed out. Have not tested the far calls as I don't have anything that generates them.

This patch came about when I was looking at why single stepping seemed
to stuff up after a call.  It breaks down the calls for 32 bit mode
calls but not necessarily 16 and not 64 bit calls.  It is a fairly messy
area of knowledge and I could do with assistance as to how the 16/32/64
bit modes work.

Change log: Add code to analyse far calls in be_i386_is_func_call
instead of only near calls.

Jeff Latimer
a lot of things still look wrong to me...
- first of all, a lot of code should be factorized
- the callee should really be filled with the way the address of the call is stored in the insn (for example, you return a modeflat for a relative call from a 16 bit segment...)
- lots of computation for negative displacements are wrong
- segment is always expressed as an unsigned short (even in ADDRESS structure), so you shouldn't convert it to an int...
- ...

A+

Index: programs/winedbg/be_i386.c
===================================================================
RCS file: /home/wine/wine/programs/winedbg/be_i386.c,v
retrieving revision 1.6
diff -u -r1.6 be_i386.c
--- programs/winedbg/be_i386.c  21 Mar 2006 19:22:51 -0000      1.6
+++ programs/winedbg/be_i386.c  8 Apr 2006 14:30:45 -0000
@@ -380,28 +380,243 @@
static unsigned be_i386_is_func_call(const void* insn, ADDRESS* callee)
 {
+#define        f_mod(byte)     ((byte)>>6)
+#define        f_reg(byte)     (((byte)>>3)&0x7)
+#define        f_rm(byte)      ((byte)&0x7)
     BYTE        ch;
-    int         delta;
+    BYTE        mod, reg, rm;
+    BYTE        delta8;
+    short       delta16;
+    int         delta = 0;
+ int segment = 0; + unsigned short segment16; if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
     switch (ch)
     {
-    case 0xe8:
-       dbg_read_memory((const char*)insn + 1, &delta, sizeof(delta));
-       
+    case 0xe8:                            /* Call near, relative to next 
instruction */
+ callee->Mode = get_selector_type(dbg_curr_thread->handle, &dbg_context, dbg_context.SegCs); + if (callee->Mode == AddrMode1616) {
+            if (!dbg_read_memory((const char*)insn + 1, &delta16, 
sizeof(delta16)))
+                return FALSE;
+            delta = delta16;              /* Align to 32 bits */
+            delta &= 0xffff;
in this case, the callee should be kept as AddrMode1616, not in flat mode.
you shouldn't either crop delta to a 16 bit value, especially it's wrong when delta is negative
+        } else {
+            if (!dbg_read_memory((const char*)insn + 1, &delta, sizeof(delta)))
+                return FALSE;
+        }
         callee->Mode = AddrModeFlat;
         callee->Offset = (DWORD)insn;
-       be_i386_disasm_one_insn(callee, FALSE);
+        be_i386_disasm_one_insn(callee, FALSE);
         callee->Offset += delta;
return TRUE;
-    case 0xff:
+
+    case 0xff:                            /* Call far, absolute address */
         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:
+        rm  = f_rm(ch);                   /* Extract ModR/M byte        */
+        reg = f_reg(ch);
+        mod = f_mod(ch);
+        if (reg != 0x02 && reg != 0x03) return FALSE;
+        if (reg == 0x02) {                /* Same segment               */
+           switch(mod)
+           {
+              case 0x00:                  /* Register operand           */
+                callee->Mode = AddrModeFlat;
+                switch (rm)
+                {
+                  case 0x00:
+                    delta = dbg_context.Ebx + dbg_context.Esi;
+                    break;
+                  case 0x01:
+                    delta = dbg_context.Ebx + dbg_context.Edi;
+                    break;
+                  case 0x02:
+                    delta = dbg_context.Ebp + dbg_context.Esi;
+                    break;
+                  case 0x03:
+                    delta = dbg_context.Ebp + dbg_context.Edi;
+                    break;
+                  case 0x04:
+                    delta = dbg_context.Esi;
+                   break;
+                  case 0x05:
+                    delta = dbg_context.Edi;
+                    break;
+                  case 0x06:
+                    if (!dbg_read_memory((const char*)insn + 2, &delta, 
sizeof(2))) /* disp16 */
+                       return FALSE;
this is ugly. it'll work but, it would be cleaner to make it with reading delta16 (as a short), then cast the short to an int
+                    break;
+                  case 0x07:
+                    delta = dbg_context.Ebx;
+                    break;
+                }
+                break;
+              case 0x01:                  /* Disp8 operand              */
+                callee->Mode = AddrModeFlat;
+                if (!dbg_read_memory((const char*)insn + 2, &delta8, 
sizeof(delta8)))
+                    return FALSE;
+                delta = delta8;
+                switch (rm)
+                {
+                  case 0x00:
+                    delta += dbg_context.Ebx + dbg_context.Esi;
+                    break;
+                  case 0x01:
+                    delta += dbg_context.Ebx + dbg_context.Edi;
+                    break;
+                  case 0x02:
+                    delta += dbg_context.Ebp + dbg_context.Esi;
+                    break;
+                  case 0x03:
+                    delta += dbg_context.Ebp + dbg_context.Edi;
+                    break;
+                  case 0x04:
+                    delta += dbg_context.Esi;
+                   break;
+                  case 0x05:
+                    delta += dbg_context.Edi;
+                    break;
+                  case 0x06:
+                    delta += dbg_context.Ebp;
+                    break;
+                  case 0x07:
+                    delta += dbg_context.Ebx;
+                    break;
+                }
+                break;
+              case 0x02:                   /* Disp16 or Disp32 bit operand     
    */
+ callee->Mode = get_selector_type(dbg_curr_thread->handle, &dbg_context, dbg_context.SegCs); + if (callee->Mode == AddrMode1616) {
+                   if (!dbg_read_memory((const char*)insn + 2, &delta16, 
sizeof(delta16)))
+                       return FALSE;
+                   delta = delta16;        /* Align to 32 bits */
+                   delta &= 0xffff;
+                } else {
+                    if (!dbg_read_memory((const char*)insn + 2, &delta, 
sizeof(delta)))
+                        return FALSE;
+                }
+                callee->Mode = AddrModeFlat;
+                switch (rm)
+                {
+                  case 0x00:
+                    delta += dbg_context.Ebx + dbg_context.Esi;
+                    break;
+                  case 0x01:
+                    delta += dbg_context.Ebx + dbg_context.Edi;
+                    break;
+                  case 0x02:
+                    delta += dbg_context.Ebp + dbg_context.Esi;
+                    break;
+                  case 0x03:
+                    delta += dbg_context.Ebp + dbg_context.Edi;
+                    break;
+                  case 0x04:
+                    delta += dbg_context.Esi;
+                   break;
+                  case 0x05:
+                    delta += dbg_context.Edi;
+                    break;
+                  case 0x06:
+                    delta += dbg_context.Ebp;
+                    break;
+                  case 0x07:
+                    delta += dbg_context.Ebx;
+                    break;
+                }
+                break;
+              case 0x03:                  /* Register operand */
+                callee->Mode = AddrModeFlat;
+                switch (rm)
+                {
+                  case 0x00:
+                    delta = dbg_context.Eax;
+                    break;
+                  case 0x01:
+                    delta = dbg_context.Ecx;
+                    break;
+                  case 0x02:
+                    delta = dbg_context.Edx;
+                    break;
+                  case 0x03:
+                    delta = dbg_context.Ebx;
+                    break;
+                  case 0x04:
+                    delta = dbg_context.Esp;
+                   break;
+                  case 0x05:
+                    delta = dbg_context.Ebp;
+                    break;
+                  case 0x06:
+                    delta = dbg_context.Esi;
+                    break;
+                  case 0x07:
+                    delta = dbg_context.Edi;
+                    break;
+                }
+                break;
+              default:                    /* Disp32 bit operand         */
+                if (!dbg_read_memory((const char*)insn + 2, &delta, 
sizeof(delta)))
+                    return FALSE;
+                break;
+           }
+ + callee->Offset = delta;
+
+           return TRUE;
+ } + else if (reg == 0x03) /* Indirect Far call into other segment */
+        {
+           far char * faraddr;
you shouldn't need the far here (it brings nothing)
+           /* Extract the far address of the indirect address  */
+           if (dbg_read_memory((const char*)insn + 2, &faraddr, 
sizeof(faraddr)))
+               return FALSE;
+           /* Extract the far address of the callee            */
+           if (dbg_read_memory((const char*)faraddr + sizeof(delta), 
&segment16, sizeof(segment16)))
+               return FALSE;
+           segment = segment16;
+ callee->Mode = get_selector_type(dbg_curr_thread->handle, &dbg_context, (int) &segment); + if (callee->Mode == AddrMode1616) {
+               if (dbg_read_memory((const char*)faraddr, &delta16, 
sizeof(delta16)))
+                  return FALSE;
+              delta = delta16;            /* Align to 32 bits    */
+              delta &= 0xffff;
+           } else {
+               if (dbg_read_memory((const char*)faraddr, &delta, 
sizeof(delta)))
+                  return FALSE;
+           }
+           callee->Mode = AddrMode1632;   /* We have made a 32 address so say 
so */
+           callee->Segment = segment;
+           callee->Offset = delta;        /* absolute address not an offset */
+
+           return TRUE;
+        }
+ + WINE_FIXME("Unsupported yet call insn (0x%02x) at %p\n", ch, insn); + return FALSE; + + case 0x9a: /* Call far, absolute address in operand */
+        if (dbg_read_memory((const char*)insn + 1 + sizeof(delta), &segment16, 
sizeof(segment16)))
+            return FALSE;
+        segment = segment16;
+ callee->Mode = get_selector_type(dbg_curr_thread->handle, &dbg_context, dbg_context.SegCs); + if (callee->Mode == AddrMode1616) {
+            if (!dbg_read_memory((const char*)insn + 1, &delta16, 
sizeof(delta16)))
+                return FALSE;
+            delta = delta16;              /* Align to 32 bits */
+            delta &= 0xffff;
+        } else {
+            if (!dbg_read_memory((const char*)insn + 1, &delta, sizeof(delta)))
+                return FALSE;
+        }
+       
+        callee->Mode = AddrMode1632;     /* We have made a 32 address so say 
so */
+        callee->Segment = segment;
+        callee->Offset = delta;          /* absolute address not an offset */
+
+        return TRUE;
+
     case 0xCD:
         WINE_FIXME("Unsupported yet call insn (0x%02x) at %p\n", ch, insn);
         /* fall through */


------------------------------------------------------------------------




--
Eric Pouech



Reply via email to