* disasm.h (gdb_disassembly): Add GDBARCH parameter.
[deliverable/binutils-gdb.git] / gdb / i386-tdep.c
index 47b87d69554f0d69e9204c62000a3d3350efe299..6b7560fa4ad851cb2341dad712007e6039c4bc2f 100644 (file)
@@ -1,14 +1,14 @@
 /* Intel 386 target-dependent stuff.
 
-   Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
-   1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software
-   Foundation, Inc.
+   Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   Free Software Foundation, Inc.
 
    This file is part of GDB.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
+#include "opcode/i386.h"
 #include "arch-utils.h"
 #include "command.h"
 #include "dummy-frame.h"
 #include "dwarf2-frame.h"
 #include "doublest.h"
-#include "floatformat.h"
 #include "frame.h"
 #include "frame-base.h"
 #include "frame-unwind.h"
 #include "inferior.h"
 #include "gdbcmd.h"
 #include "gdbcore.h"
+#include "gdbtypes.h"
 #include "objfiles.h"
 #include "osabi.h"
 #include "regcache.h"
@@ -51,6 +50,9 @@
 #include "i386-tdep.h"
 #include "i387-tdep.h"
 
+#include "record.h"
+#include <stdint.h>
+
 /* Register names.  */
 
 static char *i386_register_names[] =
@@ -98,16 +100,11 @@ i386_sse_regnum_p (struct gdbarch *gdbarch, int regnum)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-#define I387_ST0_REGNUM tdep->st0_regnum
-#define I387_NUM_XMM_REGS tdep->num_xmm_regs
-
-  if (I387_NUM_XMM_REGS == 0)
+  if (I387_NUM_XMM_REGS (tdep) == 0)
     return 0;
 
-  return (I387_XMM0_REGNUM <= regnum && regnum < I387_MXCSR_REGNUM);
-
-#undef I387_ST0_REGNUM
-#undef I387_NUM_XMM_REGS
+  return (I387_XMM0_REGNUM (tdep) <= regnum
+         && regnum < I387_MXCSR_REGNUM (tdep));
 }
 
 static int
@@ -115,49 +112,45 @@ i386_mxcsr_regnum_p (struct gdbarch *gdbarch, int regnum)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-#define I387_ST0_REGNUM tdep->st0_regnum
-#define I387_NUM_XMM_REGS tdep->num_xmm_regs
-
-  if (I387_NUM_XMM_REGS == 0)
+  if (I387_NUM_XMM_REGS (tdep) == 0)
     return 0;
 
-  return (regnum == I387_MXCSR_REGNUM);
-
-#undef I387_ST0_REGNUM
-#undef I387_NUM_XMM_REGS
+  return (regnum == I387_MXCSR_REGNUM (tdep));
 }
 
-#define I387_ST0_REGNUM (gdbarch_tdep (current_gdbarch)->st0_regnum)
-#define I387_MM0_REGNUM (gdbarch_tdep (current_gdbarch)->mm0_regnum)
-#define I387_NUM_XMM_REGS (gdbarch_tdep (current_gdbarch)->num_xmm_regs)
-
 /* FP register?  */
 
 int
-i386_fp_regnum_p (int regnum)
+i386_fp_regnum_p (struct gdbarch *gdbarch, int regnum)
 {
-  if (I387_ST0_REGNUM < 0)
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  if (I387_ST0_REGNUM (tdep) < 0)
     return 0;
 
-  return (I387_ST0_REGNUM <= regnum && regnum < I387_FCTRL_REGNUM);
+  return (I387_ST0_REGNUM (tdep) <= regnum
+         && regnum < I387_FCTRL_REGNUM (tdep));
 }
 
 int
-i386_fpc_regnum_p (int regnum)
+i386_fpc_regnum_p (struct gdbarch *gdbarch, int regnum)
 {
-  if (I387_ST0_REGNUM < 0)
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  if (I387_ST0_REGNUM (tdep) < 0)
     return 0;
 
-  return (I387_FCTRL_REGNUM <= regnum && regnum < I387_XMM0_REGNUM);
+  return (I387_FCTRL_REGNUM (tdep) <= regnum 
+         && regnum < I387_XMM0_REGNUM (tdep));
 }
 
 /* Return the name of register REGNUM.  */
 
 const char *
-i386_register_name (int regnum)
+i386_register_name (struct gdbarch *gdbarch, int regnum)
 {
-  if (i386_mmx_regnum_p (current_gdbarch, regnum))
-    return i386_mmx_names[regnum - I387_MM0_REGNUM];
+  if (i386_mmx_regnum_p (gdbarch, regnum))
+    return i386_mmx_names[regnum - I387_MM0_REGNUM (gdbarch_tdep (gdbarch))];
 
   if (regnum >= 0 && regnum < i386_num_register_names)
     return i386_register_names[regnum];
@@ -169,8 +162,10 @@ i386_register_name (int regnum)
    number used by GDB.  */
 
 static int
-i386_dbx_reg_to_regnum (int reg)
+i386_dbx_reg_to_regnum (struct gdbarch *gdbarch, int reg)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
   /* This implements what GCC calls the "default" register map
      (dbx_register_map[]).  */
 
@@ -187,29 +182,31 @@ i386_dbx_reg_to_regnum (int reg)
   else if (reg >= 12 && reg <= 19)
     {
       /* Floating-point registers.  */
-      return reg - 12 + I387_ST0_REGNUM;
+      return reg - 12 + I387_ST0_REGNUM (tdep);
     }
   else if (reg >= 21 && reg <= 28)
     {
       /* SSE registers.  */
-      return reg - 21 + I387_XMM0_REGNUM;
+      return reg - 21 + I387_XMM0_REGNUM (tdep);
     }
   else if (reg >= 29 && reg <= 36)
     {
       /* MMX registers.  */
-      return reg - 29 + I387_MM0_REGNUM;
+      return reg - 29 + I387_MM0_REGNUM (tdep);
     }
 
   /* This will hopefully provoke a warning.  */
-  return NUM_REGS + NUM_PSEUDO_REGS;
+  return gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
 }
 
 /* Convert SVR4 register number REG to the appropriate register number
    used by GDB.  */
 
 static int
-i386_svr4_reg_to_regnum (int reg)
+i386_svr4_reg_to_regnum (struct gdbarch *gdbarch, int reg)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
   /* This implements the GCC register map that tries to be compatible
      with the SVR4 C compiler for DWARF (svr4_dbx_register_map[]).  */
 
@@ -223,19 +220,19 @@ i386_svr4_reg_to_regnum (int reg)
   else if (reg >= 11 && reg <= 18)
     {
       /* Floating-point registers.  */
-      return reg - 11 + I387_ST0_REGNUM;
+      return reg - 11 + I387_ST0_REGNUM (tdep);
     }
   else if (reg >= 21 && reg <= 36)
     {
       /* The SSE and MMX registers have the same numbers as with dbx.  */
-      return i386_dbx_reg_to_regnum (reg);
+      return i386_dbx_reg_to_regnum (gdbarch, reg);
     }
 
   switch (reg)
     {
-    case 37: return I387_FCTRL_REGNUM;
-    case 38: return I387_FSTAT_REGNUM;
-    case 39: return I387_MXCSR_REGNUM;
+    case 37: return I387_FCTRL_REGNUM (tdep);
+    case 38: return I387_FSTAT_REGNUM (tdep);
+    case 39: return I387_MXCSR_REGNUM (tdep);
     case 40: return I386_ES_REGNUM;
     case 41: return I386_CS_REGNUM;
     case 42: return I386_SS_REGNUM;
@@ -245,12 +242,9 @@ i386_svr4_reg_to_regnum (int reg)
     }
 
   /* This will hopefully provoke a warning.  */
-  return NUM_REGS + NUM_PSEUDO_REGS;
+  return gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
 }
 
-#undef I387_ST0_REGNUM
-#undef I387_MM0_REGNUM
-#undef I387_NUM_XMM_REGS
 \f
 
 /* This is the variable that is set with "set disassembly-flavor", and
@@ -278,7 +272,7 @@ static const char *disassembly_flavor = att_flavor;
    This function is 64-bit safe.  */
 
 static const gdb_byte *
-i386_breakpoint_from_pc (CORE_ADDR *pc, int *len)
+i386_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pc, int *len)
 {
   static gdb_byte break_insn[] = { 0xcc }; /* int 3 */
 
@@ -286,6 +280,258 @@ i386_breakpoint_from_pc (CORE_ADDR *pc, int *len)
   return break_insn;
 }
 \f
+/* Displaced instruction handling.  */
+
+/* Skip the legacy instruction prefixes in INSN.
+   Not all prefixes are valid for any particular insn
+   but we needn't care, the insn will fault if it's invalid.
+   The result is a pointer to the first opcode byte,
+   or NULL if we run off the end of the buffer.  */
+
+static gdb_byte *
+i386_skip_prefixes (gdb_byte *insn, size_t max_len)
+{
+  gdb_byte *end = insn + max_len;
+
+  while (insn < end)
+    {
+      switch (*insn)
+       {
+       case DATA_PREFIX_OPCODE:
+       case ADDR_PREFIX_OPCODE:
+       case CS_PREFIX_OPCODE:
+       case DS_PREFIX_OPCODE:
+       case ES_PREFIX_OPCODE:
+       case FS_PREFIX_OPCODE:
+       case GS_PREFIX_OPCODE:
+       case SS_PREFIX_OPCODE:
+       case LOCK_PREFIX_OPCODE:
+       case REPE_PREFIX_OPCODE:
+       case REPNE_PREFIX_OPCODE:
+         ++insn;
+         continue;
+       default:
+         return insn;
+       }
+    }
+
+  return NULL;
+}
+
+static int
+i386_absolute_jmp_p (const gdb_byte *insn)
+{
+  /* jmp far (absolute address in operand) */
+  if (insn[0] == 0xea)
+    return 1;
+
+  if (insn[0] == 0xff)
+    {
+      /* jump near, absolute indirect (/4) */
+      if ((insn[1] & 0x38) == 0x20)
+        return 1;
+
+      /* jump far, absolute indirect (/5) */
+      if ((insn[1] & 0x38) == 0x28)
+        return 1;
+    }
+
+  return 0;
+}
+
+static int
+i386_absolute_call_p (const gdb_byte *insn)
+{
+  /* call far, absolute */
+  if (insn[0] == 0x9a)
+    return 1;
+
+  if (insn[0] == 0xff)
+    {
+      /* Call near, absolute indirect (/2) */
+      if ((insn[1] & 0x38) == 0x10)
+        return 1;
+
+      /* Call far, absolute indirect (/3) */
+      if ((insn[1] & 0x38) == 0x18)
+        return 1;
+    }
+
+  return 0;
+}
+
+static int
+i386_ret_p (const gdb_byte *insn)
+{
+  switch (insn[0])
+    {
+    case 0xc2: /* ret near, pop N bytes */
+    case 0xc3: /* ret near */
+    case 0xca: /* ret far, pop N bytes */
+    case 0xcb: /* ret far */
+    case 0xcf: /* iret */
+      return 1;
+
+    default:
+      return 0;
+    }
+}
+
+static int
+i386_call_p (const gdb_byte *insn)
+{
+  if (i386_absolute_call_p (insn))
+    return 1;
+
+  /* call near, relative */
+  if (insn[0] == 0xe8)
+    return 1;
+
+  return 0;
+}
+
+/* Return non-zero if INSN is a system call, and set *LENGTHP to its
+   length in bytes.  Otherwise, return zero.  */
+
+static int
+i386_syscall_p (const gdb_byte *insn, ULONGEST *lengthp)
+{
+  if (insn[0] == 0xcd)
+    {
+      *lengthp = 2;
+      return 1;
+    }
+
+  return 0;
+}
+
+/* Fix up the state of registers and memory after having single-stepped
+   a displaced instruction.  */
+
+void
+i386_displaced_step_fixup (struct gdbarch *gdbarch,
+                           struct displaced_step_closure *closure,
+                           CORE_ADDR from, CORE_ADDR to,
+                           struct regcache *regs)
+{
+  /* The offset we applied to the instruction's address.
+     This could well be negative (when viewed as a signed 32-bit
+     value), but ULONGEST won't reflect that, so take care when
+     applying it.  */
+  ULONGEST insn_offset = to - from;
+
+  /* Since we use simple_displaced_step_copy_insn, our closure is a
+     copy of the instruction.  */
+  gdb_byte *insn = (gdb_byte *) closure;
+  /* The start of the insn, needed in case we see some prefixes.  */
+  gdb_byte *insn_start = insn;
+
+  if (debug_displaced)
+    fprintf_unfiltered (gdb_stdlog,
+                        "displaced: fixup (0x%s, 0x%s), "
+                        "insn = 0x%02x 0x%02x ...\n",
+                        paddr_nz (from), paddr_nz (to), insn[0], insn[1]);
+
+  /* The list of issues to contend with here is taken from
+     resume_execution in arch/i386/kernel/kprobes.c, Linux 2.6.20.
+     Yay for Free Software!  */
+
+  /* Relocate the %eip, if necessary.  */
+
+  /* The instruction recognizers we use assume any leading prefixes
+     have been skipped.  */
+  {
+    /* This is the size of the buffer in closure.  */
+    size_t max_insn_len = gdbarch_max_insn_length (gdbarch);
+    gdb_byte *opcode = i386_skip_prefixes (insn, max_insn_len);
+    /* If there are too many prefixes, just ignore the insn.
+       It will fault when run.  */
+    if (opcode != NULL)
+      insn = opcode;
+  }
+
+  /* Except in the case of absolute or indirect jump or call
+     instructions, or a return instruction, the new eip is relative to
+     the displaced instruction; make it relative.  Well, signal
+     handler returns don't need relocation either, but we use the
+     value of %eip to recognize those; see below.  */
+  if (! i386_absolute_jmp_p (insn)
+      && ! i386_absolute_call_p (insn)
+      && ! i386_ret_p (insn))
+    {
+      ULONGEST orig_eip;
+      ULONGEST insn_len;
+
+      regcache_cooked_read_unsigned (regs, I386_EIP_REGNUM, &orig_eip);
+
+      /* A signal trampoline system call changes the %eip, resuming
+         execution of the main program after the signal handler has
+         returned.  That makes them like 'return' instructions; we
+         shouldn't relocate %eip.
+
+         But most system calls don't, and we do need to relocate %eip.
+
+         Our heuristic for distinguishing these cases: if stepping
+         over the system call instruction left control directly after
+         the instruction, the we relocate --- control almost certainly
+         doesn't belong in the displaced copy.  Otherwise, we assume
+         the instruction has put control where it belongs, and leave
+         it unrelocated.  Goodness help us if there are PC-relative
+         system calls.  */
+      if (i386_syscall_p (insn, &insn_len)
+          && orig_eip != to + (insn - insn_start) + insn_len)
+        {
+          if (debug_displaced)
+            fprintf_unfiltered (gdb_stdlog,
+                                "displaced: syscall changed %%eip; "
+                                "not relocating\n");
+        }
+      else
+        {
+          ULONGEST eip = (orig_eip - insn_offset) & 0xffffffffUL;
+
+         /* If we just stepped over a breakpoint insn, we don't backup
+            the pc on purpose; this is to match behaviour without
+            stepping.  */
+
+          regcache_cooked_write_unsigned (regs, I386_EIP_REGNUM, eip);
+
+          if (debug_displaced)
+            fprintf_unfiltered (gdb_stdlog,
+                                "displaced: "
+                                "relocated %%eip from 0x%s to 0x%s\n",
+                                paddr_nz (orig_eip), paddr_nz (eip));
+        }
+    }
+
+  /* If the instruction was PUSHFL, then the TF bit will be set in the
+     pushed value, and should be cleared.  We'll leave this for later,
+     since GDB already messes up the TF flag when stepping over a
+     pushfl.  */
+
+  /* If the instruction was a call, the return address now atop the
+     stack is the address following the copied instruction.  We need
+     to make it the address following the original instruction.  */
+  if (i386_call_p (insn))
+    {
+      ULONGEST esp;
+      ULONGEST retaddr;
+      const ULONGEST retaddr_len = 4;
+
+      regcache_cooked_read_unsigned (regs, I386_ESP_REGNUM, &esp);
+      retaddr = read_memory_unsigned_integer (esp, retaddr_len);
+      retaddr = (retaddr - insn_offset) & 0xffffffffUL;
+      write_memory_unsigned_integer (esp, retaddr_len, retaddr);
+
+      if (debug_displaced)
+        fprintf_unfiltered (gdb_stdlog,
+                            "displaced: relocated return addr at 0x%s "
+                            "to 0x%s\n",
+                            paddr_nz (esp),
+                            paddr_nz (retaddr));
+    }
+}
+\f
 #ifdef I386_REGNO_TO_SYMMETRY
 #error "The Sequent Symmetry is no longer supported."
 #endif
@@ -308,6 +554,7 @@ struct i386_frame_cache
   /* Saved registers.  */
   CORE_ADDR saved_regs[I386_NUM_SAVED_REGS];
   CORE_ADDR saved_sp;
+  int saved_sp_reg;
   int pc_in_eax;
 
   /* Stack space reserved for local variables.  */
@@ -334,6 +581,7 @@ i386_alloc_frame_cache (void)
   for (i = 0; i < I386_NUM_SAVED_REGS; i++)
     cache->saved_regs[i] = -1;
   cache->saved_sp = 0;
+  cache->saved_sp_reg = -1;
   cache->pc_in_eax = 0;
 
   /* Frameless until proven otherwise.  */
@@ -352,7 +600,7 @@ i386_follow_jump (CORE_ADDR pc)
   long delta = 0;
   int data16 = 0;
 
