* MAINTAINERS: Change my e-mail address.
[deliverable/binutils-gdb.git] / gdb / i386-tdep.c
index 7daea3152a3a5d9a884f9240daa7f77381fc4f38..dd19e2499d01e0e64a1aa6083ba38696ed535306 100644 (file)
@@ -24,6 +24,7 @@
 #include "arch-utils.h"
 #include "command.h"
 #include "dummy-frame.h"
+#include "dwarf2-frame.h"
 #include "doublest.h"
 #include "floatformat.h"
 #include "frame.h"
@@ -40,6 +41,7 @@
 #include "symtab.h"
 #include "target.h"
 #include "value.h"
+#include "dis-asm.h"
 
 #include "gdb_assert.h"
 #include "gdb_string.h"
@@ -125,12 +127,12 @@ i386_mxcsr_regnum_p (int regnum)
 const char *
 i386_register_name (int reg)
 {
-  if (reg >= 0 && reg < i386_num_register_names)
-    return i386_register_names[reg];
-
   if (i386_mmx_regnum_p (reg))
     return i386_mmx_names[reg - MM0_REGNUM];
 
+  if (reg >= 0 && reg < i386_num_register_names)
+    return i386_register_names[reg];
+
   return NULL;
 }
 
@@ -438,6 +440,7 @@ i386_analyze_frame_setup (CORE_ADDR pc, CORE_ADDR current_pc,
                          struct i386_frame_cache *cache)
 {
   unsigned char op;
+  int skip = 0;
 
   if (current_pc <= pc)
     return current_pc;
@@ -455,25 +458,61 @@ i386_analyze_frame_setup (CORE_ADDR pc, CORE_ADDR current_pc,
       if (current_pc <= pc + 1)
        return current_pc;
 
-      /* Check for `movl %esp, %ebp' -- can be written in two ways.  */
       op = read_memory_unsigned_integer (pc + 1, 1);
+
+      /* Check for some special instructions that might be migrated
+        by GCC into the prologue.  We check for
+
+           xorl %ebx, %ebx
+           xorl %ecx, %ecx
+           xorl %edx, %edx
+
+        and the equivalent
+
+           subl %ebx, %ebx
+           subl %ecx, %ecx
+           subl %edx, %edx
+
+        Make sure we only skip these instructions if we later see the
+        `movl %esp, %ebp' that actually sets up the frame.  */
+      while (op == 0x29 || op == 0x31)
+       {
+         op = read_memory_unsigned_integer (pc + skip + 2, 1);
+         switch (op)
+           {
+           case 0xdb:  /* %ebx */
+           case 0xc9:  /* %ecx */
+           case 0xd2:  /* %edx */
+             skip += 2;
+             break;
+           default:
+             return pc + 1;
+           }
+
+         op = read_memory_unsigned_integer (pc + skip + 1, 1);
+       }
+
+      /* Check for `movl %esp, %ebp' -- can be written in two ways.  */
       switch (op)
        {
        case 0x8b:
-         if (read_memory_unsigned_integer (pc + 2, 1) != 0xec)
+         if (read_memory_unsigned_integer (pc + skip + 2, 1) != 0xec)
            return pc + 1;
          break;
        case 0x89:
-         if (read_memory_unsigned_integer (pc + 2, 1) != 0xe5)
+         if (read_memory_unsigned_integer (pc + skip + 2, 1) != 0xe5)
            return pc + 1;
          break;
        default:
          return pc + 1;
        }
 
-      /* OK, we actually have a frame.  We just don't know how large it is
-        yet.  Set its size to zero.  We'll adjust it if necessary.  */
+      /* OK, we actually have a frame.  We just don't know how large
+        it is yet.  Set its size to zero.  We'll adjust it if
+        necessary.  We also now commit to skipping the special
+        instructions mentioned before.  */
       cache->locals = 0;
+      pc += skip;
 
       /* If that's all, return now.  */
       if (current_pc <= pc + 3)
@@ -533,23 +572,22 @@ static CORE_ADDR
 i386_analyze_register_saves (CORE_ADDR pc, CORE_ADDR current_pc,
                             struct i386_frame_cache *cache)
 {
-  if (cache->locals >= 0)
-    {
-      CORE_ADDR offset;
-      unsigned char op;
-      int i;
+  CORE_ADDR offset = 0;
+  unsigned char op;
+  int i;
 
-      offset = - 4 - cache->locals;
-      for (i = 0; i < 8 && pc < current_pc; i++)
-       {
-         op = read_memory_unsigned_integer (pc, 1);
-         if (op < 0x50 || op > 0x57)
-           break;
+  if (cache->locals > 0)
+    offset -= cache->locals;
+  for (i = 0; i < 8 && pc < current_pc; i++)
+    {
+      op = read_memory_unsigned_integer (pc, 1);
+      if (op < 0x50 || op > 0x57)
+       break;
 
-         cache->saved_regs[op - 0x50] = offset;
-         offset -= 4;
-         pc++;
-       }
+      offset -= 4;
+      cache->saved_regs[op - 0x50] = offset;
+      cache->sp_offset += 4;
+      pc++;
     }
 
   return pc;
@@ -750,6 +788,7 @@ i386_frame_this_id (struct frame_info *next_frame, void **this_cache,
   if (cache->base == 0)
     return;
 
+  /* See the end of i386_push_dummy_call.  */
   (*this_id) = frame_id_build (cache->base + 8, cache->pc);
 }
 
@@ -793,7 +832,8 @@ i386_frame_prev_register (struct frame_info *next_frame, void **this_cache,
          ULONGEST val;
 
          /* Clear the direction flag.  */
-         frame_unwind_unsigned_register (next_frame, PS_REGNUM, &val);
+         val = frame_unwind_register_unsigned (next_frame,
+                                               I386_EFLAGS_REGNUM);
          val &= ~(1 << 10);
          store_unsigned_integer (valuep, 4, val);
        }
@@ -849,7 +889,7 @@ static const struct frame_unwind i386_frame_unwind =
 };
 
 static const struct frame_unwind *
-i386_frame_p (CORE_ADDR pc)
+i386_frame_sniffer (struct frame_info *next_frame)
 {
   return &i386_frame_unwind;
 }
@@ -901,6 +941,7 @@ i386_sigtramp_frame_this_id (struct frame_info *next_frame, void **this_cache,
   struct i386_frame_cache *cache =
     i386_sigtramp_frame_cache (next_frame, this_cache);
 
+  /* See the end of i386_push_dummy_call.  */
   (*this_id) = frame_id_build (cache->base + 8, frame_pc_unwind (next_frame));
 }
 
@@ -926,10 +967,16 @@ static const struct frame_unwind i386_sigtramp_frame_unwind =
 };
 
 static const struct frame_unwind *
-i386_sigtramp_frame_p (CORE_ADDR pc)
+i386_sigtramp_frame_sniffer (struct frame_info *next_frame)
 {
+  CORE_ADDR pc = frame_pc_unwind (next_frame);
   char *name;
 
+  /* We shouldn't even bother to try if the OSABI didn't register
+     a sigcontext_addr handler.  */
+  if (!gdbarch_tdep (current_gdbarch)->sigcontext_addr)
+    return NULL;
+
   find_pc_partial_function (pc, &name, NULL, NULL);
   if (PC_IN_SIGTRAMP (pc, name))
     return &i386_sigtramp_frame_unwind;
@@ -954,12 +1001,6 @@ static const struct frame_base i386_frame_base =
   i386_frame_base_address
 };
 
-static void
-i386_save_dummy_frame_tos (CORE_ADDR sp)
-{
-  generic_save_dummy_frame_tos (sp + 8);
-}
-
 static struct frame_id
 i386_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
 {
@@ -969,6 +1010,7 @@ i386_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
   frame_unwind_register (next_frame, I386_EBP_REGNUM, buf);
   fp = extract_unsigned_integer (buf, 4);
 
+  /* See the end of i386_push_dummy_call.  */
   return frame_id_build (fp + 8, frame_pc_unwind (next_frame));
 }
 \f
@@ -994,11 +1036,14 @@ i386_get_longjmp_target (CORE_ADDR *pc)
   if (jb_pc_offset == -1)
     return 0;
 
-  sp = read_register (SP_REGNUM);
+  /* 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))
     return 0;
 
-  jb_addr = extract_typed_address (buf, builtin_type_void_func_ptr);
+  jb_addr = extract_typed_address (buf, builtin_type_void_data_ptr);
   if (target_read_memory (jb_addr + jb_pc_offset, buf, len))
     return 0;
 
@@ -1052,7 +1097,16 @@ i386_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
   /* ...and fake a frame pointer.  */
   regcache_cooked_write (regcache, I386_EBP_REGNUM, buf);
 
-  return sp;
+  /* 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
+     a given target have to agree (within a certain margin) on the
+     defenition of the stack address of a frame.  Otherwise
+     frame_id_inner() won't 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.  */
+  return sp + 8;
 }
 
 /* These registers are used for returning integers (and on some
@@ -1098,8 +1152,8 @@ i386_extract_return_value (struct type *type, struct regcache *regcache,
     }
   else
     {
-      int low_size = REGISTER_RAW_SIZE (LOW_RETURN_REGNUM);
-      int high_size = REGISTER_RAW_SIZE (HIGH_RETURN_REGNUM);
+      int low_size = register_size (current_gdbarch, LOW_RETURN_REGNUM);
+      int high_size = register_size (current_gdbarch, HIGH_RETURN_REGNUM);
 
       if (len <= low_size)
        {
@@ -1172,8 +1226,8 @@ i386_store_return_value (struct type *type, struct regcache *regcache,
     }
   else
     {
-      int low_size = REGISTER_RAW_SIZE (LOW_RETURN_REGNUM);
-      int high_size = REGISTER_RAW_SIZE (HIGH_RETURN_REGNUM);
+      int low_size = register_size (current_gdbarch, LOW_RETURN_REGNUM);
+      int high_size = register_size (current_gdbarch, HIGH_RETURN_REGNUM);
 
       if (len <= low_size)
        regcache_raw_write_part (regcache, LOW_RETURN_REGNUM, 0, len, valbuf);
@@ -1287,7 +1341,7 @@ i386_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
 
       /* Extract (always little endian).  */
       regcache_raw_read (regcache, fpnum, mmx_buf);
-      memcpy (buf, mmx_buf, REGISTER_RAW_SIZE (regnum));
+      memcpy (buf, mmx_buf, register_size (gdbarch, regnum));
     }
   else
     regcache_raw_read (regcache, regnum, buf);
