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