-  op = read_memory_unsigned_integer (pc, 1);
+  target_read_memory (pc, &op, 1);
   if (op == 0x66)
     {
       data16 = 1;
@@ -418,12 +666,12 @@ i386_analyze_struct_return (CORE_ADDR pc, CORE_ADDR current_pc,
   if (current_pc <= pc)
     return pc;
 
-  op = read_memory_unsigned_integer (pc, 1);
+  target_read_memory (pc, &op, 1);
 
   if (op != 0x58)              /* popl %eax */
     return pc;
 
-  read_memory (pc + 1, buf, 4);
+  target_read_memory (pc + 1, buf, 4);
   if (memcmp (buf, proto1, 3) != 0 && memcmp (buf, proto2, 4) != 0)
     return pc;
 
@@ -462,7 +710,7 @@ i386_skip_probe (CORE_ADDR pc)
   gdb_byte buf[8];
   gdb_byte op;
 
-  op = read_memory_unsigned_integer (pc, 1);
+  target_read_memory (pc, &op, 1);
 
   if (op == 0x68 || op == 0x6a)
     {
@@ -485,15 +733,132 @@ i386_skip_probe (CORE_ADDR pc)
   return pc;
 }
 
+/* GCC 4.1 and later, can put code in the prologue to realign the
+   stack pointer.  Check whether PC points to such code, and update
+   CACHE accordingly.  Return the first instruction after the code
+   sequence or CURRENT_PC, whichever is smaller.  If we don't
+   recognize the code, return PC.  */
+
+static CORE_ADDR
+i386_analyze_stack_align (CORE_ADDR pc, CORE_ADDR current_pc,
+                         struct i386_frame_cache *cache)
+{
+  /* There are 2 code sequences to re-align stack before the frame
+     gets set up:
+
+       1. Use a caller-saved saved register:
+
+               leal  4(%esp), %reg
+               andl  $-XXX, %esp
+               pushl -4(%reg)
+
+       2. Use a callee-saved saved register:
+
+               pushl %reg
+               leal  8(%esp), %reg
+               andl  $-XXX, %esp
+               pushl -4(%reg)
+
+     "andl $-XXX, %esp" can be either 3 bytes or 6 bytes:
+     
+       0x83 0xe4 0xf0                  andl $-16, %esp
+       0x81 0xe4 0x00 0xff 0xff 0xff   andl $-256, %esp
+   */
+
+  gdb_byte buf[14];
+  int reg;
+  int offset, offset_and;
+  static int regnums[8] = {
+    I386_EAX_REGNUM,           /* %eax */
+    I386_ECX_REGNUM,           /* %ecx */
+    I386_EDX_REGNUM,           /* %edx */
+    I386_EBX_REGNUM,           /* %ebx */
+    I386_ESP_REGNUM,           /* %esp */
+    I386_EBP_REGNUM,           /* %ebp */
+    I386_ESI_REGNUM,           /* %esi */
+    I386_EDI_REGNUM            /* %edi */
+  };
+
+  if (target_read_memory (pc, buf, sizeof buf))
+    return pc;
+
+  /* Check caller-saved saved register.  The first instruction has
+     to be "leal 4(%esp), %reg".  */
+  if (buf[0] == 0x8d && buf[2] == 0x24 && buf[3] == 0x4)
+    {
+      /* MOD must be binary 10 and R/M must be binary 100.  */
+      if ((buf[1] & 0xc7) != 0x44)
+       return pc;
+
+      /* REG has register number.  */
+      reg = (buf[1] >> 3) & 7;
+      offset = 4;
+    }
+  else
+    {
+      /* Check callee-saved saved register.  The first instruction
+        has to be "pushl %reg".  */
+      if ((buf[0] & 0xf8) != 0x50)
+       return pc;
+
+      /* Get register.  */
+      reg = buf[0] & 0x7;
+
+      /* The next instruction has to be "leal 8(%esp), %reg".  */
+      if (buf[1] != 0x8d || buf[3] != 0x24 || buf[4] != 0x8)
+       return pc;
+
+      /* MOD must be binary 10 and R/M must be binary 100.  */
+      if ((buf[2] & 0xc7) != 0x44)
+       return pc;
+      
+      /* REG has register number.  Registers in pushl and leal have to
+        be the same.  */
+      if (reg != ((buf[2] >> 3) & 7))
+       return pc;
+
+      offset = 5;
+    }
+
+  /* Rigister can't be %esp nor %ebp.  */
+  if (reg == 4 || reg == 5)
+    return pc;
+
+  /* The next instruction has to be "andl $-XXX, %esp".  */
+  if (buf[offset + 1] != 0xe4
+      || (buf[offset] != 0x81 && buf[offset] != 0x83))
+    return pc;
+
+  offset_and = offset;
+  offset += buf[offset] == 0x81 ? 6 : 3;
+
+  /* The next instruction has to be "pushl -4(%reg)".  8bit -4 is
+     0xfc.  REG must be binary 110 and MOD must be binary 01.  */
+  if (buf[offset] != 0xff
+      || buf[offset + 2] != 0xfc
+      || (buf[offset + 1] & 0xf8) != 0x70)
+    return pc;
+
+  /* R/M has register.  Registers in leal and pushl have to be the
+     same.  */
+  if (reg != (buf[offset + 1] & 7))
+    return pc;
+
+  if (current_pc > pc + offset_and)
+    cache->saved_sp_reg = regnums[reg];
+
+  return min (pc + offset + 3, current_pc);
+}
+
 /* Maximum instruction length we need to handle.  */
-#define I386_MAX_INSN_LEN      6
+#define I386_MAX_MATCHED_INSN_LEN      6
 
 /* Instruction description.  */
 struct i386_insn
 {
   size_t len;
-  gdb_byte insn[I386_MAX_INSN_LEN];
-  gdb_byte mask[I386_MAX_INSN_LEN];
+  gdb_byte insn[I386_MAX_MATCHED_INSN_LEN];
+  gdb_byte mask[I386_MAX_MATCHED_INSN_LEN];
 };
 
 /* Search for the instruction at PC in the list SKIP_INSNS.  Return
@@ -506,20 +871,20 @@ i386_match_insn (CORE_ADDR pc, struct i386_insn *skip_insns)
   struct i386_insn *insn;
   gdb_byte op;
 
-  op = read_memory_unsigned_integer (pc, 1);
+  target_read_memory (pc, &op, 1);
 
   for (insn = skip_insns; insn->len > 0; insn++)
     {
       if ((op & insn->mask[0]) == insn->insn[0])
        {
-         gdb_byte buf[I386_MAX_INSN_LEN - 1];
+         gdb_byte buf[I386_MAX_MATCHED_INSN_LEN - 1];
          int insn_matched = 1;
          size_t i;
 
          gdb_assert (insn->len > 1);
-         gdb_assert (insn->len <= I386_MAX_INSN_LEN);
+         gdb_assert (insn->len <= I386_MAX_MATCHED_INSN_LEN);
 
-         read_memory (pc + 1, buf, insn->len - 1);
+         target_read_memory (pc + 1, buf, insn->len - 1);
          for (i = 1; i < insn->len; i++)
            {
              if ((buf[i - 1] & insn->mask[i]) != insn->insn[i])
@@ -589,6 +954,51 @@ struct i386_insn i386_frame_setup_skip_insns[] =
   { 0 }
 };
 
+
+/* Check whether PC points to a no-op instruction.  */
+static CORE_ADDR
+i386_skip_noop (CORE_ADDR pc)
+{
+  gdb_byte op;
+  int check = 1;
+
+  target_read_memory (pc, &op, 1);
+
+  while (check) 
+    {
+      check = 0;
+      /* Ignore `nop' instruction.  */
+      if (op == 0x90) 
+       {
+         pc += 1;
+         target_read_memory (pc, &op, 1);
+         check = 1;
+       }
+      /* Ignore no-op instruction `mov %edi, %edi'.
+        Microsoft system dlls often start with
+        a `mov %edi,%edi' instruction.
+        The 5 bytes before the function start are
+        filled with `nop' instructions.
+        This pattern can be used for hot-patching:
+        The `mov %edi, %edi' instruction can be replaced by a
+        near jump to the location of the 5 `nop' instructions
+        which can be replaced by a 32-bit jump to anywhere
+        in the 32-bit address space.  */
+
+      else if (op == 0x8b)
+       {
+         target_read_memory (pc + 1, &op, 1);
+         if (op == 0xff)
+           {
+             pc += 2;
+             target_read_memory (pc, &op, 1);
+             check = 1;
+           }
+       }
+    }
+  return pc; 
+}
+
 /* Check whether PC points at a code that sets up a new stack frame.
    If so, it updates CACHE and returns the address of the first
    instruction after the sequence that sets up the frame or LIMIT,
@@ -605,7 +1015,7 @@ i386_analyze_frame_setup (CORE_ADDR pc, CORE_ADDR limit,
   if (limit <= pc)
     return limit;
 
-  op = read_memory_unsigned_integer (pc, 1);
+  target_read_memory (pc, &op, 1);
 
   if (op == 0x55)              /* pushl %ebp */
     {
@@ -640,7 +1050,7 @@ i386_analyze_frame_setup (CORE_ADDR pc, CORE_ADDR limit,
       if (limit <= pc + skip)
        return limit;
 
-      op = read_memory_unsigned_integer (pc + skip, 1);
+      target_read_memory (pc + skip, &op, 1);
 
       /* Check for `movl %esp, %ebp' -- can be written in two ways.  */
       switch (op)
@@ -674,7 +1084,7 @@ i386_analyze_frame_setup (CORE_ADDR pc, CORE_ADDR limit,
 
         NOTE: You can't subtract a 16-bit immediate from a 32-bit
         reg, so we don't have to worry about a data16 prefix.  */
-      op = read_memory_unsigned_integer (pc, 1);
+      target_read_memory (pc, &op, 1);
       if (op == 0x83)
        {
          /* `subl' with 8-bit immediate.  */
@@ -730,7 +1140,7 @@ i386_analyze_register_saves (CORE_ADDR pc, CORE_ADDR current_pc,
     offset -= cache->locals;
   for (i = 0; i < 8 && pc < current_pc; i++)
     {
-      op = read_memory_unsigned_integer (pc, 1);
+      target_read_memory (pc, &op, 1);
       if (op < 0x50 || op > 0x57)
        break;
 
@@ -774,9 +1184,11 @@ static CORE_ADDR
 i386_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc,
                       struct i386_frame_cache *cache)
 {
+  pc = i386_skip_noop (pc);
   pc = i386_follow_jump (pc);
   pc = i386_analyze_struct_return (pc, current_pc, cache);
   pc = i386_skip_probe (pc);
+  pc = i386_analyze_stack_align (pc, current_pc, cache);
   pc = i386_analyze_frame_setup (pc, current_pc, cache);
   return i386_analyze_register_saves (pc, current_pc, cache);
 }
@@ -784,7 +1196,7 @@ i386_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc,
 /* Return PC of first real instruction.  */
 
 static CORE_ADDR
-i386_skip_prologue (CORE_ADDR start_pc)
+i386_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc)
 {
   static gdb_byte pic_pat[6] =
   {
@@ -818,7 +1230,7 @@ i386_skip_prologue (CORE_ADDR start_pc)
 
   for (i = 0; i < 6; i++)
     {
-      op = read_memory_unsigned_integer (pc + i, 1);
+      target_read_memory (pc + i, &op, 1);
       if (pic_pat[i] != op)
        break;
     }
@@ -826,7 +1238,7 @@ i386_skip_prologue (CORE_ADDR start_pc)
     {
       int delta = 6;
 
-      op = read_memory_unsigned_integer (pc + delta, 1);
+      target_read_memory (pc + delta, &op, 1);
 
       if (op == 0x89)          /* movl %ebx, x(%ebp) */
        {
@@ -839,12 +1251,12 @@ i386_skip_prologue (CORE_ADDR start_pc)
          else                  /* Unexpected instruction.  */
            delta = 0;
 
-         op = read_memory_unsigned_integer (pc + delta, 1);
+          target_read_memory (pc + delta, &op, 1);
        }
 
       /* addl y,%ebx */
       if (delta > 0 && op == 0x81
-         && read_memory_unsigned_integer (pc + delta + 1, 1) == 0xc3);
+         && read_memory_unsigned_integer (pc + delta + 1, 1) == 0xc3)
        {
          pc += delta + 6;
        }
@@ -859,6 +1271,38 @@ i386_skip_prologue (CORE_ADDR start_pc)
   return pc;
 }
 
+/* Check that the code pointed to by PC corresponds to a call to
+   __main, skip it if so.  Return PC otherwise.  */
+
+CORE_ADDR
+i386_skip_main_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  gdb_byte op;
+
+  target_read_memory (pc, &op, 1);
+  if (op == 0xe8)
+    {
+      gdb_byte buf[4];
+
+      if (target_read_memory (pc + 1, buf, sizeof buf) == 0)
+       {
+         /* Make sure address is computed correctly as a 32bit
+            integer even if CORE_ADDR is 64 bit wide.  */
+         struct minimal_symbol *s;
+         CORE_ADDR call_dest = pc + 5 + extract_signed_integer (buf, 4);
+
+         call_dest = call_dest & 0xffffffffU;
+         s = lookup_minimal_symbol_by_pc (call_dest);
+         if (s != NULL
+             && SYMBOL_LINKAGE_NAME (s) != NULL
+             && strcmp (SYMBOL_LINKAGE_NAME (s), "__main") == 0)
+           pc += 5;
+       }
+    }
+
+  return pc;
+}
+
 /* This function is 64-bit safe.  */
 
 static CORE_ADDR
@@ -866,15 +1310,15 @@ i386_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
 {
   gdb_byte buf[8];
 
-  frame_unwind_register (next_frame, PC_REGNUM, buf);
-  return extract_typed_address (buf, builtin_type_void_func_ptr);
+  frame_unwind_register (next_frame, gdbarch_pc_regnum (gdbarch), buf);
+  return extract_typed_address (buf, builtin_type (gdbarch)->builtin_func_ptr);
 }
 \f
 
 /* Normal frames.  */
 
 static struct i386_frame_cache *
-i386_frame_cache (struct frame_info *next_frame, void **this_cache)
+i386_frame_cache (struct frame_info *this_frame, void **this_cache)
 {
   struct i386_frame_cache *cache;
   gdb_byte buf[4];
@@ -895,7 +1339,7 @@ i386_frame_cache (struct frame_info *next_frame, void **this_cache)
      They (usually) share their frame pointer with the frame that was
      in progress when the signal occurred.  */
 
-  frame_unwind_register (next_frame, I386_EBP_REGNUM, buf);
+  get_frame_register (this_frame, I386_EBP_REGNUM, buf);
   cache->base = extract_unsigned_integer (buf, 4);
   if (cache->base == 0)
     return cache;
@@ -903,9 +1347,16 @@ i386_frame_cache (struct frame_info *next_frame, void **this_cache)
   /* For normal frames, %eip is stored at 4(%ebp).  */
   cache->saved_regs[I386_EIP_REGNUM] = 4;
 
-  cache->pc = frame_func_unwind (next_frame);
+  cache->pc = get_frame_func (this_frame);
   if (cache->pc != 0)
-    i386_analyze_prologue (cache->pc, frame_pc_unwind (next_frame), cache);
+    i386_analyze_prologue (cache->pc, get_frame_pc (this_frame), cache);
+
+  if (cache->saved_sp_reg != -1)
+    {
+      /* Saved stack pointer has been saved.  */
+      get_frame_register (this_frame, cache->saved_sp_reg, buf);
+      cache->saved_sp = extract_unsigned_integer(buf, 4);
+    }
 
   if (cache->locals < 0)
     {
@@ -917,13 +1368,26 @@ i386_frame_cache (struct frame_info *next_frame, void **this_cache)
         frame by looking at the stack pointer.  For truly "frameless"
         functions this might work too.  */
 
-      frame_unwind_register (next_frame, I386_ESP_REGNUM, buf);
-      cache->base = extract_unsigned_integer (buf, 4) + cache->sp_offset;
+      if (cache->saved_sp_reg != -1)
+       {
+         /* We're halfway aligning the stack.  */
+         cache->base = ((cache->saved_sp - 4) & 0xfffffff0) - 4;
+         cache->saved_regs[I386_EIP_REGNUM] = cache->saved_sp - 4;
+
+         /* This will be added back below.  */
+         cache->saved_regs[I386_EIP_REGNUM] -= cache->base;
+       }
+      else
+       {
+         get_frame_register (this_frame, I386_ESP_REGNUM, buf);
+         cache->base = extract_unsigned_integer (buf, 4) + cache->sp_offset;
+       }
     }
 
   /* Now that we have the base address for the stack frame we can
      calculate the value of %esp in the calling frame.  */
-  cache->saved_sp = cache->base + 8;
+  if (cache->saved_sp == 0)
+    cache->saved_sp = cache->base + 8;
 
   /* Adjust all the saved registers such that they contain addresses
      instead of offsets.  */
@@ -935,10 +1399,10 @@ i386_frame_cache (struct frame_info *next_frame, void **this_cache)
 }
 
 static void
-i386_frame_this_id (struct frame_info *next_frame, void **this_cache,
+i386_frame_this_id (struct frame_info *this_frame, void **this_cache,
                    struct frame_id *this_id)
 {
-  struct i386_frame_cache *cache = i386_frame_cache (next_frame, this_cache);
+  struct i386_frame_cache *cache = i386_frame_cache (this_frame, this_cache);
 
   /* This marks the outermost frame.  */
   if (cache->base == 0)
@@ -948,13 +1412,11 @@ i386_frame_this_id (struct frame_info *next_frame, void **this_cache,
   (*this_id) = frame_id_build (cache->base + 8, cache->pc);
 }
 
-static void
-i386_frame_prev_register (struct frame_info *next_frame, void **this_cache,
-                         int regnum, int *optimizedp,
-                         enum lval_type *lvalp, CORE_ADDR *addrp,
-                         int *realnump, gdb_byte *valuep)
+static struct value *
+i386_frame_prev_register (struct frame_info *this_frame, void **this_cache,
+                         int regnum)
 {
-  struct i386_frame_cache *cache = i386_frame_cache (next_frame, this_cache);
+  struct i386_frame_cache *cache = i386_frame_cache (this_frame, this_cache);
 
   gdb_assert (regnum >= 0);
 
@@ -979,93 +1441,43 @@ i386_frame_prev_register (struct frame_info *next_frame, void **this_cache,
 
   if (regnum == I386_EFLAGS_REGNUM)
     {
-      *optimizedp = 0;
-      *lvalp = not_lval;
-      *addrp = 0;
-      *realnump = -1;
-      if (valuep)
-       {
-         ULONGEST val;
+      ULONGEST val;
 
-         /* Clear the direction flag.  */
-         val = frame_unwind_register_unsigned (next_frame,
-                                               I386_EFLAGS_REGNUM);
-         val &= ~(1 << 10);
-         store_unsigned_integer (valuep, 4, val);
-       }
-
-      return;
+      val = get_frame_register_unsigned (this_frame, regnum);
+      val &= ~(1 << 10);
+      return frame_unwind_got_constant (this_frame, regnum, val);
     }
 
   if (regnum == I386_EIP_REGNUM && cache->pc_in_eax)
-    {
-      *optimizedp = 0;
-      *lvalp = lval_register;
-      *addrp = 0;
-      *realnump = I386_EAX_REGNUM;
-      if (valuep)
-       frame_unwind_register (next_frame, (*realnump), valuep);
-      return;
-    }
+    return frame_unwind_got_register (this_frame, regnum, I386_EAX_REGNUM);
 
   if (regnum == I386_ESP_REGNUM && cache->saved_sp)
-    {
-      *optimizedp = 0;
-      *lvalp = not_lval;
-      *addrp = 0;
-      *realnump = -1;
-      if (valuep)
-       {
-         /* Store the value.  */
-         store_unsigned_integer (valuep, 4, cache->saved_sp);
-       }
-      return;
-    }
+    return frame_unwind_got_constant (this_frame, regnum, cache->saved_sp);
 
   if (regnum < I386_NUM_SAVED_REGS && cache->saved_regs[regnum] != -1)
-    {
-      *optimizedp = 0;
-      *lvalp = lval_memory;
-      *addrp = cache->saved_regs[regnum];
-      *realnump = -1;
-      if (valuep)
-       {
-         /* Read the value in from memory.  */
-         read_memory (*addrp, valuep,
-                      register_size (current_gdbarch, regnum));
-       }
-      return;
-    }
+    return frame_unwind_got_memory (this_frame, regnum,
+                                   cache->saved_regs[regnum]);
 
-  *optimizedp = 0;
-  *lvalp = lval_register;
-  *addrp = 0;
-  *realnump = regnum;
-  if (valuep)
-    frame_unwind_register (next_frame, (*realnump), valuep);
+  return frame_unwind_got_register (this_frame, regnum, regnum);
 }
 
 static const struct frame_unwind i386_frame_unwind =
 {
   NORMAL_FRAME,
   i386_frame_this_id,
-  i386_frame_prev_register
+  i386_frame_prev_register,
+  NULL,
+  default_frame_sniffer
 };
-
-static const struct frame_unwind *
-i386_frame_sniffer (struct frame_info *next_frame)
-{
-  return &i386_frame_unwind;
-}
 \f
 
 /* Signal trampolines.  */
 
 static struct i386_frame_cache *
-i386_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache)
+i386_sigtramp_frame_cache (struct frame_info *this_frame, void **this_cache)
 {
   struct i386_frame_cache *cache;
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (this_frame));
   CORE_ADDR addr;
   gdb_byte buf[4];
 
@@ -1074,10 +1486,10 @@ i386_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache)
 
   cache = i386_alloc_frame_cache ();
 
-  frame_unwind_register (next_frame, I386_ESP_REGNUM, buf);
+  get_frame_register (this_frame, I386_ESP_REGNUM, buf);
   cache->base = extract_unsigned_integer (buf, 4) - 4;
 
-  addr = tdep->sigcontext_addr (next_frame);
+  addr = tdep->sigcontext_addr (this_frame);
   if (tdep->sc_reg_offset)
     {
       int i;
@@ -1099,70 +1511,70 @@ i386_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache)
 }
 
 static void
-i386_sigtramp_frame_this_id (struct frame_info *next_frame, void **this_cache,
+i386_sigtramp_frame_this_id (struct frame_info *this_frame, void **this_cache,
                             struct frame_id *this_id)
 {
   struct i386_frame_cache *cache =
-    i386_sigtramp_frame_cache (next_frame, this_cache);
+    i386_sigtramp_frame_cache (this_frame, this_cache);
 
   /* See the end of i386_push_dummy_call.  */
-  (*this_id) = frame_id_build (cache->base + 8, frame_pc_unwind (next_frame));
+  (*this_id) = frame_id_build (cache->base + 8, get_frame_pc (this_frame));
 }
 
-static void
-i386_sigtramp_frame_prev_register (struct frame_info *next_frame,
-                                  void **this_cache,
-                                  int regnum, int *optimizedp,
-                                  enum lval_type *lvalp, CORE_ADDR *addrp,
-                                  int *realnump, gdb_byte *valuep)
+static struct value *
+i386_sigtramp_frame_prev_register (struct frame_info *this_frame,
+                                  void **this_cache, int regnum)
 {
   /* Make sure we've initialized the cache.  */
-  i386_sigtramp_frame_cache (next_frame, this_cache);
+  i386_sigtramp_frame_cache (this_frame, this_cache);
 
-  i386_frame_prev_register (next_frame, this_cache, regnum,
-                           optimizedp, lvalp, addrp, realnump, valuep);
+  return i386_frame_prev_register (this_frame, this_cache, regnum);
 }
 
-static const struct frame_unwind i386_sigtramp_frame_unwind =
-{
-  SIGTRAMP_FRAME,
-  i386_sigtramp_frame_this_id,
-  i386_sigtramp_frame_prev_register
-};
-
-static const struct frame_unwind *
-i386_sigtramp_frame_sniffer (struct frame_info *next_frame)
+static int
+i386_sigtramp_frame_sniffer (const struct frame_unwind *self,
+                            struct frame_info *this_frame,
+                            void **this_prologue_cache)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (next_frame));
+  struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (this_frame));
 
   /* We shouldn't even bother if we don't have a sigcontext_addr
      handler.  */
   if (tdep->sigcontext_addr == NULL)
-    return NULL;
+    return 0;
 
   if (tdep->sigtramp_p != NULL)
     {
-      if (tdep->sigtramp_p (next_frame))
-       return &i386_sigtramp_frame_unwind;
+      if (tdep->sigtramp_p (this_frame))
+       return 1;
     }
 
   if (tdep->sigtramp_start != 0)
     {
-      CORE_ADDR pc = frame_pc_unwind (next_frame);
+      CORE_ADDR pc = get_frame_pc (this_frame);
 
       gdb_assert (tdep->sigtramp_end != 0);
       if (pc >= tdep->sigtramp_start && pc < tdep->sigtramp_end)
-       return &i386_sigtramp_frame_unwind;
+       return 1;
     }
 
-  return NULL;
+  return 0;
 }
+
+static const struct frame_unwind i386_sigtramp_frame_unwind =
+{
+  SIGTRAMP_FRAME,
+  i386_sigtramp_frame_this_id,
+  i386_sigtramp_frame_prev_register,
+  NULL,
+  i386_sigtramp_frame_sniffer
+};
 \f
 
 static CORE_ADDR
-i386_frame_base_address (struct frame_info *next_frame, void **this_cache)
+i386_frame_base_address (struct frame_info *this_frame, void **this_cache)
 {
-  struct i386_frame_cache *cache = i386_frame_cache (next_frame, this_cache);
+  struct i386_frame_cache *cache = i386_frame_cache (this_frame, this_cache);
 
   return cache->base;
 }
@@ -1176,16 +1588,14 @@ static const struct frame_base i386_frame_base =
 };
 
 static struct frame_id
-i386_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+i386_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
 {
-  gdb_byte buf[4];
   CORE_ADDR fp;
 
-  frame_unwind_register (next_frame, I386_EBP_REGNUM, buf);
-  fp = extract_unsigned_integer (buf, 4);
+  fp = get_frame_register_unsigned (this_frame, I386_EBP_REGNUM);
 
   /* See the end of i386_push_dummy_call.  */
-  return frame_id_build (fp + 8, frame_pc_unwind (next_frame));
+  return frame_id_build (fp + 8, get_frame_pc (this_frame));
 }
 \f
 
@@ -1193,39 +1603,63 @@ i386_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
    stack.  We expect the first arg to be a pointer to the jmp_buf
    structure from which we extract the address that we will land at.
    This address is copied into PC.  This routine returns non-zero on
-   success.
-
-   This function is 64-bit safe.  */
+   success.  */
 
 static int
-i386_get_longjmp_target (CORE_ADDR *pc)
+i386_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
 {
-  gdb_byte buf[8];
+  gdb_byte buf[4];
   CORE_ADDR sp, jb_addr;
-  int jb_pc_offset = gdbarch_tdep (current_gdbarch)->jb_pc_offset;
-  int len = TYPE_LENGTH (builtin_type_void_func_ptr);
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  int jb_pc_offset = gdbarch_tdep (gdbarch)->jb_pc_offset;
 
   /* If JB_PC_OFFSET is -1, we have no way to find out where the
      longjmp will land.  */
   if (jb_pc_offset == -1)
     return 0;
 
-  /* Don't use I386_ESP_REGNUM here, since this function is also used
-     for AMD64.  */
-  regcache_cooked_read (current_regcache, SP_REGNUM, buf);
-  sp = extract_typed_address (buf, builtin_type_void_data_ptr);
-  if (target_read_memory (sp + len, buf, len))
+  get_frame_register (frame, I386_ESP_REGNUM, buf);
+  sp = extract_unsigned_integer (buf, 4);
+  if (target_read_memory (sp + 4, buf, 4))
     return 0;
 
-  jb_addr = extract_typed_address (buf, builtin_type_void_data_ptr);
-  if (target_read_memory (jb_addr + jb_pc_offset, buf, len))
+  jb_addr = extract_unsigned_integer (buf, 4);
+  if (target_read_memory (jb_addr + jb_pc_offset, buf, 4))
     return 0;
 
-  *pc = extract_typed_address (buf, builtin_type_void_func_ptr);
+  *pc = extract_unsigned_integer (buf, 4);
   return 1;
 }
 \f
 
+/* Check whether TYPE must be 16-byte-aligned when passed as a
+   function argument.  16-byte vectors, _Decimal128 and structures or
+   unions containing such types must be 16-byte-aligned; other
+   arguments are 4-byte-aligned.  */
+
+static int
+i386_16_byte_align_p (struct type *type)
+{
+  type = check_typedef (type);
+  if ((TYPE_CODE (type) == TYPE_CODE_DECFLOAT
+       || (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type)))
+      && TYPE_LENGTH (type) == 16)
+    return 1;
+  if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+    return i386_16_byte_align_p (TYPE_TARGET_TYPE (type));
+  if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+      || TYPE_CODE (type) == TYPE_CODE_UNION)
+    {
+      int i;
+      for (i = 0; i < TYPE_NFIELDS (type); i++)
+       {
+         if (i386_16_byte_align_p (TYPE_FIELD_TYPE (type, i)))
+           return 1;
+       }
+    }
+  return 0;
+}
+
 static CORE_ADDR
 i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                      struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
@@ -1234,29 +1668,68 @@ i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 {
   gdb_byte buf[4];
   int i;
+  int write_pass;
+  int args_space = 0;
+
+  /* Determine the total space required for arguments and struct
+     return address in a first pass (allowing for 16-byte-aligned
+     arguments), then push arguments in a second pass.  */
 
-  /* Push arguments in reverse order.  */
-  for (i = nargs - 1; i >= 0; i--)
+  for (write_pass = 0; write_pass < 2; write_pass++)
     {
-      int len = TYPE_LENGTH (value_enclosing_type (args[i]));
+      int args_space_used = 0;
+      int have_16_byte_aligned_arg = 0;
 
-      /* The System V ABI says that:
+      if (struct_return)
+       {
+         if (write_pass)
+           {
+             /* Push value address.  */
+             store_unsigned_integer (buf, 4, struct_addr);
+             write_memory (sp, buf, 4);
+             args_space_used += 4;
+           }
+         else
+           args_space += 4;
+       }
+
+      for (i = 0; i < nargs; i++)
+       {
+         int len = TYPE_LENGTH (value_enclosing_type (args[i]));
 
-        "An argument's size is increased, if necessary, to make it a
-        multiple of [32-bit] words.  This may require tail padding,
-        depending on the size of the argument."
+         if (write_pass)
+           {
+             if (i386_16_byte_align_p (value_enclosing_type (args[i])))
+               args_space_used = align_up (args_space_used, 16);
 
-        This makes sure the stack says word-aligned.  */
-      sp -= (len + 3) & ~3;
-      write_memory (sp, value_contents_all (args[i]), len);
-    }
+             write_memory (sp + args_space_used,
+                           value_contents_all (args[i]), len);
+             /* The System V ABI says that:
 
-  /* Push value address.  */
-  if (struct_return)
-    {
-      sp -= 4;
-      store_unsigned_integer (buf, 4, struct_addr);
-      write_memory (sp, buf, 4);
+             "An argument's size is increased, if necessary, to make it a
+             multiple of [32-bit] words.  This may require tail padding,
+             depending on the size of the argument."
+
+             This makes sure the stack stays word-aligned.  */
+             args_space_used += align_up (len, 4);
+           }
+         else
+           {
+             if (i386_16_byte_align_p (value_enclosing_type (args[i])))
+               {
+                 args_space = align_up (args_space, 16);
+                 have_16_byte_aligned_arg = 1;
+               }
+             args_space += align_up (len, 4);
+           }
+       }
+
+      if (!write_pass)
+       {
+         if (have_16_byte_aligned_arg)
+           args_space = align_up (args_space, 16);
+         sp -= args_space;
+       }
     }
 
   /* Store return address.  */