@@ -1305,72 +1359,150 @@ i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
       /* Read ...  */
       regcache_raw_read (regcache, fpnum, mmx_buf);
       /* ... Modify ... (always little endian).  */
-      memcpy (mmx_buf, buf, REGISTER_RAW_SIZE (regnum));
+      memcpy (mmx_buf, buf, register_size (gdbarch, regnum));
       /* ... Write.  */
       regcache_raw_write (regcache, fpnum, mmx_buf);
     }
   else
     regcache_raw_write (regcache, regnum, buf);
 }
+\f
+
+/* These registers don't have pervasive standard uses.  Move them to
+   i386-tdep.h if necessary.  */
+
+#define I386_EBX_REGNUM                3 /* %ebx */
+#define I386_ECX_REGNUM                1 /* %ecx */
+#define I386_ESI_REGNUM                6 /* %esi */
+#define I386_EDI_REGNUM                7 /* %edi */
+
+/* Return the register number of the register allocated by GCC after
+   REGNUM, or -1 if there is no such register.  */
+
+static int
+i386_next_regnum (int regnum)
+{
+  /* GCC allocates the registers in the order:
+
+     %eax, %edx, %ecx, %ebx, %esi, %edi, %ebp, %esp, ...
+
+     Since storing a variable in %esp doesn't make any sense we return
+     -1 for %ebp and for %esp itself.  */
+  static int next_regnum[] =
+  {
+    I386_EDX_REGNUM,           /* Slot for %eax.  */
+    I386_EBX_REGNUM,           /* Slot for %ecx.  */
+    I386_ECX_REGNUM,           /* Slot for %edx.  */
+    I386_ESI_REGNUM,           /* Slot for %ebx.  */
+    -1, -1,                    /* Slots for %esp and %ebp.  */
+    I386_EDI_REGNUM,           /* Slot for %esi.  */
+    I386_EBP_REGNUM            /* Slot for %edi.  */
+  };
+
+  if (regnum >= 0 && regnum < sizeof (next_regnum) / sizeof (next_regnum[0]))
+    return next_regnum[regnum];
+
+  return -1;
+}
 
-/* Return true iff register REGNUM's virtual format is different from
-   its raw format.  Note that this definition assumes that the host
-   supports IEEE 32-bit floats, since it doesn't say that SSE
-   registers need conversion.  Even if we can't find a counterexample,
-   this is still sloppy.  */
+/* Return nonzero if a value of type TYPE stored in register REGNUM
+   needs any special handling.  */
 
 static int
-i386_register_convertible (int regnum)
+i386_convert_register_p (int regnum, struct type *type)
 {
+  int len = TYPE_LENGTH (type);
+
+  /* Values may be spread across multiple registers.  Most debugging
+     formats aren't expressive enough to specify the locations, so
+     some heuristics is involved.  Right now we only handle types that
+     have a length that is a multiple of the word size, since GCC
+     doesn't seem to put any other types into registers.  */
+  if (len > 4 && len % 4 == 0)
+    {
+      int last_regnum = regnum;
+
+      while (len > 4)
+       {
+         last_regnum = i386_next_regnum (last_regnum);
+         len -= 4;
+       }
+
+      if (last_regnum != -1)
+       return 1;
+    }
+
   return i386_fp_regnum_p (regnum);
 }
 
-/* Convert data from raw format for register REGNUM in buffer FROM to
-   virtual format with type TYPE in buffer TO.  */
+/* Read a value of type TYPE from register REGNUM in frame FRAME, and
+   return its contents in TO.  */
 
 static void