@@ -1273,10 +1746,10 @@ i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
   /* MarkK wrote: This "+ 8" is all over the place:
      (i386_frame_this_id, i386_sigtramp_frame_this_id,
-     i386_unwind_dummy_id).  It's there, since all frame unwinders for
+     i386_dummy_id).  It's there, since all frame unwinders for
      a given target have to agree (within a certain margin) on the
-     definition of the stack address of a frame.  Otherwise
-     frame_id_inner() won't work correctly.  Since DWARF2/GCC uses the
+     definition of the stack address of a frame.  Otherwise frame id
+     comparison might not work correctly.  Since DWARF2/GCC uses the
      stack address *before* the function call as a frame's CFA.  On
      the i386, when %ebp is used as a frame pointer, the offset
      between the contents %ebp and the CFA as defined by GCC.  */
@@ -1314,12 +1787,12 @@ i386_extract_return_value (struct gdbarch *gdbarch, struct type *type,
         exactly how it would happen on the target itself, but it is
         the best we can do.  */
       regcache_raw_read (regcache, I386_ST0_REGNUM, buf);
-      convert_typed_floating (buf, builtin_type_i387_ext, valbuf, type);
+      convert_typed_floating (buf, i387_ext_type (gdbarch), valbuf, type);
     }
   else
     {
-      int low_size = register_size (current_gdbarch, LOW_RETURN_REGNUM);
-      int high_size = register_size (current_gdbarch, HIGH_RETURN_REGNUM);
+      int low_size = register_size (gdbarch, LOW_RETURN_REGNUM);
+      int high_size = register_size (gdbarch, HIGH_RETURN_REGNUM);
 
       if (len <= low_size)
        {
@@ -1349,10 +1822,6 @@ i386_store_return_value (struct gdbarch *gdbarch, struct type *type,
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   int len = TYPE_LENGTH (type);
 
-  /* Define I387_ST0_REGNUM such that we use the proper definitions
-     for the architecture.  */
-#define I387_ST0_REGNUM I386_ST0_REGNUM
-
   if (TYPE_CODE (type) == TYPE_CODE_FLT)
     {
       ULONGEST fstat;
@@ -1372,26 +1841,26 @@ i386_store_return_value (struct gdbarch *gdbarch, struct type *type,
         floating-point format used by the FPU.  This is probably
         not exactly how it would happen on the target itself, but
         it is the best we can do.  */
-      convert_typed_floating (valbuf, type, buf, builtin_type_i387_ext);
+      convert_typed_floating (valbuf, type, buf, i387_ext_type (gdbarch));
       regcache_raw_write (regcache, I386_ST0_REGNUM, buf);
 
       /* Set the top of the floating-point register stack to 7.  The
          actual value doesn't really matter, but 7 is what a normal
          function return would end up with if the program started out
          with a freshly initialized FPU.  */
-      regcache_raw_read_unsigned (regcache, I387_FSTAT_REGNUM, &fstat);
+      regcache_raw_read_unsigned (regcache, I387_FSTAT_REGNUM (tdep), &fstat);
       fstat |= (7 << 11);
-      regcache_raw_write_unsigned (regcache, I387_FSTAT_REGNUM, fstat);
+      regcache_raw_write_unsigned (regcache, I387_FSTAT_REGNUM (tdep), fstat);
 
       /* Mark %st(1) through %st(7) as empty.  Since we set the top of
          the floating-point register stack to 7, the appropriate value
          for the tag word is 0x3fff.  */
-      regcache_raw_write_unsigned (regcache, I387_FTAG_REGNUM, 0x3fff);
+      regcache_raw_write_unsigned (regcache, I387_FTAG_REGNUM (tdep), 0x3fff);
     }
   else
     {
-      int low_size = register_size (current_gdbarch, LOW_RETURN_REGNUM);
-      int high_size = register_size (current_gdbarch, HIGH_RETURN_REGNUM);
+      int low_size = register_size (gdbarch, LOW_RETURN_REGNUM);
+      int high_size = register_size (gdbarch, HIGH_RETURN_REGNUM);
 
       if (len <= low_size)
        regcache_raw_write_part (regcache, LOW_RETURN_REGNUM, 0, len, valbuf);
@@ -1405,8 +1874,6 @@ i386_store_return_value (struct gdbarch *gdbarch, struct type *type,
        internal_error (__FILE__, __LINE__,
                        _("Cannot store return value of %d bytes long."), len);
     }
-
-#undef I387_ST0_REGNUM
 }
 \f
 
@@ -1463,16 +1930,18 @@ i386_reg_struct_return_p (struct gdbarch *gdbarch, struct type *type)
    from WRITEBUF into REGCACHE.  */
 
 static enum return_value_convention
-i386_return_value (struct gdbarch *gdbarch, struct type *type,
-                  struct regcache *regcache, gdb_byte *readbuf,
-                  const gdb_byte *writebuf)
+i386_return_value (struct gdbarch *gdbarch, struct type *func_type,
+                  struct type *type, struct regcache *regcache,
+                  gdb_byte *readbuf, const gdb_byte *writebuf)
 {
   enum type_code code = TYPE_CODE (type);
 
-  if ((code == TYPE_CODE_STRUCT
-       || code == TYPE_CODE_UNION
-       || code == TYPE_CODE_ARRAY)
-      && !i386_reg_struct_return_p (gdbarch, type))
+  if (((code == TYPE_CODE_STRUCT
+       || code == TYPE_CODE_UNION
+       || code == TYPE_CODE_ARRAY)
+       && !i386_reg_struct_return_p (gdbarch, type))
+      /* 128-bit decimal float uses the struct return convention.  */
+      || (code == TYPE_CODE_DECFLOAT && TYPE_LENGTH (type) == 16))
     {
       /* The System V ABI says that:
 
@@ -1512,7 +1981,8 @@ i386_return_value (struct gdbarch *gdbarch, struct type *type,
   if (code == TYPE_CODE_STRUCT && TYPE_NFIELDS (type) == 1)
     {
       type = check_typedef (TYPE_FIELD_TYPE (type, 0));
-      return i386_return_value (gdbarch, type, regcache, readbuf, writebuf);
+      return i386_return_value (gdbarch, func_type, type, regcache,
+                               readbuf, writebuf);
     }
 
   if (readbuf)
@@ -1524,93 +1994,205 @@ i386_return_value (struct gdbarch *gdbarch, struct type *type,
 }
 \f
 
-/* Types for the MMX and SSE registers.  */
-static struct type *i386_mmx_type;
-static struct type *i386_sse_type;
-
-/* Construct the type for MMX registers.  */
-static struct type *
-i386_build_mmx_type (void)
+/* Construct types for ISA-specific registers.  */
+struct type *
+i386_eflags_type (struct gdbarch *gdbarch)
 {
-  /* The type we're building is this: */
-#if 0
-  union __gdb_builtin_type_vec64i 
-  {
-    int64_t uint64;
-    int32_t v2_int32[2];
-    int16_t v4_int16[4];
-    int8_t v8_int8[8];
-  };
-#endif
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  if (! i386_mmx_type)
+  if (!tdep->i386_eflags_type)
     {
-      struct type *t;
-
-      t = init_composite_type ("__gdb_builtin_type_vec64i", TYPE_CODE_UNION);
-      append_composite_type_field (t, "uint64", builtin_type_int64);
-      append_composite_type_field (t, "v2_int32", builtin_type_v2_int32);
-      append_composite_type_field (t, "v4_int16", builtin_type_v4_int16);
-      append_composite_type_field (t, "v8_int8", builtin_type_v8_int8);
-
-      TYPE_FLAGS (t) |= TYPE_FLAG_VECTOR;
-      TYPE_NAME (t) = "builtin_type_vec64i";
-
-      i386_mmx_type = t;
+      struct type *type;
+
+      type = arch_flags_type (gdbarch, "builtin_type_i386_eflags", 4);
+      append_flags_type_flag (type, 0, "CF");
+      append_flags_type_flag (type, 1, NULL);
+      append_flags_type_flag (type, 2, "PF");
+      append_flags_type_flag (type, 4, "AF");
+      append_flags_type_flag (type, 6, "ZF");
+      append_flags_type_flag (type, 7, "SF");
+      append_flags_type_flag (type, 8, "TF");
+      append_flags_type_flag (type, 9, "IF");
+      append_flags_type_flag (type, 10, "DF");
+      append_flags_type_flag (type, 11, "OF");
+      append_flags_type_flag (type, 14, "NT");
+      append_flags_type_flag (type, 16, "RF");
+      append_flags_type_flag (type, 17, "VM");
+      append_flags_type_flag (type, 18, "AC");
+      append_flags_type_flag (type, 19, "VIF");
+      append_flags_type_flag (type, 20, "VIP");
+      append_flags_type_flag (type, 21, "ID");
+
+      tdep->i386_eflags_type = type;
     }
 
-  return i386_mmx_type;
+  return tdep->i386_eflags_type;
 }
 
-/* Construct the type for SSE registers.  */
-static struct type *
-i386_build_sse_type (void)
+struct type *
+i386_mxcsr_type (struct gdbarch *gdbarch)
 {
-  if (! i386_sse_type)
-    {
-      struct type *t;
-
-      t = init_composite_type ("__gdb_builtin_type_vec128i", TYPE_CODE_UNION);
-      append_composite_type_field (t, "v4_float", builtin_type_v4_float);
-      append_composite_type_field (t, "v2_double", builtin_type_v2_double);
-      append_composite_type_field (t, "v16_int8", builtin_type_v16_int8);
-      append_composite_type_field (t, "v8_int16", builtin_type_v8_int16);
-      append_composite_type_field (t, "v4_int32", builtin_type_v4_int32);
-      append_composite_type_field (t, "v2_int64", builtin_type_v2_int64);
-      append_composite_type_field (t, "uint128", builtin_type_int128);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-      TYPE_FLAGS (t) |= TYPE_FLAG_VECTOR;
-      TYPE_NAME (t) = "builtin_type_vec128i";
-      
-      i386_sse_type = t;
+  if (!tdep->i386_mxcsr_type)
+    {
+      struct type *type;
+
+      type = arch_flags_type (gdbarch, "builtin_type_i386_mxcsr", 4);
+      append_flags_type_flag (type, 0, "IE");
+      append_flags_type_flag (type, 1, "DE");
+      append_flags_type_flag (type, 2, "ZE");
+      append_flags_type_flag (type, 3, "OE");
+      append_flags_type_flag (type, 4, "UE");
+      append_flags_type_flag (type, 5, "PE");
+      append_flags_type_flag (type, 6, "DAZ");
+      append_flags_type_flag (type, 7, "IM");
+      append_flags_type_flag (type, 8, "DM");
+      append_flags_type_flag (type, 9, "ZM");
+      append_flags_type_flag (type, 10, "OM");
+      append_flags_type_flag (type, 11, "UM");
+      append_flags_type_flag (type, 12, "PM");
+      append_flags_type_flag (type, 15, "FZ");
+
+      tdep->i386_mxcsr_type = type;
     }
 
-  return i386_sse_type;
+  return tdep->i386_mxcsr_type;
 }
 
-/* Return the GDB type object for the "standard" data type of data in
-   register REGNUM.  Perhaps %esi and %edi should go here, but
-   potentially they could be used for things other than address.  */
-
-static struct type *
-i386_register_type (struct gdbarch *gdbarch, int regnum)
+struct type *
+i387_ext_type (struct gdbarch *gdbarch)
 {
-  if (regnum == I386_EIP_REGNUM)
-    return builtin_type_void_func_ptr;
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  if (regnum == I386_EBP_REGNUM || regnum == I386_ESP_REGNUM)
-    return builtin_type_void_data_ptr;
+  if (!tdep->i387_ext_type)
+    tdep->i387_ext_type
+      = arch_float_type (gdbarch, -1, "builtin_type_i387_ext",
+                        floatformats_i387_ext);
 
-  if (i386_fp_regnum_p (regnum))
-    return builtin_type_i387_ext;
+  return tdep->i387_ext_type;
+}
 
-  if (i386_sse_regnum_p (gdbarch, regnum))
-    return i386_build_sse_type ();
+/* Construct vector type for MMX registers.  */
+struct type *
+i386_mmx_type (struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  if (!tdep->i386_mmx_type)
+    {
+      const struct builtin_type *bt = builtin_type (gdbarch);
+
+      /* The type we're building is this: */
+#if 0
+      union __gdb_builtin_type_vec64i
+      {
+        int64_t uint64;
+        int32_t v2_int32[2];
+        int16_t v4_int16[4];
+        int8_t v8_int8[8];
+      };
+#endif
+
+      struct type *t;
+
+      t = arch_composite_type (gdbarch,
+                              "__gdb_builtin_type_vec64i", TYPE_CODE_UNION);
+
+      append_composite_type_field (t, "uint64", bt->builtin_int64);
+      append_composite_type_field (t, "v2_int32",
+                                  init_vector_type (bt->builtin_int32, 2));
+      append_composite_type_field (t, "v4_int16",
+                                  init_vector_type (bt->builtin_int16, 4));
+      append_composite_type_field (t, "v8_int8",
+                                  init_vector_type (bt->builtin_int8, 8));
+
+      TYPE_VECTOR (t) = 1;
+      TYPE_NAME (t) = "builtin_type_vec64i";
+      tdep->i386_mmx_type = t;
+    }
+
+  return tdep->i386_mmx_type;
+}
+
+struct type *
+i386_sse_type (struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  if (!tdep->i386_sse_type)
+    {
+      const struct builtin_type *bt = builtin_type (gdbarch);
+
+      /* The type we're building is this: */
+#if 0
+      union __gdb_builtin_type_vec128i
+      {
+        int128_t uint128;
+        int64_t v2_int64[2];
+        int32_t v4_int32[4];
+        int16_t v8_int16[8];
+        int8_t v16_int8[16];
+        double v2_double[2];
+        float v4_float[4];
+      };
+#endif
+
+      struct type *t;
+
+      t = arch_composite_type (gdbarch,
+                              "__gdb_builtin_type_vec128i", TYPE_CODE_UNION);
+      append_composite_type_field (t, "v4_float",
+                                  init_vector_type (bt->builtin_float, 4));
+      append_composite_type_field (t, "v2_double",
+                                  init_vector_type (bt->builtin_double, 2));
+      append_composite_type_field (t, "v16_int8",
+                                  init_vector_type (bt->builtin_int8, 16));
+      append_composite_type_field (t, "v8_int16",
+                                  init_vector_type (bt->builtin_int16, 8));
+      append_composite_type_field (t, "v4_int32",
+                                  init_vector_type (bt->builtin_int32, 4));
+      append_composite_type_field (t, "v2_int64",
+                                  init_vector_type (bt->builtin_int64, 2));
+      append_composite_type_field (t, "uint128", bt->builtin_int128);
+
+      TYPE_VECTOR (t) = 1;
+      TYPE_NAME (t) = "builtin_type_vec128i";
+      tdep->i386_sse_type = t;
+    }
+
+  return tdep->i386_sse_type;
+}
+
+/* Return the GDB type object for the "standard" data type of data in
+   register REGNUM.  Perhaps %esi and %edi should go here, but
+   potentially they could be used for things other than address.  */
+
+static struct type *
+i386_register_type (struct gdbarch *gdbarch, int regnum)
+{
+  if (regnum == I386_EIP_REGNUM)
+    return builtin_type (gdbarch)->builtin_func_ptr;
+
+  if (regnum == I386_EFLAGS_REGNUM)
+    return i386_eflags_type (gdbarch);
+
+  if (regnum == I386_EBP_REGNUM || regnum == I386_ESP_REGNUM)
+    return builtin_type (gdbarch)->builtin_data_ptr;
+
+  if (i386_fp_regnum_p (gdbarch, regnum))
+    return i387_ext_type (gdbarch);
 
   if (i386_mmx_regnum_p (gdbarch, regnum))
-    return i386_build_mmx_type ();
+    return i386_mmx_type (gdbarch);
+
+  if (i386_sse_regnum_p (gdbarch, regnum))
+    return i386_sse_type (gdbarch);
 
-  return builtin_type_int;
+  if (regnum == I387_MXCSR_REGNUM (gdbarch_tdep (gdbarch)))
+    return i386_mxcsr_type (gdbarch);
+
+  return builtin_type (gdbarch)->builtin_int;
 }
 
 /* Map a cooked register onto a raw register or memory.  For the i386,
@@ -1624,18 +2206,12 @@ i386_mmx_regnum_to_fp_regnum (struct regcache *regcache, int regnum)
   ULONGEST fstat;
   int tos;
 
-  /* Define I387_ST0_REGNUM such that we use the proper definitions
-     for REGCACHE's architecture.  */
-#define I387_ST0_REGNUM tdep->st0_regnum
-
   mmxreg = regnum - tdep->mm0_regnum;
-  regcache_raw_read_unsigned (regcache, I387_FSTAT_REGNUM, &fstat);
+  regcache_raw_read_unsigned (regcache, I387_FSTAT_REGNUM (tdep), &fstat);
   tos = (fstat >> 11) & 0x7;
   fpreg = (mmxreg + tos) % 8;
 
-  return (I387_ST0_REGNUM + fpreg);
-
-#undef I387_ST0_REGNUM
+  return (I387_ST0_REGNUM (tdep) + fpreg);
 }
 
 static void
@@ -1709,7 +2285,7 @@ i386_next_regnum (int regnum)
    needs any special handling.  */
 
 static int
-i386_convert_register_p (int regnum, struct type *type)
+i386_convert_register_p (struct gdbarch *gdbarch, int regnum, struct type *type)
 {
   int len = TYPE_LENGTH (type);
 
@@ -1732,7 +2308,7 @@ i386_convert_register_p (int regnum, struct type *type)
        return 1;
     }
 
-  return i386_fp_regnum_p (regnum);
+  return i387_convert_register_p (gdbarch, regnum, type);
 }
 
 /* Read a value of type TYPE from register REGNUM in frame FRAME, and
@@ -1742,12 +2318,13 @@ static void
 i386_register_to_value (struct frame_info *frame, int regnum,
                        struct type *type, gdb_byte *to)
 {
+  struct gdbarch *gdbarch = get_frame_arch (frame);
   int len = TYPE_LENGTH (type);
 
   /* FIXME: kettenis/20030609: What should we do if REGNUM isn't
      available in FRAME (i.e. if it wasn't saved)?  */
 
-  if (i386_fp_regnum_p (regnum))
+  if (i386_fp_regnum_p (gdbarch, regnum))
     {
       i387_register_to_value (frame, regnum, type, to);
       return;
@@ -1760,7 +2337,7 @@ i386_register_to_value (struct frame_info *frame, int regnum,
   while (len > 0)
     {
       gdb_assert (regnum != -1);
-      gdb_assert (register_size (current_gdbarch, regnum) == 4);
+      gdb_assert (register_size (gdbarch, regnum) == 4);
 
       get_frame_register (frame, regnum, to);
       regnum = i386_next_regnum (regnum);
@@ -1778,7 +2355,7 @@ i386_value_to_register (struct frame_info *frame, int regnum,
 {
   int len = TYPE_LENGTH (type);
 
-  if (i386_fp_regnum_p (regnum))
+  if (i386_fp_regnum_p (get_frame_arch (frame), regnum))
     {
       i387_value_to_register (frame, regnum, type, from);
       return;
@@ -1791,7 +2368,7 @@ i386_value_to_register (struct frame_info *frame, int regnum,
   while (len > 0)
     {
       gdb_assert (regnum != -1);
-      gdb_assert (register_size (current_gdbarch, regnum) == 4);
+      gdb_assert (register_size (get_frame_arch (frame), regnum) == 4);
 
       put_frame_register (frame, regnum, from);
       regnum = i386_next_regnum (regnum);
@@ -1919,32 +2496,6 @@ i386_regset_from_core_section (struct gdbarch *gdbarch,
 }
 \f
 
-#ifdef STATIC_TRANSFORM_NAME
-/* SunPRO encodes the static variables.  This is not related to C++
-   mangling, it is done for C too.  */
-
-char *
-sunpro_static_transform_name (char *name)
-{
-  char *p;
-  if (IS_STATIC_TRANSFORM_NAME (name))
-    {
-      /* For file-local statics there will be a period, a bunch of
-         junk (the contents of which match a string given in the
-         N_OPT), a period and the name.  For function-local statics
-         there will be a bunch of junk (which seems to change the
-         second character from 'A' to 'B'), a period, the name of the
-         function, and the name.  So just skip everything before the
-         last period.  */
-      p = strrchr (name, '.');
-      if (p != NULL)
-       name = p + 1;
-    }
-  return name;
-}
-#endif /* STATIC_TRANSFORM_NAME */
-\f
-
 /* Stuff for WIN32 PE style DLL's but is pretty generic really.  */
 
 CORE_ADDR
@@ -1968,13 +2519,13 @@ i386_pe_skip_trampoline_code (CORE_ADDR pc, char *name)
 }
 \f
 
-/* Return whether the frame preceding NEXT_FRAME corresponds to a
-   sigtramp routine.  */
+/* Return whether the THIS_FRAME corresponds to a sigtramp
+   routine.  */
 
-static int
-i386_sigtramp_p (struct frame_info *next_frame)
+int
+i386_sigtramp_p (struct frame_info *this_frame)
 {
-  CORE_ADDR pc = frame_pc_unwind (next_frame);
+  CORE_ADDR pc = get_frame_pc (this_frame);
   char *name;
 
   find_pc_partial_function (pc, &name, NULL, NULL);
@@ -1994,7 +2545,6 @@ i386_print_insn (bfd_vma pc, struct disassemble_info *info)
   /* FIXME: kettenis/20020915: Until disassembler_options is properly
      constified, cast to prevent a compiler warning.  */
   info->disassembler_options = (char *) disassembly_flavor;
-  info->mach = gdbarch_bfd_arch_info (current_gdbarch)->mach;
 
   return print_insn_i386 (pc, info);
 }
@@ -2007,13 +2557,13 @@ i386_print_insn (bfd_vma pc, struct disassemble_info *info)
 
 /* System V Release 4 (SVR4).  */
 
-/* Return whether the frame preceding NEXT_FRAME corresponds to a SVR4
-   sigtramp routine.  */
+/* Return whether THIS_FRAME corresponds to a SVR4 sigtramp
+   routine.  */
 
 static int
-i386_svr4_sigtramp_p (struct frame_info *next_frame)
+i386_svr4_sigtramp_p (struct frame_info *this_frame)
 {
-  CORE_ADDR pc = frame_pc_unwind (next_frame);
+  CORE_ADDR pc = get_frame_pc (this_frame);
   char *name;
 
   /* UnixWare uses _sigacthandler.  The origin of the other symbols is
@@ -2024,17 +2574,16 @@ i386_svr4_sigtramp_p (struct frame_info *next_frame)
                   || strcmp ("sigvechandler", name) == 0));
 }
 
-/* Assuming NEXT_FRAME is for a frame following a SVR4 sigtramp
-   routine, return the address of the associated sigcontext (ucontext)
-   structure.  */
+/* Assuming THIS_FRAME is for a SVR4 sigtramp routine, return the
+   address of the associated sigcontext (ucontext) structure.  */
 
 static CORE_ADDR
-i386_svr4_sigcontext_addr (struct frame_info *next_frame)
+i386_svr4_sigcontext_addr (struct frame_info *this_frame)
 {
   gdb_byte buf[4];
   CORE_ADDR sp;
 
-  frame_unwind_register (next_frame, I386_ESP_REGNUM, buf);
+  get_frame_register (this_frame, I386_ESP_REGNUM, buf);
   sp = extract_unsigned_integer (buf, 4);
 
   return read_memory_unsigned_integer (sp + 8, 4);
@@ -2082,16 +2631,17 @@ i386_go32_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   tdep->sigtramp_p = NULL;
 
   tdep->jb_pc_offset = 36;
-}
-
-/* NetWare.  */
 
-static void
-i386_nw_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
-{
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  /* DJGPP does not support the SSE registers.  */
+  tdep->num_xmm_regs = 0;
+  set_gdbarch_num_regs (gdbarch, I386_NUM_GREGS + I386_NUM_FREGS);
 
-  tdep->jb_pc_offset = 24;
+  /* Native compiler is GCC, which uses the SVR4 register numbering
+     even in COFF and STABS.  See the comment in i386_gdbarch_init,
+     before the calls to set_gdbarch_stab_reg_to_regnum and
+     set_gdbarch_sdb_reg_to_regnum.  */
+  set_gdbarch_stab_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
+  set_gdbarch_sdb_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
 }
 \f
 
@@ -2128,8 +2678,8 @@ i386_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
 {
   int sse_regnum_p = (i386_sse_regnum_p (gdbarch, regnum)
                      || i386_mxcsr_regnum_p (gdbarch, regnum));
-  int fp_regnum_p = (i386_fp_regnum_p (regnum)
-                    || i386_fpc_regnum_p (regnum));
+  int fp_regnum_p = (i386_fp_regnum_p (gdbarch, regnum)
+                    || i386_fpc_regnum_p (gdbarch, regnum));
   int mmx_regnum_p = (i386_mmx_regnum_p (gdbarch, regnum));
 
   if (group == i386_mmx_reggroup)
@@ -2157,161 +2707,2581 @@ i386_fetch_pointer_argument (struct frame_info *frame, int argi,
   return read_memory_unsigned_integer (sp + (4 * (argi + 1)), 4);
 }
 
-\f
-static struct gdbarch *
-i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+static void
+i386_skip_permanent_breakpoint (struct regcache *regcache)
 {
-  struct gdbarch_tdep *tdep;
-  struct gdbarch *gdbarch;
-
-  /* If there is already a candidate, use it.  */
-  arches = gdbarch_list_lookup_by_info (arches, &info);
-  if (arches != NULL)
-    return arches->gdbarch;
-
-  /* Allocate space for the new architecture.  */
-  tdep = XMALLOC (struct gdbarch_tdep);
-  gdbarch = gdbarch_alloc (&info, tdep);
+  CORE_ADDR current_pc = regcache_read_pc (regcache);
 
-  /* General-purpose registers.  */
-  tdep->gregset = NULL;
-  tdep->gregset_reg_offset = NULL;
-  tdep->gregset_num_regs = I386_NUM_GREGS;
-  tdep->sizeof_gregset = 0;
-
-  /* Floating-point registers.  */
-  tdep->fpregset = NULL;
-  tdep->sizeof_fpregset = I387_SIZEOF_FSAVE;
-
-  /* The default settings include the FPU registers, the MMX registers
-     and the SSE registers.  This can be overridden for a specific ABI
-     by adjusting the members `st0_regnum', `mm0_regnum' and
-     `num_xmm_regs' of `struct gdbarch_tdep', otherwise the registers
-     will show up in the output of "info all-registers".  Ideally we
-     should try to autodetect whether they are available, such that we
-     can prevent "info all-registers" from displaying registers that
-     aren't available.
+ /* On i386, breakpoint is exactly 1 byte long, so we just
+    adjust the PC in the regcache.  */
+  current_pc += 1;
+  regcache_write_pc (regcache, current_pc);
+}
 
-     NOTE: kevinb/2003-07-13: ... if it's a choice between printing
-     [the SSE registers] always (even when they don't exist) or never
-     showing them to the user (even when they do exist), I prefer the
-     former over the latter.  */
 
-  tdep->st0_regnum = I386_ST0_REGNUM;
+#define PREFIX_REPZ    0x01
+#define PREFIX_REPNZ   0x02
+#define PREFIX_LOCK    0x04
+#define PREFIX_DATA    0x08
+#define PREFIX_ADDR    0x10
 
-  /* The MMX registers are implemented as pseudo-registers.  Put off
-     calculating the register number for %mm0 until we know the number
-     of raw registers.  */
-  tdep->mm0_regnum = 0;
+/* operand size */
+enum
+{
+  OT_BYTE = 0,
+  OT_WORD,
+  OT_LONG,
+};
 
-  /* I386_NUM_XREGS includes %mxcsr, so substract one.  */
-  tdep->num_xmm_regs = I386_NUM_XREGS - 1;
+/* i386 arith/logic operations */
+enum
+{
+  OP_ADDL,
+  OP_ORL,
+  OP_ADCL,
+  OP_SBBL,
+  OP_ANDL,
+  OP_SUBL,
+  OP_XORL,
+  OP_CMPL,
+};
 
-  tdep->jb_pc_offset = -1;
-  tdep->struct_return = pcc_struct_return;
-  tdep->sigtramp_start = 0;
-  tdep->sigtramp_end = 0;
-  tdep->sigtramp_p = i386_sigtramp_p;
-  tdep->sigcontext_addr = NULL;
-  tdep->sc_reg_offset = NULL;
-  tdep->sc_pc_offset = -1;
-  tdep->sc_sp_offset = -1;
+struct i386_record_s
+{
+  struct regcache *regcache;
+  CORE_ADDR addr;
+  int aflag;
+  int dflag;
+  int override;
+  uint8_t modrm;
+  uint8_t mod, reg, rm;
+  int ot;
+};
 
-  /* The format used for `long double' on almost all i386 targets is
-     the i387 extended floating-point format.  In fact, of all targets
-     in the GCC 2.95 tree, only OSF/1 does it different, and insists
-     on having a `long double' that's not `long' at all.  */
-  set_gdbarch_long_double_format (gdbarch, &floatformat_i387_ext);
+/* Parse "modrm" part in current memory address that irp->addr point to
+   Return -1 if something wrong. */
 
-  /* Although the i387 extended floating-point has only 80 significant
-     bits, a `long double' actually takes up 96, probably to enforce
-     alignment.  */
-  set_gdbarch_long_double_bit (gdbarch, 96);
+static int
+i386_record_modrm (struct i386_record_s *irp)
+{
+  if (target_read_memory (irp->addr, &irp->modrm, 1))
+    {
+      if (record_debug)
+       printf_unfiltered (_("Process record: error reading memory at "
+                            "addr 0x%s len = 1.\n"),
+                          paddr_nz (irp->addr));
+      return -1;
+    }
+  irp->addr++;
+  irp->mod = (irp->modrm >> 6) & 3;
+  irp->reg = (irp->modrm >> 3) & 7;
+  irp->rm = irp->modrm & 7;
 
-  /* The default ABI includes general-purpose registers, 
-     floating-point registers, and the SSE registers.  */
-  set_gdbarch_num_regs (gdbarch, I386_SSE_NUM_REGS);
-  set_gdbarch_register_name (gdbarch, i386_register_name);
-  set_gdbarch_register_type (gdbarch, i386_register_type);
+  return 0;
+}
 
-  /* Register numbers of various important registers.  */
-  set_gdbarch_sp_regnum (gdbarch, I386_ESP_REGNUM); /* %esp */
-  set_gdbarch_pc_regnum (gdbarch, I386_EIP_REGNUM); /* %eip */
-  set_gdbarch_ps_regnum (gdbarch, I386_EFLAGS_REGNUM); /* %eflags */
-  set_gdbarch_fp0_regnum (gdbarch, I386_ST0_REGNUM); /* %st(0) */
+/* Get the memory address that current instruction  write to and set it to
+   the argument "addr".
+   Return -1 if something wrong. */
 
-  /* NOTE: kettenis/20040418: GCC does have two possible register
-     numbering schemes on the i386: dbx and SVR4.  These schemes
-     differ in how they number %ebp, %esp, %eflags, and the
-     floating-point registers, and are implemented by the arrays
-     dbx_register_map[] and svr4_dbx_register_map in
-     gcc/config/i386.c.  GCC also defines a third numbering scheme in
-     gcc/config/i386.c, which it designates as the "default" register
-     map used in 64bit mode.  This last register numbering scheme is
-     implemented in dbx64_register_map, and is used for AMD64; see
-     amd64-tdep.c.
+static int
+i386_record_lea_modrm_addr (struct i386_record_s *irp, uint32_t * addr)
+{
+  uint8_t tmpu8;
+  uint16_t tmpu16;
+  uint32_t tmpu32;
 
-     Currently, each GCC i386 target always uses the same register
-     numbering scheme across all its supported debugging formats
-     i.e. SDB (COFF), stabs and DWARF 2.  This is because
-     gcc/sdbout.c, gcc/dbxout.c and gcc/dwarf2out.c all use the
-     DBX_REGISTER_NUMBER macro which is defined by each target's
-     respective config header in a manner independent of the requested
-     output debugging format.
+  *addr = 0;
+  if (irp->aflag)
+    {
+      /* 32 bits */
+      int havesib = 0;
+      uint8_t scale = 0;
+      uint8_t index = 0;
+      uint8_t base = irp->rm;
 
-     This does not match the arrangement below, which presumes that
-     the SDB and stabs numbering schemes differ from the DWARF and
-     DWARF 2 ones.  The reason for this arrangement is that it is
-     likely to get the numbering scheme for the target's
-     default/native debug format right.  For targets where GCC is the
-     native compiler (FreeBSD, NetBSD, OpenBSD, GNU/Linux) or for
-     targets where the native toolchain uses a different numbering
-     scheme for a particular debug format (stabs-in-ELF on Solaris)
-     the defaults below will have to be overridden, like
-     i386_elf_init_abi() does.  */
+      if (base == 4)
+       {
+         havesib = 1;
+         if (target_read_memory (irp->addr, &tmpu8, 1))
+           {
+             if (record_debug)
+               printf_unfiltered (_("Process record: error reading memory "
+                                    "at addr 0x%s len = 1.\n"),
+                                  paddr_nz (irp->addr));
+             return -1;
+           }
+         irp->addr++;
+         scale = (tmpu8 >> 6) & 3;
+         index = ((tmpu8 >> 3) & 7);
+         base = (tmpu8 & 7);
+       }
 
-  /* Use the dbx register numbering scheme for stabs and COFF.  */
-  set_gdbarch_stab_reg_to_regnum (gdbarch, i386_dbx_reg_to_regnum);
-  set_gdbarch_sdb_reg_to_regnum (gdbarch, i386_dbx_reg_to_regnum);
+      switch (irp->mod)
+       {
+       case 0:
+         if ((base & 7) == 5)
+           {
+             base = 0xff;
+             if (target_read_memory (irp->addr, (gdb_byte *) addr, 4))
+               {
+                 if (record_debug)
+                   printf_unfiltered (_("Process record: error reading "
+                                        "memory at addr 0x%s len = 4.\n"),
+                                      paddr_nz (irp->addr));
+                 return -1;
+               }
+             irp->addr += 4;
+           }
+         else
+           {
+             *addr = 0;
+           }
+         break;
+       case 1:
+         if (target_read_memory (irp->addr, &tmpu8, 1))
+           {
+             if (record_debug)
+               printf_unfiltered (_("Process record: error reading memory "
+                                    "at addr 0x%s len = 1.\n"),
+                                  paddr_nz (irp->addr));
+             return -1;
+           }
+         irp->addr++;
+         *addr = (int8_t) tmpu8;
+         break;
+       case 2:
+         if (target_read_memory (irp->addr, (gdb_byte *) addr, 4))
+           {
+             if (record_debug)
+               printf_unfiltered (_("Process record: error reading memory "
+                                    "at addr 0x%s len = 4.\n"),
+                                  paddr_nz (irp->addr));
+             return -1;
+           }
+         irp->addr += 4;
+         break;
+       }
 
-  /* Use the SVR4 register numbering scheme for DWARF and DWARF 2.  */
-  set_gdbarch_dwarf_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
-  set_gdbarch_dwarf2_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
+      if (base != 0xff)
+       {
+         regcache_raw_read (irp->regcache, base, (gdb_byte *) & tmpu32);
+         *addr += tmpu32;
+       }
 
-  /* We don't define ECOFF_REG_TO_REGNUM, since ECOFF doesn't seem to
-     be in use on any of the supported i386 targets.  */
+      /* XXX: index == 4 is always invalid */
+      if (havesib && (index != 4 || scale != 0))
+       {
+         regcache_raw_read (irp->regcache, index, (gdb_byte *) & tmpu32);
+         *addr += tmpu32 << scale;
+       }
+    }
+  else
+    {
+      /* 16 bits */
+      switch (irp->mod)
+       {
+       case 0:
+         if (irp->rm == 6)
+           {
+             if (target_read_memory
+                 (irp->addr, (gdb_byte *) & tmpu16, 2))
+               {
+                 if (record_debug)
+                   printf_unfiltered (_("Process record: error reading "
+                                        "memory at addr 0x%s len = 2.\n"),
+                                      paddr_nz (irp->addr));
+                 return -1;
+               }
+             irp->addr += 2;
+             *addr = (int16_t) tmpu16;
+             irp->rm = 0;
+             goto no_rm;
+           }
+         else
+           {
+             *addr = 0;
+           }
+         break;
+       case 1:
+         if (target_read_memory (irp->addr, &tmpu8, 1))
+           {
+             if (record_debug)
+               printf_unfiltered (_("Process record: error reading memory "
+                                    "at addr 0x%s len = 1.\n"),
+                                  paddr_nz (irp->addr));
+             return -1;
+           }
+         irp->addr++;
+         *addr = (int8_t) tmpu8;
+         break;
+       case 2:
+         if (target_read_memory (irp->addr, (gdb_byte *) & tmpu16, 2))
+           {
+             if (record_debug)
+               printf_unfiltered (_("Process record: error reading memory "
+                                    "at addr 0x%s len = 2.\n"),
+                                  paddr_nz (irp->addr));
+             return -1;
+           }
+         irp->addr += 2;
+         *addr = (int16_t) tmpu16;
+         break;
+       }
 
-  set_gdbarch_print_float_info (gdbarch, i387_print_float_info);
+      switch (irp->rm)
+       {
+       case 0:
+         regcache_raw_read (irp->regcache, I386_EBX_REGNUM,
+                            (gdb_byte *) & tmpu32);
+         *addr += tmpu32;
+         regcache_raw_read (irp->regcache, I386_ESI_REGNUM,
+                            (gdb_byte *) & tmpu32);
+         *addr += tmpu32;
+         break;
+       case 1:
+         regcache_raw_read (irp->regcache, I386_EBX_REGNUM,
+                            (gdb_byte *) & tmpu32);
+         *addr += tmpu32;
+         regcache_raw_read (irp->regcache, I386_EDI_REGNUM,
+                            (gdb_byte *) & tmpu32);
+         *addr += tmpu32;
+         break;
+       case 2:
+         regcache_raw_read (irp->regcache, I386_EBP_REGNUM,
+                            (gdb_byte *) & tmpu32);
+         *addr += tmpu32;
+         regcache_raw_read (irp->regcache, I386_ESI_REGNUM,
+                            (gdb_byte *) & tmpu32);
+         *addr += tmpu32;
+         break;
+       case 3:
+         regcache_raw_read (irp->regcache, I386_EBP_REGNUM,
+                            (gdb_byte *) & tmpu32);
+         *addr += tmpu32;
+         regcache_raw_read (irp->regcache, I386_EDI_REGNUM,
+                            (gdb_byte *) & tmpu32);
+         *addr += tmpu32;
+         break;
+       case 4:
+         regcache_raw_read (irp->regcache, I386_ESI_REGNUM,
+                            (gdb_byte *) & tmpu32);
+         *addr += tmpu32;
+         break;
+       case 5:
+         regcache_raw_read (irp->regcache, I386_EDI_REGNUM,
+                            (gdb_byte *) & tmpu32);
+         *addr += tmpu32;
+         break;
+       case 6:
+         regcache_raw_read (irp->regcache, I386_EBP_REGNUM,
+                            (gdb_byte *) & tmpu32);
+         *addr += tmpu32;
+         break;
+       case 7:
+         regcache_raw_read (irp->regcache, I386_EBX_REGNUM,
+                            (gdb_byte *) & tmpu32);
+         *addr += tmpu32;
+         break;
+       }
+      *addr &= 0xffff;
+    }
 
-  set_gdbarch_get_longjmp_target (gdbarch, i386_get_longjmp_target);
+no_rm:
+  return 0;
+}
 
-  /* Call dummy code.  */
-  set_gdbarch_push_dummy_call (gdbarch, i386_push_dummy_call);
+/* Record the value of the memory that willbe changed in current instruction
+   to "record_arch_list".
+   Return -1 if something wrong. */
 
-  set_gdbarch_convert_register_p (gdbarch, i386_convert_register_p);
-  set_gdbarch_register_to_value (gdbarch,  i386_register_to_value);
-  set_gdbarch_value_to_register (gdbarch, i386_value_to_register);
+static int
+i386_record_lea_modrm (struct i386_record_s *irp)
+{
+  uint32_t addr;
 
-  set_gdbarch_return_value (gdbarch, i386_return_value);
+  if (irp->override)
+    {
+      if (record_debug)
+       printf_unfiltered (_("Process record ignores the memory change "
+                            "of instruction at address 0x%s because it "
+                            "can't get the value of the segment register.\n"),
+                          paddr_nz (irp->addr));
+      return 0;
+    }
 
-  set_gdbarch_skip_prologue (gdbarch, i386_skip_prologue);
+  if (i386_record_lea_modrm_addr (irp, &addr))
+    return -1;
 
-  /* Stack grows downward.  */
-  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  if (record_arch_list_add_mem (addr, 1 << irp->ot))
+    return -1;
 
-  set_gdbarch_breakpoint_from_pc (gdbarch, i386_breakpoint_from_pc);
-  set_gdbarch_decr_pc_after_break (gdbarch, 1);
+  return 0;
+}
 
-  set_gdbarch_frame_args_skip (gdbarch, 8);
+/* Parse the current instruction and record the values of the registers and
+   memory that will be changed in current instruction to "record_arch_list".
+   Return -1 if something wrong. */
 
-  /* Wire in the MMX registers.  */
-  set_gdbarch_num_pseudo_regs (gdbarch, i386_num_mmx_regs);
-  set_gdbarch_pseudo_register_read (gdbarch, i386_pseudo_register_read);
-  set_gdbarch_pseudo_register_write (gdbarch, i386_pseudo_register_write);
+int
+i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
+                    CORE_ADDR addr)
+{
+  int prefixes = 0;
+  uint8_t tmpu8;
+  uint16_t tmpu16;
+  uint32_t tmpu32;
+  uint32_t opcode;
+  struct i386_record_s ir;
+
+  memset (&ir, 0, sizeof (struct i386_record_s));
+  ir.regcache = regcache;
+  ir.addr = addr;
+  ir.aflag = 1;
+  ir.dflag = 1;
+
+  if (record_debug > 1)
+    fprintf_unfiltered (gdb_stdlog, "Process record: i386_process_record "
+                                   "addr = 0x%s\n",
+                       paddr_nz (ir.addr));
+
+  /* prefixes */
+  while (1)
+    {
+      if (target_read_memory (ir.addr, &tmpu8, 1))
+       {
+         if (record_debug)
+           printf_unfiltered (_("Process record: error reading memory at "
+                                "addr 0x%s len = 1.\n"),
+                              paddr_nz (ir.addr));
+         return -1;
+       }
+      ir.addr++;
+      switch (tmpu8)
+       {
+       case 0xf3:
+         prefixes |= PREFIX_REPZ;
+         break;
+       case 0xf2:
+         prefixes |= PREFIX_REPNZ;
+         break;
+       case 0xf0:
+         prefixes |= PREFIX_LOCK;
+         break;
+       case 0x2e:
+         ir.override = I386_CS_REGNUM;
+         break;
+       case 0x36:
+         ir.override = I386_SS_REGNUM;
+         break;
+       case 0x3e:
+         ir.override = I386_DS_REGNUM;
+         break;
+       case 0x26:
+         ir.override = I386_ES_REGNUM;
+         break;
+       case 0x64:
+         ir.override = I386_FS_REGNUM;
+         break;
+       case 0x65:
+         ir.override = I386_GS_REGNUM;
+         break;
+       case 0x66:
+         prefixes |= PREFIX_DATA;
+         break;
+       case 0x67:
+         prefixes |= PREFIX_ADDR;
+         break;
+       default:
+         goto out_prefixes;
+         break;
+       }
+    }
+out_prefixes:
+  if (prefixes & PREFIX_DATA)
+    ir.dflag ^= 1;
+  if (prefixes & PREFIX_ADDR)
+    ir.aflag ^= 1;
+
+  /* now check op code */
+  opcode = (uint32_t) tmpu8;
+reswitch:
+  switch (opcode)
+    {
+    case 0x0f:
+      if (target_read_memory (ir.addr, &tmpu8, 1))
+       {
+         if (record_debug)
+           printf_unfiltered (_("Process record: error reading memory at "
+                                "addr 0x%s len = 1.\n"),
+                              paddr_nz (ir.addr));
+         return -1;
+       }
+      ir.addr++;
+      opcode = (uint16_t) tmpu8 | 0x0f00;
+      goto reswitch;
+      break;
+
+      /* arith & logic */
+    case 0x00:
+    case 0x01:
+    case 0x02:
+    case 0x03:
+    case 0x04:
+    case 0x05:
+    case 0x08:
+    case 0x09:
+    case 0x0a:
+    case 0x0b:
+    case 0x0c:
+    case 0x0d:
+    case 0x10:
+    case 0x11:
+    case 0x12:
+    case 0x13:
+    case 0x14:
+    case 0x15:
+    case 0x18:
+    case 0x19:
+    case 0x1a:
+    case 0x1b:
+    case 0x1c:
+    case 0x1d:
+    case 0x20:
+    case 0x21:
+    case 0x22:
+    case 0x23:
+    case 0x24:
+    case 0x25:
+    case 0x28:
+    case 0x29:
+    case 0x2a:
+    case 0x2b:
+    case 0x2c:
+    case 0x2d:
+    case 0x30:
+    case 0x31:
+    case 0x32:
+    case 0x33:
+    case 0x34:
+    case 0x35:
+    case 0x38:
+    case 0x39:
+    case 0x3a:
+    case 0x3b:
+    case 0x3c:
+    case 0x3d:
+      if (((opcode >> 3) & 7) != OP_CMPL)
+       {
+         if ((opcode & 1) == 0)
+           ir.ot = OT_BYTE;
+         else
+           ir.ot = ir.dflag + OT_WORD;
+
+         switch ((opcode >> 1) & 3)
+           {
+             /* OP Ev, Gv */
+           case 0:
+             if (i386_record_modrm (&ir))
+               return -1;
+             if (ir.mod != 3)
+               {
+                 if (i386_record_lea_modrm (&ir))
+                   return -1;
+               }
+             else
+               {
+                 if (ir.ot == OT_BYTE)
+                   ir.rm &= 0x3;
+                 if (record_arch_list_add_reg (ir.regcache, ir.rm))
+                   return -1;
+               }
+             break;
+             /* OP Gv, Ev */
+           case 1:
+             if (i386_record_modrm (&ir))
+               return -1;
+             if (ir.ot == OT_BYTE)
+               ir.reg &= 0x3;
+             if (record_arch_list_add_reg (ir.regcache, ir.reg))
+               return -1;
+             break;
+             /* OP A, Iv */
+           case 2:
+             if (record_arch_list_add_reg (ir.regcache, I386_EAX_REGNUM))
+               return -1;
+             break;
+           }
+       }
+      if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+       return -1;
+      break;
+
+      /* GRP1 */
+    case 0x80:
+    case 0x81:
+    case 0x82:
+    case 0x83:
+      if (i386_record_modrm (&ir))
+       return -1;
+
+      if (ir.reg != OP_CMPL)
+       {
+         if ((opcode & 1) == 0)
+           ir.ot = OT_BYTE;
+         else
+           ir.ot = ir.dflag + OT_WORD;
+
+         if (ir.mod != 3)
+           {
+             if (i386_record_lea_modrm (&ir))
+               return -1;
+           }
+         else
+           {
+             if (record_arch_list_add_reg (ir.regcache, ir.rm))
+               return -1;
+           }
+       }
+      if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+       return -1;
+      break;
+
+      /* inv */
+    case 0x40:
+    case 0x41:
+    case 0x42:
+    case 0x43:
+    case 0x44:
+    case 0x45:
+    case 0x46:
+    case 0x47:
+      /* dec */
+    case 0x48:
+    case 0x49:
+    case 0x4a:
+    case 0x4b:
+    case 0x4c:
+    case 0x4d:
+    case 0x4e:
+    case 0x4f:
+      if (record_arch_list_add_reg (ir.regcache, opcode & 7))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+       return -1;
+      break;
+
+      /* GRP3 */
+    case 0xf6:
+    case 0xf7:
+      if ((opcode & 1) == 0)
+       ir.ot = OT_BYTE;
+      else
+       ir.ot = ir.dflag + OT_WORD;
+      if (i386_record_modrm (&ir))
+       return -1;
+
+      switch (ir.reg)
+       {
+         /* test */
+       case 0:
+         if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+           return -1;
+         break;
+         /* not */
+       case 2:
+         if (ir.mod != 3)
+           {
+             if (i386_record_lea_modrm (&ir))
+               return -1;
+           }
+         else
+           {
+             if (ir.ot == OT_BYTE)
+               ir.rm &= 0x3;
+             if (record_arch_list_add_reg (ir.regcache, ir.rm))
+               return -1;
+           }
+         break;
+         /* neg */
+       case 3:
+         if (ir.mod != 3)
+           {
+             if (i386_record_lea_modrm (&ir))
+               return -1;
+           }
+         else
+           {
+             if (ir.ot == OT_BYTE)
+               ir.rm &= 0x3;
+             if (record_arch_list_add_reg (ir.regcache, ir.rm))
+               return -1;
+           }
+         if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+           return -1;
+         break;
+         /* mul */
+       case 4:
+         /* imul */
+       case 5:
+         /* div */
+       case 6:
+         /* idiv */
+       case 7:
+         if (record_arch_list_add_reg (ir.regcache, I386_EAX_REGNUM))
+           return -1;
+         if (ir.ot != OT_BYTE)
+           {
+             if (record_arch_list_add_reg (ir.regcache, I386_EDX_REGNUM))
+               return -1;
+           }
+         if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+           return -1;
+         break;
+       default:
+         ir.addr -= 2;
+         opcode = opcode << 8 | ir.modrm;
+         goto no_support;
+         break;
+       }
+      break;
+
+      /* GRP4 */
+    case 0xfe:
+      /* GRP5 */
+    case 0xff:
+      if ((opcode & 1) == 0)
+       ir.ot = OT_BYTE;
+      else
+       ir.ot = ir.dflag + OT_WORD;
+      if (i386_record_modrm (&ir))
+       return -1;
+      if (ir.reg >= 2 && opcode == 0xfe)
+       {
+         ir.addr -= 2;
+         opcode = opcode << 8 | ir.modrm;
+         goto no_support;
+       }
+
+      switch (ir.reg)
+       {
+         /* inc */
+       case 0:
+         /* dec */
+       case 1:
+         if (ir.mod != 3)
+           {
+             if (i386_record_lea_modrm (&ir))
+               return -1;
+           }
+         else
+           {
+             if (ir.ot == OT_BYTE)
+               ir.rm &= 0x3;
+             if (record_arch_list_add_reg (ir.regcache, ir.rm))
+               return -1;
+           }
+         if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+           return -1;
+         break;
+         /* call */
+       case 2:
+         /* push */
+       case 6:
+         if (record_arch_list_add_reg (ir.regcache, I386_ESP_REGNUM))
+           return -1;
+         regcache_raw_read (ir.regcache, I386_ESP_REGNUM,
+                            (gdb_byte *) & tmpu32);
+         if (record_arch_list_add_mem
+             ((CORE_ADDR) tmpu32 - (1 << (ir.dflag + 1)), (1 << (ir.dflag + 1))))
+           return -1;
+         break;
+         /* lcall */
+       case 3:
+         if (record_arch_list_add_reg (ir.regcache, I386_ESP_REGNUM))
+           return -1;
+         if (record_arch_list_add_reg (ir.regcache, I386_CS_REGNUM))
+           return -1;
+         regcache_raw_read (ir.regcache, I386_ESP_REGNUM,
+                            (gdb_byte *) & tmpu32);
+         if (record_arch_list_add_mem
+             ((CORE_ADDR) tmpu32 - (1 << (ir.dflag + 2)), (1 << (ir.dflag + 2))))
+           return -1;
+         break;
+         /* jmp */
+       case 4:
+         /* ljmp */
+       case 5:
+         break;
+       default:
+         ir.addr -= 2;
+         opcode = opcode << 8 | ir.modrm;
+         goto no_support;
+         break;
+       }
+      break;
+
+      /* test */
+    case 0x84:
+    case 0x85:
+    case 0xa8:
+    case 0xa9:
+      if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+       return -1;
+      break;
+
+      /* CWDE/CBW */
+    case 0x98:
+      if (record_arch_list_add_reg (ir.regcache, I386_EAX_REGNUM))
+       return -1;
+      break;
+
+      /* CDQ/CWD */
+    case 0x99:
+      if (record_arch_list_add_reg (ir.regcache, I386_EAX_REGNUM))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, I386_EDX_REGNUM))
+       return -1;
+      break;
+
+      /* imul */
+    case 0x0faf:
+    case 0x69:
+    case 0x6b:
+      ir.ot = ir.dflag + OT_WORD;
+      if (i386_record_modrm (&ir))
+       return -1;
+      if (ir.ot == OT_BYTE)
+       ir.reg &= 0x3;
+      if (record_arch_list_add_reg (ir.regcache, ir.reg))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+       return -1;
+      break;
+
+      /* xadd */
+    case 0x0fc0:
+    case 0x0fc1:
+      if ((opcode & 1) == 0)
+       ir.ot = OT_BYTE;
+      else
+       ir.ot = ir.dflag + OT_WORD;
+      if (i386_record_modrm (&ir))
+       return -1;
+      if (ir.mod == 3)
+       {
+         if (ir.ot == OT_BYTE)
+           ir.reg &= 0x3;
+         if (record_arch_list_add_reg (ir.regcache, ir.reg))
+           return -1;
+         if (ir.ot == OT_BYTE)
+           ir.rm &= 0x3;
+         if (record_arch_list_add_reg (ir.regcache, ir.rm))
+           return -1;
+       }
+      else
+       {
+         if (i386_record_lea_modrm (&ir))
+           return -1;
+         if (ir.ot == OT_BYTE)
+           ir.reg &= 0x3;
+         if (record_arch_list_add_reg (ir.regcache, ir.reg))
+           return -1;
+       }
+      if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+       return -1;
+      break;
+
+      /* cmpxchg */
+    case 0x0fb0:
+    case 0x0fb1:
+      if ((opcode & 1) == 0)
+       ir.ot = OT_BYTE;
+      else
+       ir.ot = ir.dflag + OT_WORD;
+      if (i386_record_modrm (&ir))
+       return -1;
+      if (ir.mod == 3)
+       {
+         if (record_arch_list_add_reg (ir.regcache, I386_EAX_REGNUM))
+           return -1;
+         if (ir.ot == OT_BYTE)
+           ir.reg &= 0x3;
+         if (record_arch_list_add_reg (ir.regcache, ir.reg))
+           return -1;
+       }
+      else
+       {
+         if (record_arch_list_add_reg (ir.regcache, I386_EAX_REGNUM))
+           return -1;
+         if (i386_record_lea_modrm (&ir))
+           return -1;
+       }
+      if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+       return -1;
+      break;
+
+      /* cmpxchg8b */
+    case 0x0fc7:
+      if (i386_record_modrm (&ir))
+       return -1;
+      if (ir.mod == 3)
+       {
+         ir.addr -= 2;
+         opcode = opcode << 8 | ir.modrm;
+         goto no_support;
+       }
+      if (record_arch_list_add_reg (ir.regcache, I386_EAX_REGNUM))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, I386_EDX_REGNUM))
+       return -1;
+      if (i386_record_lea_modrm (&ir))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+       return -1;
+      break;
+
+      /* push */
+    case 0x50:
+    case 0x51:
+    case 0x52:
+    case 0x53:
+    case 0x54:
+    case 0x55:
+    case 0x56:
+    case 0x57:
+    case 0x68:
+    case 0x6a:
+      /* push es */
+    case 0x06:
+      /* push cs */
+    case 0x0e:
+      /* push ss */
+    case 0x16:
+      /* push ds */
+    case 0x1e:
+      /* push fs */
+    case 0x0fa0:
+      /* push gs */
+    case 0x0fa8:
+      if (record_arch_list_add_reg (ir.regcache, I386_ESP_REGNUM))
+       return -1;
+      regcache_raw_read (ir.regcache, I386_ESP_REGNUM,
+                        (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem
+         ((CORE_ADDR) tmpu32 - (1 << (ir.dflag + 1)), (1 << (ir.dflag + 1))))
+       return -1;
+      break;
+
+      /* pop */
+    case 0x58:
+    case 0x59:
+    case 0x5a:
+    case 0x5b:
+    case 0x5c:
+    case 0x5d:
+    case 0x5e:
+    case 0x5f:
+      ir.ot = ir.dflag + OT_WORD;
+      if (record_arch_list_add_reg (ir.regcache, I386_ESP_REGNUM))
+       return -1;
+      if (ir.ot == OT_BYTE)
+       opcode &= 0x3;
+      if (record_arch_list_add_reg (ir.regcache, opcode & 0x7))
+       return -1;
+      break;
+
+      /* pusha */
+    case 0x60:
+      if (record_arch_list_add_reg (ir.regcache, I386_ESP_REGNUM))
+       return -1;
+      regcache_raw_read (ir.regcache, I386_ESP_REGNUM,
+                        (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem
+         ((CORE_ADDR) tmpu32 - (1 << (ir.dflag + 4)), (1 << (ir.dflag + 4))))
+       return -1;
+      break;
+
+      /* popa */
+    case 0x61:
+      for (tmpu8 = I386_EAX_REGNUM; tmpu8 <= I386_EDI_REGNUM; tmpu8++)
+       {
+         if (record_arch_list_add_reg (ir.regcache, tmpu8))
+           return -1;
+       }
+      break;
+
+      /* pop */
+    case 0x8f:
+      ir.ot = ir.dflag + OT_WORD;
+      if (i386_record_modrm (&ir))
+       return -1;
+      if (ir.mod == 3)
+       {
+         if (record_arch_list_add_reg (ir.regcache, ir.rm))
+           return -1;
+       }
+      else
+       {
+         if (i386_record_lea_modrm (&ir))
+           return -1;
+       }
+      if (record_arch_list_add_reg (ir.regcache, I386_ESP_REGNUM))
+       return -1;
+      break;
+
+      /* enter */
+    case 0xc8:
+      if (record_arch_list_add_reg (ir.regcache, I386_ESP_REGNUM))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, I386_EBP_REGNUM))
+       return -1;
+      regcache_raw_read (ir.regcache, I386_ESP_REGNUM,
+                        (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem
+         ((CORE_ADDR) tmpu32 - (1 << (ir.dflag + 1)), (1 << (ir.dflag + 1))))
+       return -1;
+      break;
+
+      /* leave */
+    case 0xc9:
+      if (record_arch_list_add_reg (ir.regcache, I386_ESP_REGNUM))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, I386_EBP_REGNUM))
+       return -1;
+      break;
+
+      /* pop es */
+    case 0x07:
+      if (record_arch_list_add_reg (ir.regcache, I386_ESP_REGNUM))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, I386_ES_REGNUM))
+       return -1;
+      break;
+
+      /* pop ss */
+    case 0x17:
+      if (record_arch_list_add_reg (ir.regcache, I386_ESP_REGNUM))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, I386_SS_REGNUM))
+       return -1;
+      break;
+
+      /* pop ds */
+    case 0x1f:
+      if (record_arch_list_add_reg (ir.regcache, I386_ESP_REGNUM))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, I386_DS_REGNUM))
+       return -1;
+      break;
+
+      /* pop fs */
+    case 0x0fa1:
+      if (record_arch_list_add_reg (ir.regcache, I386_ESP_REGNUM))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, I386_FS_REGNUM))
+       return -1;
+      break;
+
+      /* pop gs */
+    case 0x0fa9:
+      if (record_arch_list_add_reg (ir.regcache, I386_ESP_REGNUM))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, I386_GS_REGNUM))
+       return -1;
+      break;
+
+      /* mov */
+    case 0x88:
+    case 0x89:
+    case 0xc6:
+    case 0xc7:
+      if ((opcode & 1) == 0)
+       ir.ot = OT_BYTE;
+      else
+       ir.ot = ir.dflag + OT_WORD;
+
+      if (i386_record_modrm (&ir))
+       return -1;
+
+      if (ir.mod != 3)
+       {
+         if (i386_record_lea_modrm (&ir))
+           return -1;
+       }
+      else
+       {
+         if (ir.ot == OT_BYTE)
+           ir.rm &= 0x3;
+         if (record_arch_list_add_reg (ir.regcache, ir.rm))
+           return -1;
+       }
+      if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+       return -1;
+      break;
+      /* mov */
+    case 0x8a:
+    case 0x8b:
+      if ((opcode & 1) == 0)
+       ir.ot = OT_BYTE;
+      else
+       ir.ot = ir.dflag + OT_WORD;
+
+      if (i386_record_modrm (&ir))
+       return -1;
+
+      if (ir.ot == OT_BYTE)
+       ir.reg &= 0x3;
+      if (record_arch_list_add_reg (ir.regcache, ir.reg))
+       return -1;
+
+      if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+       return -1;
+      break;
+
+      /* mov seg */
+    case 0x8e:
+      if (i386_record_modrm (&ir))
+       return -1;
+
+      switch (ir.reg)
+       {
+       case 0:
+         tmpu8 = I386_ES_REGNUM;
+         break;
+       case 2:
+         tmpu8 = I386_SS_REGNUM;
+         break;
+       case 3:
+         tmpu8 = I386_DS_REGNUM;
+         break;
+       case 4:
+         tmpu8 = I386_FS_REGNUM;
+         break;
+       case 5:
+         tmpu8 = I386_GS_REGNUM;
+         break;
+       default:
+         ir.addr -= 2;
+         opcode = opcode << 8 | ir.modrm;
+         goto no_support;
+         break;
+       }
+      if (record_arch_list_add_reg (ir.regcache, tmpu8))
+       return -1;
+
+      if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+       return -1;
+      break;
+
+      /* mov seg */
+    case 0x8c:
+      if (i386_record_modrm (&ir))
+       return -1;
+      if (ir.reg > 5)
+       {
+         ir.addr -= 2;
+         opcode = opcode << 8 | ir.modrm;
+         goto no_support;
+       }
+
+      if (ir.mod == 3)
+       {
+         if (record_arch_list_add_reg (ir.regcache, ir.rm))
+           return -1;
+       }
+      else
+       {
+         ir.ot = OT_WORD;
+         if (i386_record_lea_modrm (&ir))
+           return -1;
+       }
+
+      if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+       return -1;
+      break;
+
+      /* movzbS */
+    case 0x0fb6:
+      /* movzwS */
+    case 0x0fb7:
+      /* movsbS */
+    case 0x0fbe:
+      /* movswS */
+    case 0x0fbf:
+      if (i386_record_modrm (&ir))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, ir.reg))
+       return -1;
+      break;
+
+      /* lea */
+    case 0x8d:
+      if (i386_record_modrm (&ir))
+       return -1;
+      if (ir.mod == 3)
+       {
+         ir.addr -= 2;
+         opcode = opcode << 8 | ir.modrm;
+         goto no_support;
+       }
+
+      ir.ot = ir.dflag;
+      if (ir.ot == OT_BYTE)
+       ir.reg &= 0x3;
+      if (record_arch_list_add_reg (ir.regcache, ir.reg))
+       return -1;
+      break;
+
+      /* mov EAX */
+    case 0xa0:
+    case 0xa1:
+      /* xlat */
+    case 0xd7:
+      if (record_arch_list_add_reg (ir.regcache, I386_EAX_REGNUM))
+       return -1;
+      break;
+
+      /* mov EAX */
+    case 0xa2:
+    case 0xa3:
+      {
+       uint32_t addr;
+
+       if (ir.override)
+         {
+           if (record_debug)
+             printf_unfiltered (_("Process record ignores the memory change "
+                                  "of instruction at address 0x%s because "
+                                  "it can't get the value of the segment "
+                                  "register.\n"),
+                                paddr_nz (ir.addr));
+         }
+       else
+         {
+           if ((opcode & 1) == 0)
+             ir.ot = OT_BYTE;
+           else
+             ir.ot = ir.dflag + OT_WORD;
+           if (ir.aflag)
+             {
+               if (target_read_memory
+                   (ir.addr, (gdb_byte *) & addr, 4))
+                 {
+                   if (record_debug)
+                     printf_unfiltered (_("Process record: error reading "
+                                          "memory at addr 0x%s len = 4.\n"),
+                                        paddr_nz (ir.addr));
+                   return -1;
+                 }
+               ir.addr += 4;
+             }
+           else
+             {
+               if (target_read_memory
+                   (ir.addr, (gdb_byte *) & tmpu16, 4))
+                 {
+                   if (record_debug)
+                     printf_unfiltered (_("Process record: error reading "
+                                          "memory at addr 0x%s len = 4.\n"),
+                                        paddr_nz (ir.addr));
+                   return -1;
+                 }
+               ir.addr += 2;
+               addr = tmpu16;
+             }
+           if (record_arch_list_add_mem (addr, 1 << ir.ot))
+             return -1;
+         }
+      }
+      break;
+
+      /* mov R, Ib */
+    case 0xb0:
+    case 0xb1:
+    case 0xb2:
+    case 0xb3:
+    case 0xb4:
+    case 0xb5:
+    case 0xb6:
+    case 0xb7:
+      if (record_arch_list_add_reg (ir.regcache, (opcode & 0x7) & 0x3))
+       return -1;
+      break;
+
+      /* mov R, Iv */
+    case 0xb8:
+    case 0xb9:
+    case 0xba:
+    case 0xbb:
+    case 0xbc:
+    case 0xbd:
+    case 0xbe:
+    case 0xbf:
+      if (record_arch_list_add_reg (ir.regcache, opcode & 0x7))
+       return -1;
+      break;
+
+      /* xchg R, EAX */
+    case 0x91:
+    case 0x92:
+    case 0x93:
+    case 0x94:
+    case 0x95:
+    case 0x96:
+    case 0x97:
+      if (record_arch_list_add_reg (ir.regcache, I386_EAX_REGNUM))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, opcode & 0x7))
+       return -1;
+      break;
+
+      /* xchg Ev, Gv */
+    case 0x86:
+    case 0x87:
+      if ((opcode & 1) == 0)
+       ir.ot = OT_BYTE;
+      else
+       ir.ot = ir.dflag + OT_WORD;
+
+      if (i386_record_modrm (&ir))
+       return -1;
+
+      if (ir.mod == 3)
+       {
+         if (ir.ot == OT_BYTE)
+           ir.rm &= 0x3;
+         if (record_arch_list_add_reg (ir.regcache, ir.rm))
+           return -1;
+       }
+      else
+       {
+         if (i386_record_lea_modrm (&ir))
+           return -1;
+       }
+
+      if (ir.ot == OT_BYTE)
+       ir.reg &= 0x3;
+      if (record_arch_list_add_reg (ir.regcache, ir.reg))
+       return -1;
+      break;
+
+      /* les Gv */
+    case 0xc4:
+      /* lds Gv */
+    case 0xc5:
+      /* lss Gv */
+    case 0x0fb2:
+      /* lfs Gv */
+    case 0x0fb4:
+      /* lgs Gv */
+    case 0x0fb5:
+      if (i386_record_modrm (&ir))
+       return -1;
+      if (ir.mod == 3)
+       {
+         if (opcode > 0xff)
+           ir.addr -= 3;
+         else
+           ir.addr -= 2;
+         opcode = opcode << 8 | ir.modrm;
+         goto no_support;
+       }
+
+      switch (opcode)
+       {
+         /* les Gv */
+       case 0xc4:
+         tmpu8 = I386_ES_REGNUM;
+         break;
+         /* lds Gv */
+       case 0xc5:
+         tmpu8 = I386_DS_REGNUM;
+         break;
+         /* lss Gv */
+       case 0x0fb2:
+         tmpu8 = I386_SS_REGNUM;
+         break;
+         /* lfs Gv */
+       case 0x0fb4:
+         tmpu8 = I386_FS_REGNUM;
+         break;
+         /* lgs Gv */
+       case 0x0fb5:
+         tmpu8 = I386_GS_REGNUM;
+         break;
+       }
+      if (record_arch_list_add_reg (ir.regcache, tmpu8))
+       return -1;
+
+      if (record_arch_list_add_reg (ir.regcache, ir.reg))
+       return -1;
+      break;
+
+      /* shifts */
+    case 0xc0:
+    case 0xc1:
+    case 0xd0:
+    case 0xd1:
+    case 0xd2:
+    case 0xd3:
+      if ((opcode & 1) == 0)
+       ir.ot = OT_BYTE;
+      else
+       ir.ot = ir.dflag + OT_WORD;
+
+      if (i386_record_modrm (&ir))
+       return -1;
+
+      if (ir.mod != 3 && (opcode == 0xd2 || opcode == 0xd3))
+       {
+         if (i386_record_lea_modrm (&ir))
+           return -1;
+       }
+      else
+       {
+         if (ir.ot == OT_BYTE)
+           ir.rm &= 0x3;
+         if (record_arch_list_add_reg (ir.regcache, ir.rm))
+           return -1;
+       }
+
+      if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+       return -1;
+      break;
+
+    case 0x0fa4:
+    case 0x0fa5:
+    case 0x0fac:
+    case 0x0fad:
+      if (i386_record_modrm (&ir))
+       return -1;
+      if (ir.mod == 3)
+       {
+         if (record_arch_list_add_reg (ir.regcache, ir.rm))
+           return -1;
+       }
+      else
+       {
+         if (i386_record_lea_modrm (&ir))
+           return -1;
+       }
+      break;
+
+      /* floats */
+      /* It just record the memory change of instrcution. */
+    case 0xd8:
+    case 0xd9:
+    case 0xda:
+    case 0xdb:
+    case 0xdc:
+    case 0xdd:
+    case 0xde:
+    case 0xdf:
+      if (i386_record_modrm (&ir))
+       return -1;
+      ir.reg |= ((opcode & 7) << 3);
+      if (ir.mod != 3)
+       {
+         /* memory */
+         uint32_t addr;
+
+         if (i386_record_lea_modrm_addr (&ir, &addr))
+           return -1;
+         switch (ir.reg)
+           {
+           case 0x00:
+           case 0x01:
+           case 0x02:
+           case 0x03:
+           case 0x04:
+           case 0x05:
+           case 0x06:
+           case 0x07:
+           case 0x10:
+           case 0x11:
+           case 0x12:
+           case 0x13:
+           case 0x14:
+           case 0x15:
+           case 0x16:
+           case 0x17:
+           case 0x20:
+           case 0x21:
+           case 0x22:
+           case 0x23:
+           case 0x24:
+           case 0x25:
+           case 0x26:
+           case 0x27:
+           case 0x30:
+           case 0x31:
+           case 0x32:
+           case 0x33:
+           case 0x34:
+           case 0x35:
+           case 0x36:
+           case 0x37:
+             break;
+           case 0x08:
+           case 0x0a:
+           case 0x0b:
+           case 0x18:
+           case 0x19:
+           case 0x1a:
+           case 0x1b:
+           case 0x28:
+           case 0x29:
+           case 0x2a:
+           case 0x2b:
+           case 0x38:
+           case 0x39:
+           case 0x3a:
+           case 0x3b:
+             switch (ir.reg & 7)
+               {
+               case 0:
+                 break;
+               case 1:
+                 switch (ir.reg >> 4)
+                   {
+                   case 0:
+                     if (record_arch_list_add_mem (addr, 4))
+                       return -1;
+                     break;
+                   case 2:
+                     if (record_arch_list_add_mem (addr, 8))
+                       return -1;
+                     break;
+                   case 3:
+                   default:
+                     if (record_arch_list_add_mem (addr, 2))
+                       return -1;
+                     break;
+                   }
+                 break;
+               default:
+                 switch (ir.reg >> 4)
+                   {
+                   case 0:
+                   case 1:
+                     if (record_arch_list_add_mem (addr, 4))
+                       return -1;
+                     break;
+                   case 2:
+                     if (record_arch_list_add_mem (addr, 8))
+                       return -1;
+                     break;
+                   case 3:
+                   default:
+                     if (record_arch_list_add_mem (addr, 2))
+                       return -1;
+                     break;
+                   }
+                 break;
+               }
+             break;
+           case 0x0c:
+           case 0x0d:
+           case 0x1d:
+           case 0x2c:
+           case 0x3c:
+           case 0x3d:
+             break;
+           case 0x0e:
+             if (ir.dflag)
+               {
+                 if (record_arch_list_add_mem (addr, 28))
+                   return -1;
+               }
+             else
+               {
+                 if (record_arch_list_add_mem (addr, 14))
+                   return -1;
+               }
+             break;
+           case 0x0f:
+           case 0x2f:
+             if (record_arch_list_add_mem (addr, 2))
+               return -1;
+             break;
+           case 0x1f:
+           case 0x3e:
+             if (record_arch_list_add_mem (addr, 10))
+               return -1;
+             break;
+           case 0x2e:
+             if (ir.dflag)
+               {
+                 if (record_arch_list_add_mem (addr, 28))
+                   return -1;
+                 addr += 28;
+               }
+             else
+               {
+                 if (record_arch_list_add_mem (addr, 14))
+                   return -1;
+                 addr += 14;
+               }
+             if (record_arch_list_add_mem (addr, 80))
+               return -1;
+             break;
+           case 0x3f:
+             if (record_arch_list_add_mem (addr, 8))
+               return -1;
+             break;
+           default:
+             ir.addr -= 2;
+             opcode = opcode << 8 | ir.modrm;
+             goto no_support;
+             break;
+           }
+       }
+      break;
+
+      /* string ops */
+      /* movsS */
+    case 0xa4:
+    case 0xa5:
+      /* stosS */
+    case 0xaa:
+    case 0xab:
+      /* insS */
+    case 0x6c:
+    case 0x6d:
+      {
+       uint32_t addr;
+
+       if ((opcode & 1) == 0)
+         ir.ot = OT_BYTE;
+       else
+         ir.ot = ir.dflag + OT_WORD;
+       if (opcode == 0xa4 || opcode == 0xa5)
+         {
+           if (record_arch_list_add_reg (ir.regcache, I386_ESI_REGNUM))
+             return -1;
+         }
+       if (record_arch_list_add_reg (ir.regcache, I386_EDI_REGNUM))
+         return -1;
+
+       regcache_raw_read (ir.regcache, I386_EDI_REGNUM,
+                          (gdb_byte *) & addr);
+       if (!ir.aflag)
+         {
+           addr &= 0xffff;
+           /* addr += ((uint32_t)read_register (I386_ES_REGNUM)) << 4; */
+           if (record_debug)
+             printf_unfiltered (_("Process record ignores the memory change "
+                                  "of instruction at address 0x%s because "
+                                  "it can't get the value of the segment "
+                                  "register.\n"),
+                                paddr_nz (ir.addr));
+         }
+
+       if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))
+         {
+           uint32_t count;
+
+           regcache_raw_read (ir.regcache, I386_ECX_REGNUM,
+                              (gdb_byte *) & count);
+           if (!ir.aflag)
+             count &= 0xffff;
+
+           regcache_raw_read (ir.regcache, I386_EFLAGS_REGNUM,
+                              (gdb_byte *) & tmpu32);
+           if ((tmpu32 >> 10) & 0x1)
+             addr -= (count - 1) * (1 << ir.ot);
+
+           if (ir.aflag)
+             {
+               if (record_arch_list_add_mem (addr, count * (1 << ir.ot)))
+                 return -1;
+             }
+
+           if (record_arch_list_add_reg (ir.regcache, I386_ECX_REGNUM))
+             return -1;
+         }
+       else
+         {
+           if (ir.aflag)
+             {
+               if (record_arch_list_add_mem (addr, 1 << ir.ot))
+                 return -1;
+             }
+         }
+      }
+      break;
+
+      /* lodsS */
+    case 0xac:
+    case 0xad:
+      if (record_arch_list_add_reg (ir.regcache, I386_EAX_REGNUM))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, I386_ESI_REGNUM))
+       return -1;
+      if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))
+       {
+         if (record_arch_list_add_reg (ir.regcache, I386_ECX_REGNUM))
+           return -1;
+       }
+      break;
+
+      /* outsS */
+    case 0x6e:
+    case 0x6f:
+      if (record_arch_list_add_reg (ir.regcache, I386_ESI_REGNUM))
+       return -1;
+      if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))
+       {
+         if (record_arch_list_add_reg (ir.regcache, I386_ECX_REGNUM))
+           return -1;
+       }
+      break;
+
+      /* scasS */
+    case 0xae:
+    case 0xaf:
+      if (record_arch_list_add_reg (ir.regcache, I386_EDI_REGNUM))
+       return -1;
+      if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))
+       {
+         if (record_arch_list_add_reg (ir.regcache, I386_ECX_REGNUM))
+           return -1;
+       }
+      if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+       return -1;
+      break;
+
+      /* cmpsS */
+    case 0xa6:
+    case 0xa7:
+      if (record_arch_list_add_reg (ir.regcache, I386_EDI_REGNUM))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, I386_ESI_REGNUM))
+       return -1;
+      if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))
+       {
+         if (record_arch_list_add_reg (ir.regcache, I386_ECX_REGNUM))
+           return -1;
+       }
+      if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+       return -1;
+      break;
+
+      /* port I/O */
+    case 0xe4:
+    case 0xe5:
+    case 0xec:
+    case 0xed:
+      if (record_arch_list_add_reg (ir.regcache, I386_EAX_REGNUM))
+       return -1;
+      break;
+
+    case 0xe6:
+    case 0xe7:
+    case 0xee:
+    case 0xef:
+      break;
+
+      /* control */
+      /* ret im */
+    case 0xc2:
+      /* ret */
+    case 0xc3:
+      /* lret im */
+    case 0xca:
+      /* lret */
+    case 0xcb:
+      if (record_arch_list_add_reg (ir.regcache, I386_ESP_REGNUM))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, I386_CS_REGNUM))
+       return -1;
+      break;
+
+      /* iret */
+    case 0xcf:
+      if (record_arch_list_add_reg (ir.regcache, I386_ESP_REGNUM))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, I386_CS_REGNUM))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+       return -1;
+      break;
+
+      /* call im */
+    case 0xe8:
+      if (record_arch_list_add_reg (ir.regcache, I386_ESP_REGNUM))
+       return -1;
+      regcache_raw_read (ir.regcache, I386_ESP_REGNUM,
+                        (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem
+         ((CORE_ADDR) tmpu32 - (1 << (ir.dflag + 1)), (1 << (ir.dflag + 1))))
+       return -1;
+      break;
+
+      /* lcall im */
+    case 0x9a:
+      if (record_arch_list_add_reg (ir.regcache, I386_CS_REGNUM))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, I386_ESP_REGNUM))
+       return -1;
+      regcache_raw_read (ir.regcache, I386_ESP_REGNUM,
+                        (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem
+         ((CORE_ADDR) tmpu32 - (1 << (ir.dflag + 2)), (1 << (ir.dflag + 2))))
+       return -1;
+      break;
+
+      /* jmp im */
+    case 0xe9:
+      /* ljmp im */
+    case 0xea:
+      /* jmp Jb */
+    case 0xeb:
+      /* jcc Jb */
+    case 0x70:
+    case 0x71:
+    case 0x72:
+    case 0x73:
+    case 0x74:
+    case 0x75:
+    case 0x76:
+    case 0x77:
+    case 0x78:
+    case 0x79:
+    case 0x7a:
+    case 0x7b:
+    case 0x7c:
+    case 0x7d:
+    case 0x7e:
+    case 0x7f:
+      /* jcc Jv */
+    case 0x0f80:
+    case 0x0f81:
+    case 0x0f82:
+    case 0x0f83:
+    case 0x0f84:
+    case 0x0f85:
+    case 0x0f86:
+    case 0x0f87:
+    case 0x0f88:
+    case 0x0f89:
+    case 0x0f8a:
+    case 0x0f8b:
+    case 0x0f8c:
+    case 0x0f8d:
+    case 0x0f8e:
+    case 0x0f8f:
+      break;
+
+      /* setcc Gv */
+    case 0x0f90:
+    case 0x0f91:
+    case 0x0f92:
+    case 0x0f93:
+    case 0x0f94:
+    case 0x0f95:
+    case 0x0f96:
+    case 0x0f97:
+    case 0x0f98:
+    case 0x0f99:
+    case 0x0f9a:
+    case 0x0f9b:
+    case 0x0f9c:
+    case 0x0f9d:
+    case 0x0f9e:
+    case 0x0f9f:
+      ir.ot = OT_BYTE;
+      if (i386_record_modrm (&ir))
+       return -1;
+      if (ir.mod == 3)
+       {
+         if (record_arch_list_add_reg (ir.regcache, ir.rm & 0x3))
+           return -1;
+       }
+      else
+       {
+         if (i386_record_lea_modrm (&ir))
+           return -1;
+       }
+      break;
+
+      /* cmov Gv, Ev */
+    case 0x0f40:
+    case 0x0f41:
+    case 0x0f42:
+    case 0x0f43:
+    case 0x0f44:
+    case 0x0f45:
+    case 0x0f46:
+    case 0x0f47:
+    case 0x0f48:
+    case 0x0f49:
+    case 0x0f4a:
+    case 0x0f4b:
+    case 0x0f4c:
+    case 0x0f4d:
+    case 0x0f4e:
+    case 0x0f4f:
+      if (i386_record_modrm (&ir))
+       return -1;
+      if (ir.dflag == OT_BYTE)
+       ir.reg &= 0x3;
+      if (record_arch_list_add_reg (ir.regcache, ir.reg & 0x3))
+       return -1;
+      break;
+
+      /* flags */
+      /* pushf */
+    case 0x9c:
+      if (record_arch_list_add_reg (ir.regcache, I386_ESP_REGNUM))
+       return -1;
+      regcache_raw_read (ir.regcache, I386_ESP_REGNUM,
+                        (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem
+         ((CORE_ADDR) tmpu32 - (1 << (ir.dflag + 1)), (1 << (ir.dflag + 1))))
+       return -1;
+      break;
+
+      /* popf */
+    case 0x9d:
+      if (record_arch_list_add_reg (ir.regcache, I386_ESP_REGNUM))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+       return -1;
+      break;
+
+      /* sahf */
+    case 0x9e:
+      /* cmc */
+    case 0xf5:
+      /* clc */
+    case 0xf8:
+      /* stc */
+    case 0xf9:
+      /* cld */
+    case 0xfc:
+      /* std */
+    case 0xfd:
+      if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+       return -1;
+      break;
+
+      /* lahf */
+    case 0x9f:
+      if (record_arch_list_add_reg (ir.regcache, I386_EAX_REGNUM))
+       return -1;
+      break;
+
+      /* bit operations */
+      /* bt/bts/btr/btc Gv, im */
+    case 0x0fba:
+      /* bts */
+    case 0x0fab:
+      /* btr */
+    case 0x0fb3:
+      /* btc */
+    case 0x0fbb:
+      ir.ot = ir.dflag + OT_WORD;
+      if (i386_record_modrm (&ir))
+       return -1;
+      if (ir.reg < 4)
+       {
+         ir.addr -= 3;
+         opcode = opcode << 8 | ir.modrm;
+         goto no_support;
+       }
+      ir.reg -= 4;
+      if (ir.reg != 0)
+       {
+         if (ir.mod != 3)
+           {
+             if (i386_record_lea_modrm (&ir))
+               return -1;
+           }
+         else
+           {
+             if (record_arch_list_add_reg (ir.regcache, ir.rm))
+               return -1;
+           }
+       }
+      if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+       return -1;
+      break;
+
+      /* bt Gv, Ev */
+    case 0x0fa3:
+      if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+       return -1;
+      break;
+
+      /* bsf */
+    case 0x0fbc:
+      /* bsr */
+    case 0x0fbd:
+      if (record_arch_list_add_reg (ir.regcache, ir.reg))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+       return -1;
+      break;
+
+      /* bcd */
+      /* daa */
+    case 0x27:
+      /* das */
+    case 0x2f:
+      /* aaa */
+    case 0x37:
+      /* aas */
+    case 0x3f:
+      /* aam */
+    case 0xd4:
+      /* aad */
+    case 0xd5:
+      if (record_arch_list_add_reg (ir.regcache, I386_EAX_REGNUM))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+       return -1;
+      break;
+
+      /* misc */
+      /* nop */
+    case 0x90:
+      if (prefixes & PREFIX_LOCK)
+       {
+         ir.addr -= 1;
+         goto no_support;
+       }
+      break;
+
+      /* fwait */
+      /* XXX */
+    case 0x9b:
+      printf_unfiltered (_("Process record doesn't support instruction "
+                          "fwait.\n"));
+      ir.addr -= 1;
+      goto no_support;
+      break;
+
+      /* int3 */
+      /* XXX */
+    case 0xcc:
+      printf_unfiltered (_("Process record doesn't support instruction "
+                          "int3.\n"));
+      ir.addr -= 1;
+      goto no_support;
+      break;
+
+      /* int */
+      /* XXX */
+    case 0xcd:
+      {
+       int ret;
+       if (target_read_memory (ir.addr, &tmpu8, 1))
+         {
+           if (record_debug)
+             printf_unfiltered (_("Process record: error reading memory "
+                                  "at addr 0x%s len = 1.\n"),
+                                paddr_nz (ir.addr));
+           return -1;
+         }
+       ir.addr++;
+       if (tmpu8 != 0x80
+           || gdbarch_tdep (gdbarch)->i386_intx80_record == NULL)
+         {
+           printf_unfiltered (_("Process record doesn't support "
+                                "instruction int 0x%02x.\n"),
+                              tmpu8);
+           ir.addr -= 2;
+           goto no_support;
+         }
+       ret = gdbarch_tdep (gdbarch)->i386_intx80_record (ir.regcache);
+       if (ret)
+         return ret;
+      }
+      break;
+
+      /* into */
+      /* XXX */
+    case 0xce:
+      printf_unfiltered (_("Process record doesn't support "
+                          "instruction into.\n"));
+      ir.addr -= 1;
+      goto no_support;
+      break;
+
+      /* cli */
+    case 0xfa:
+      /* sti */
+    case 0xfb:
+      break;
+
+      /* bound */
+    case 0x62:
+      printf_unfiltered (_("Process record doesn't support "
+                          "instruction bound.\n"));
+      ir.addr -= 1;
+      goto no_support;
+      break;
+
+      /* bswap reg */
+    case 0x0fc8:
+    case 0x0fc9:
+    case 0x0fca:
+    case 0x0fcb:
+    case 0x0fcc:
+    case 0x0fcd:
+    case 0x0fce:
+    case 0x0fcf:
+      if (record_arch_list_add_reg (ir.regcache, opcode & 7))
+       return -1;
+      break;
+
+      /* salc */
+    case 0xd6:
+      if (record_arch_list_add_reg (ir.regcache, I386_EAX_REGNUM))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+       return -1;
+      break;
+
+      /* loopnz */
+    case 0xe0:
+      /* loopz */
+    case 0xe1:
+      /* loop */
+    case 0xe2:
+      /* jecxz */
+    case 0xe3:
+      if (record_arch_list_add_reg (ir.regcache, I386_ECX_REGNUM))
+       return -1;
+      break;
+
+      /* wrmsr */
+    case 0x0f30:
+      printf_unfiltered (_("Process record doesn't support "
+                          "instruction wrmsr.\n"));
+      ir.addr -= 2;
+      goto no_support;
+      break;
+
+      /* rdmsr */
+    case 0x0f32:
+      printf_unfiltered (_("Process record doesn't support "
+                          "instruction rdmsr.\n"));
+      ir.addr -= 2;
+      goto no_support;
+      break;
+
+      /* rdtsc */
+    case 0x0f31:
+      printf_unfiltered (_("Process record doesn't support "
+                          "instruction rdtsc.\n"));
+      ir.addr -= 2;
+      goto no_support;
+      break;
+
+      /* sysenter */
+    case 0x0f34:
+      {
+       int ret;
+       if (gdbarch_tdep (gdbarch)->i386_sysenter_record == NULL)
+         {
+           printf_unfiltered (_("Process record doesn't support "
+                                "instruction sysenter.\n"));
+           ir.addr -= 2;
+           goto no_support;
+         }
+       ret = gdbarch_tdep (gdbarch)->i386_sysenter_record (ir.regcache);
+       if (ret)
+         return ret;
+      }
+      break;
+
+      /* sysexit */
+    case 0x0f35:
+      printf_unfiltered (_("Process record doesn't support "
+                          "instruction sysexit.\n"));
+      ir.addr -= 2;
+      goto no_support;
+      break;
+
+      /* cpuid */
+    case 0x0fa2:
+      if (record_arch_list_add_reg (ir.regcache, I386_EAX_REGNUM))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, I386_ECX_REGNUM))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, I386_EDX_REGNUM))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, I386_EBX_REGNUM))
+       return -1;
+      break;
+
+      /* hlt */
+    case 0xf4:
+      printf_unfiltered (_("Process record doesn't support "
+                          "instruction hlt.\n"));
+      ir.addr -= 1;
+      goto no_support;
+      break;
+
+    case 0x0f00:
+      if (i386_record_modrm (&ir))
+       return -1;
+      switch (ir.reg)
+       {
+         /* sldt */
+       case 0:
+         /* str */
+       case 1:
+         if (ir.mod == 3)
+           {
+             if (record_arch_list_add_reg (ir.regcache, ir.rm))
+               return -1;
+           }
+         else
+           {
+             ir.ot = OT_WORD;
+             if (i386_record_lea_modrm (&ir))
+               return -1;
+           }
+         break;
+         /* lldt */
+       case 2:
+         /* ltr */
+       case 3:
+         break;
+         /* verr */
+       case 4:
+         /* verw */
+       case 5:
+         if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+           return -1;
+         break;
+       default:
+         ir.addr -= 3;
+         opcode = opcode << 8 | ir.modrm;
+         goto no_support;
+         break;
+       }
+      break;
+
+    case 0x0f01:
+      if (i386_record_modrm (&ir))
+       return -1;
+      switch (ir.reg)
+       {
+         /* sgdt */
+       case 0:
+         {
+           uint32_t addr;
+
+           if (ir.mod == 3)
+             {
+               ir.addr -= 3;
+               opcode = opcode << 8 | ir.modrm;
+               goto no_support;
+             }
+
+           if (ir.override)
+             {
+               if (record_debug)
+                 printf_unfiltered (_("Process record ignores the memory "
+                                      "change of instruction at "
+                                      "address 0x%s because it can't get "
+                                      "the value of the segment "
+                                      "register.\n"),
+                                    paddr_nz (ir.addr));
+             }
+           else
+             {
+               if (i386_record_lea_modrm_addr (&ir, &addr))
+                 return -1;
+               if (record_arch_list_add_mem (addr, 2))
+                 return -1;
+               addr += 2;
+               if (record_arch_list_add_mem (addr, 4))
+                 return -1;
+             }
+         }
+         break;
+       case 1:
+         if (ir.mod == 3)
+           {
+             switch (ir.rm)
+               {
+                 /* monitor */
+               case 0:
+                 break;
+                 /* mwait */
+               case 1:
+                 if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+                   return -1;
+                 break;
+               default:
+                 ir.addr -= 3;
+                 opcode = opcode << 8 | ir.modrm;
+                 goto no_support;
+                 break;
+               }
+           }
+         else
+           {
+             /* sidt */
+             if (ir.override)
+               {
+                 if (record_debug)
+                   printf_unfiltered (_("Process record ignores the memory "
+                                        "change of instruction at "
+                                        "address 0x%s because it can't get "
+                                        "the value of the segment "
+                                        "register.\n"),
+                                      paddr_nz (ir.addr));
+               }
+             else
+               {
+                 uint32_t addr;
+
+                 if (i386_record_lea_modrm_addr (&ir, &addr))
+                   return -1;
+                 if (record_arch_list_add_mem (addr, 2))
+                   return -1;
+                 addr += 2;
+                 if (record_arch_list_add_mem (addr, 4))
+                   return -1;
+               }
+           }
+         break;
+         /* lgdt */
+       case 2:
+         /* lidt */
+       case 3:
+         /* invlpg */
+       case 7:
+       default:
+         if (ir.mod == 3)
+           {
+             ir.addr -= 3;
+             opcode = opcode << 8 | ir.modrm;
+             goto no_support;
+           }
+         break;
+         /* smsw */
+       case 4:
+         if (ir.mod == 3)
+           {
+             if (record_arch_list_add_reg (ir.regcache, ir.rm))
+               return -1;
+           }
+         else
+           {
+             ir.ot = OT_WORD;
+             if (i386_record_lea_modrm (&ir))
+               return -1;
+           }
+         break;
+         /* lmsw */
+       case 6:
+         break;
+       }
+      break;
+
+      /* invd */
+    case 0x0f08:
+      /* wbinvd */
+    case 0x0f09:
+      break;
+
+      /* arpl */
+    case 0x63:
+      ir.ot = ir.dflag ? OT_LONG : OT_WORD;
+      if (i386_record_modrm (&ir))
+       return -1;
+      if (ir.mod != 3)
+       {
+         if (i386_record_lea_modrm (&ir))
+           return -1;
+       }
+      else
+       {
+         if (record_arch_list_add_reg (ir.regcache, ir.rm))
+           return -1;
+       }
+      if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+       return -1;
+      break;
+
+      /* lar */
+    case 0x0f02:
+      /* lsl */
+    case 0x0f03:
+      if (i386_record_modrm (&ir))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, ir.reg))
+       return -1;
+      if (record_arch_list_add_reg (ir.regcache, I386_EFLAGS_REGNUM))
+       return -1;
+      break;
+
+    case 0x0f18:
+      break;
+
+      /* nop (multi byte) */
+    case 0x0f19:
+    case 0x0f1a:
+    case 0x0f1b:
+    case 0x0f1c:
+    case 0x0f1d:
+    case 0x0f1e:
+    case 0x0f1f:
+      break;
+
+      /* mov reg, crN */
+    case 0x0f20:
+      /* mov crN, reg */
+    case 0x0f22:
+      if (i386_record_modrm (&ir))
+       return -1;
+      if ((ir.modrm & 0xc0) != 0xc0)
+       {
+         ir.addr -= 2;
+         opcode = opcode << 8 | ir.modrm;
+         goto no_support;
+       }
+      switch (ir.reg)
+       {
+       case 0:
+       case 2:
+       case 3:
+       case 4:
+       case 8:
+         if (opcode & 2)
+           {
+           }
+         else
+           {
+             if (record_arch_list_add_reg (ir.regcache, ir.rm))
+               return -1;
+           }
+         break;
+       default:
+         ir.addr -= 2;
+         opcode = opcode << 8 | ir.modrm;
+         goto no_support;
+         break;
+       }
+      break;
+
+      /* mov reg, drN */
+    case 0x0f21:
+      /* mov drN, reg */
+    case 0x0f23:
+      if (i386_record_modrm (&ir))
+       return -1;
+      if ((ir.modrm & 0xc0) != 0xc0 || ir.reg == 4
+         || ir.reg == 5 || ir.reg >= 8)
+       {
+         ir.addr -= 2;
+         opcode = opcode << 8 | ir.modrm;
+         goto no_support;
+       }
+      if (opcode & 2)
+       {
+       }
+      else
+       {
+         if (record_arch_list_add_reg (ir.regcache, ir.rm))
+           return -1;
+       }
+      break;
+
+      /* clts */
+    case 0x0f06:
+      break;
+
+      /* MMX/SSE/SSE2/PNI support */
+      /* XXX */
+
+    default:
+      if (opcode > 0xff)
+       ir.addr -= 2;
+      else
+       ir.addr -= 1;
+      goto no_support;
+      break;
+    }
+
+/* In the future, Maybe still need to deal with need_dasm */
+  if (record_arch_list_add_reg (ir.regcache, I386_EIP_REGNUM))
+    return -1;
+  if (record_arch_list_add_end ())
+    return -1;
+
+  return 0;
+
+no_support:
+  printf_unfiltered (_("Process record doesn't support instruction 0x%02x "
+                      "at address 0x%s.\n"),
+                    (unsigned int) (opcode), paddr_nz (ir.addr));
+  return -1;
+}
+
+\f
+static struct gdbarch *
+i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch_tdep *tdep;
+  struct gdbarch *gdbarch;
+
+  /* If there is already a candidate, use it.  */
+  arches = gdbarch_list_lookup_by_info (arches, &info);
+  if (arches != NULL)
+    return arches->gdbarch;
+
+  /* Allocate space for the new architecture.  */
+  tdep = XCALLOC (1, struct gdbarch_tdep);
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  /* General-purpose registers.  */
+  tdep->gregset = NULL;
+  tdep->gregset_reg_offset = NULL;
+  tdep->gregset_num_regs = I386_NUM_GREGS;
+  tdep->sizeof_gregset = 0;
+
+  /* Floating-point registers.  */
+  tdep->fpregset = NULL;
+  tdep->sizeof_fpregset = I387_SIZEOF_FSAVE;
+
+  /* The default settings include the FPU registers, the MMX registers
+     and the SSE registers.  This can be overridden for a specific ABI
+     by adjusting the members `st0_regnum', `mm0_regnum' and
+     `num_xmm_regs' of `struct gdbarch_tdep', otherwise the registers
+     will show up in the output of "info all-registers".  Ideally we
+     should try to autodetect whether they are available, such that we
+     can prevent "info all-registers" from displaying registers that
+     aren't available.
+
+     NOTE: kevinb/2003-07-13: ... if it's a choice between printing
+     [the SSE registers] always (even when they don't exist) or never
+     showing them to the user (even when they do exist), I prefer the
+     former over the latter.  */
+
+  tdep->st0_regnum = I386_ST0_REGNUM;
+
+  /* The MMX registers are implemented as pseudo-registers.  Put off
+     calculating the register number for %mm0 until we know the number
+     of raw registers.  */
+  tdep->mm0_regnum = 0;
+
+  /* I386_NUM_XREGS includes %mxcsr, so substract one.  */
+  tdep->num_xmm_regs = I386_NUM_XREGS - 1;
+
+  tdep->jb_pc_offset = -1;
+  tdep->struct_return = pcc_struct_return;
+  tdep->sigtramp_start = 0;
+  tdep->sigtramp_end = 0;
+  tdep->sigtramp_p = i386_sigtramp_p;
+  tdep->sigcontext_addr = NULL;
+  tdep->sc_reg_offset = NULL;
+  tdep->sc_pc_offset = -1;
+  tdep->sc_sp_offset = -1;
+
+  /* The format used for `long double' on almost all i386 targets is
+     the i387 extended floating-point format.  In fact, of all targets
+     in the GCC 2.95 tree, only OSF/1 does it different, and insists
+     on having a `long double' that's not `long' at all.  */
+  set_gdbarch_long_double_format (gdbarch, floatformats_i387_ext);
+
+  /* Although the i387 extended floating-point has only 80 significant
+     bits, a `long double' actually takes up 96, probably to enforce
+     alignment.  */
+  set_gdbarch_long_double_bit (gdbarch, 96);
+
+  /* The default ABI includes general-purpose registers, 
+     floating-point registers, and the SSE registers.  */
+  set_gdbarch_num_regs (gdbarch, I386_SSE_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, i386_register_name);
+  set_gdbarch_register_type (gdbarch, i386_register_type);
+
+  /* Register numbers of various important registers.  */
+  set_gdbarch_sp_regnum (gdbarch, I386_ESP_REGNUM); /* %esp */
+  set_gdbarch_pc_regnum (gdbarch, I386_EIP_REGNUM); /* %eip */
+  set_gdbarch_ps_regnum (gdbarch, I386_EFLAGS_REGNUM); /* %eflags */
+  set_gdbarch_fp0_regnum (gdbarch, I386_ST0_REGNUM); /* %st(0) */
+
+  /* NOTE: kettenis/20040418: GCC does have two possible register
+     numbering schemes on the i386: dbx and SVR4.  These schemes
+     differ in how they number %ebp, %esp, %eflags, and the
+     floating-point registers, and are implemented by the arrays
+     dbx_register_map[] and svr4_dbx_register_map in
+     gcc/config/i386.c.  GCC also defines a third numbering scheme in
+     gcc/config/i386.c, which it designates as the "default" register
+     map used in 64bit mode.  This last register numbering scheme is
+     implemented in dbx64_register_map, and is used for AMD64; see
+     amd64-tdep.c.
+
+     Currently, each GCC i386 target always uses the same register
+     numbering scheme across all its supported debugging formats
+     i.e. SDB (COFF), stabs and DWARF 2.  This is because
+     gcc/sdbout.c, gcc/dbxout.c and gcc/dwarf2out.c all use the
+     DBX_REGISTER_NUMBER macro which is defined by each target's
+     respective config header in a manner independent of the requested
+     output debugging format.
+
+     This does not match the arrangement below, which presumes that
+     the SDB and stabs numbering schemes differ from the DWARF and
+     DWARF 2 ones.  The reason for this arrangement is that it is
+     likely to get the numbering scheme for the target's
+     default/native debug format right.  For targets where GCC is the
+     native compiler (FreeBSD, NetBSD, OpenBSD, GNU/Linux) or for
+     targets where the native toolchain uses a different numbering
+     scheme for a particular debug format (stabs-in-ELF on Solaris)
+     the defaults below will have to be overridden, like
+     i386_elf_init_abi() does.  */
+
+  /* Use the dbx register numbering scheme for stabs and COFF.  */
+  set_gdbarch_stab_reg_to_regnum (gdbarch, i386_dbx_reg_to_regnum);
+  set_gdbarch_sdb_reg_to_regnum (gdbarch, i386_dbx_reg_to_regnum);
+
+  /* Use the SVR4 register numbering scheme for DWARF 2.  */
+  set_gdbarch_dwarf2_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
+
+  /* We don't set gdbarch_stab_reg_to_regnum, since ECOFF doesn't seem to
+     be in use on any of the supported i386 targets.  */
+
+  set_gdbarch_print_float_info (gdbarch, i387_print_float_info);
+
+  set_gdbarch_get_longjmp_target (gdbarch, i386_get_longjmp_target);
+
+  /* Call dummy code.  */
+  set_gdbarch_push_dummy_call (gdbarch, i386_push_dummy_call);
+
+  set_gdbarch_convert_register_p (gdbarch, i386_convert_register_p);
+  set_gdbarch_register_to_value (gdbarch,  i386_register_to_value);
+  set_gdbarch_value_to_register (gdbarch, i386_value_to_register);
+
+  set_gdbarch_return_value (gdbarch, i386_return_value);
+
+  set_gdbarch_skip_prologue (gdbarch, i386_skip_prologue);
+
+  /* Stack grows downward.  */
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+
+  set_gdbarch_breakpoint_from_pc (gdbarch, i386_breakpoint_from_pc);
+  set_gdbarch_decr_pc_after_break (gdbarch, 1);
+  set_gdbarch_max_insn_length (gdbarch, I386_MAX_INSN_LEN);
+
+  set_gdbarch_frame_args_skip (gdbarch, 8);
+
+  /* Wire in the MMX registers.  */
+  set_gdbarch_num_pseudo_regs (gdbarch, i386_num_mmx_regs);
+  set_gdbarch_pseudo_register_read (gdbarch, i386_pseudo_register_read);
+  set_gdbarch_pseudo_register_write (gdbarch, i386_pseudo_register_write);
 
   set_gdbarch_print_insn (gdbarch, i386_print_insn);
 