-i386_register_convert_to_virtual (int regnum, struct type *type,
-                                 char *from, char *to)
+i386_register_to_value (struct frame_info *frame, int regnum,
+                       struct type *type, void *to)
 {
-  gdb_assert (i386_fp_regnum_p (regnum));
+  int len = TYPE_LENGTH (type);
+  char *buf = to;
+
+  /* FIXME: kettenis/20030609: What should we do if REGNUM isn't
+     available in FRAME (i.e. if it wasn't saved)?  */
 
-  /* We only support floating-point values.  */
-  if (TYPE_CODE (type) != TYPE_CODE_FLT)
+  if (i386_fp_regnum_p (regnum))
     {
-      warning ("Cannot convert floating-point register value "
-              "to non-floating-point type.");
-      memset (to, 0, TYPE_LENGTH (type));
+      i387_register_to_value (frame, regnum, type, to);
       return;
     }
 
-  /* Convert to TYPE.  This should be a no-op if TYPE is equivalent to
-     the extended floating-point format used by the FPU.  */
-  convert_typed_floating (from, builtin_type_i387_ext, to, type);
+  /* Read a value spread accross multiple registers.  */
+
+  gdb_assert (len > 4 && len % 4 == 0);
+
+  while (len > 0)
+    {
+      gdb_assert (regnum != -1);
+      gdb_assert (register_size (current_gdbarch, regnum) == 4);
+
+      get_frame_register (frame, regnum, buf);
+      regnum = i386_next_regnum (regnum);
+      len -= 4;
+      buf += 4;
+    }
 }
 
-/* Convert data from virtual format with type TYPE in buffer FROM to
-   raw format for register REGNUM in buffer TO.  */
+/* Write the contents FROM of a value of type TYPE into register
+   REGNUM in frame FRAME.  */
 
 static void
-i386_register_convert_to_raw (struct type *type, int regnum,
-                             char *from, char *to)
+i386_value_to_register (struct frame_info *frame, int regnum,
+                       struct type *type, const void *from)
 {
-  gdb_assert (i386_fp_regnum_p (regnum));
+  int len = TYPE_LENGTH (type);
+  const char *buf = from;
 
-  /* We only support floating-point values.  */
-  if (TYPE_CODE (type) != TYPE_CODE_FLT)
+  if (i386_fp_regnum_p (regnum))
     {
-      warning ("Cannot convert non-floating-point type "
-              "to floating-point register value.");
-      memset (to, 0, TYPE_LENGTH (type));
+      i387_value_to_register (frame, regnum, type, from);
       return;
     }
 
-  /* Convert from TYPE.  This should be a no-op if TYPE is equivalent
-     to the extended floating-point format used by the FPU.  */
-  convert_typed_floating (from, type, to, builtin_type_i387_ext);
+  /* Write a value spread accross multiple registers.  */
+
+  gdb_assert (len > 4 && len % 4 == 0);
+
+  while (len > 0)
+    {
+      gdb_assert (regnum != -1);
+      gdb_assert (register_size (current_gdbarch, regnum) == 4);
+
+      put_frame_register (frame, regnum, buf);
+      regnum = i386_next_regnum (regnum);
+      len -= 4;
+      buf += 4;
+    }
 }
-\f     
+\f
+
 
 #ifdef STATIC_TRANSFORM_NAME
 /* SunPRO encodes the static variables.  This is not related to C++
@@ -1435,7 +1567,7 @@ i386_pc_in_sigtramp (CORE_ADDR pc, char *name)
    deals with switching between those.  */
 
 static int
-i386_print_insn (bfd_vma pc, disassemble_info *info)
+i386_print_insn (bfd_vma pc, struct disassemble_info *info)
 {
   gdb_assert (disassembly_flavor == att_flavor
              || disassembly_flavor == intel_flavor);
@@ -1599,6 +1731,17 @@ i386_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
 }
 \f
 
+/* Get the ARGIth function argument for the current function.  */
+
+static CORE_ADDR
+i386_fetch_pointer_argument (struct frame_info *frame, int argi, 
+                            struct type *type)
+{
+  CORE_ADDR sp = get_frame_register_unsigned  (frame, I386_ESP_REGNUM);
+  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)
 {
@@ -1614,10 +1757,23 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   tdep = XMALLOC (struct gdbarch_tdep);
   gdbarch = gdbarch_alloc (&info, tdep);
 
-  /* The i386 default settings don't include the SSE registers.
+  /* The i386 default settings now include the SSE registers.
+     I386_NUM_XREGS includes mxcsr, and we don't want to count
+     this as one of the xmm regs -- which is why we subtract one.
+
+     Note: kevinb/2003-07-14: Whatever Mark's concerns are about the
+     FPU registers in the FIXME below apply to the SSE registers as well.
+     The only problem that I see is that these registers will show up
+     in "info all-registers" even on CPUs where they don't exist.  IMO,
+     however, if it's a choice between printing them 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.  Ideally, of course,
+     we'd somehow autodetect that we have them (or not) and display them
+     when we have them and suppress them when we don't.
+
      FIXME: kettenis/20020614: They do include the FPU registers for
      now, which probably is not quite right.  */
-  tdep->num_xmm_regs = 0;
+  tdep->num_xmm_regs = I386_NUM_XREGS - 1;
 
   tdep->jb_pc_offset = -1;
   tdep->struct_return = pcc_struct_return;
@@ -1639,9 +1795,9 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
      alignment.  */
   set_gdbarch_long_double_bit (gdbarch, 96);
 
-  /* The default ABI includes general-purpose registers and
-     floating-point registers.  */
-  set_gdbarch_num_regs (gdbarch, I386_NUM_GREGS + I386_NUM_FREGS);
+  /* 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);
 
@@ -1669,10 +1825,9 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   /* Call dummy code.  */
   set_gdbarch_push_dummy_call (gdbarch, i386_push_dummy_call);
 
-  set_gdbarch_register_convertible (gdbarch, i386_register_convertible);
-  set_gdbarch_register_convert_to_virtual (gdbarch,
-                                          i386_register_convert_to_virtual);
-  set_gdbarch_register_convert_to_raw (gdbarch, i386_register_convert_to_raw);
+  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_extract_return_value (gdbarch, i386_extract_return_value);
   set_gdbarch_store_return_value (gdbarch, i386_store_return_value);
@@ -1690,7 +1845,6 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_function_start_offset (gdbarch, 0);
 
   set_gdbarch_frame_args_skip (gdbarch, 8);
-  set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown);
   set_gdbarch_pc_in_sigtramp (gdbarch, i386_pc_in_sigtramp);
 
   /* Wire in the MMX registers.  */
@@ -1701,7 +1855,6 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_print_insn (gdbarch, i386_print_insn);
 
   set_gdbarch_unwind_dummy_id (gdbarch, i386_unwind_dummy_id);
-  set_gdbarch_save_dummy_frame_tos (gdbarch, i386_save_dummy_frame_tos);
 
   set_gdbarch_unwind_pc (gdbarch, i386_unwind_pc);
 
@@ -1709,13 +1862,19 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   i386_add_reggroups (gdbarch);
   set_gdbarch_register_reggroup_p (gdbarch, i386_register_reggroup_p);
 
+  /* Helper for function argument information.  */
+  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);
+
   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_predicate (gdbarch, i386_sigtramp_frame_p);
-  frame_unwind_append_predicate (gdbarch, i386_frame_p);
+  frame_unwind_append_sniffer (gdbarch, i386_sigtramp_frame_sniffer);
+  frame_unwind_append_sniffer (gdbarch, i386_frame_sniffer);
 
   return gdbarch;
 }
This page took 0.030511 seconds and 4 git commands to generate.