-  set_gdbarch_unwind_dummy_id (gdbarch, i386_unwind_dummy_id);
+  set_gdbarch_dummy_id (gdbarch, i386_dummy_id);
 
   set_gdbarch_unwind_pc (gdbarch, i386_unwind_pc);
 
@@ -2323,15 +5293,15 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_fetch_pointer_argument (gdbarch, i386_fetch_pointer_argument);
 
   /* Hook in the DWARF CFI frame unwinder.  */
-  frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
+  dwarf2_append_unwinders (gdbarch);
 
   frame_base_set_default (gdbarch, &i386_frame_base);
 
   /* Hook in ABI-specific overrides, if they have been registered.  */
   gdbarch_init_osabi (info, gdbarch);
 
-  frame_unwind_append_sniffer (gdbarch, i386_sigtramp_frame_sniffer);
-  frame_unwind_append_sniffer (gdbarch, i386_frame_sniffer);
+  frame_unwind_append_unwinder (gdbarch, &i386_sigtramp_frame_unwind);
+  frame_unwind_append_unwinder (gdbarch, &i386_frame_unwind);
 
   /* If we have a register mapping, enable the generic core file
      support, unless it has already been enabled.  */
@@ -2345,6 +5315,9 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   if (tdep->mm0_regnum == 0)
     tdep->mm0_regnum = gdbarch_num_regs (gdbarch);
 
+  set_gdbarch_skip_permanent_breakpoint (gdbarch,
+                                        i386_skip_permanent_breakpoint);
+
   return gdbarch;
 }
 
@@ -2357,12 +5330,6 @@ i386_coff_osabi_sniffer (bfd *abfd)
 
   return GDB_OSABI_UNKNOWN;
 }
-
-static enum gdb_osabi
-i386_nlm_osabi_sniffer (bfd *abfd)
-{
-  return GDB_OSABI_NETWARE;
-}
 \f
 
 /* Provide a prototype to silence -Wmissing-prototypes.  */
@@ -2397,16 +5364,12 @@ is \"default\"."),
 
   gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_coff_flavour,
                                  i386_coff_osabi_sniffer);
-  gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_nlm_flavour,
-                                 i386_nlm_osabi_sniffer);
 
   gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_SVR4,
                          i386_svr4_init_abi);
   gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_GO32,
                          i386_go32_init_abi);
-  gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_NETWARE,
-                         i386_nw_init_abi);
 
-  /* Initialize the i386 specific register groups.  */
+  /* Initialize the i386-specific register groups.  */
   i386_init_reggroups ();
 }
This page took 0.074711 seconds and 4 git commands to generate.