2003-09-04 Andrew Cagney <cagney@redhat.com>
[deliverable/binutils-gdb.git] / gdb / i386-tdep.c
index a639b174c70d19ac8977f0904dadcfccc9936557..dd19e2499d01e0e64a1aa6083ba38696ed535306 100644 (file)
@@ -41,7 +41,7 @@
 #include "symtab.h"
 #include "target.h"
 #include "value.h"
-#include "trad-frame.h"
+#include "dis-asm.h"
 
 #include "gdb_assert.h"
 #include "gdb_string.h"
@@ -249,10 +249,8 @@ struct i386_frame_cache
   CORE_ADDR sp_offset;
   CORE_ADDR pc;
 
-  /* Saved registers.  While trad-frame allocates space for the full
-     NUM_REGS + NUM_PSEUDOREGS, some of the code below cheats and
-     allocates space for only I386_NUM_SAVED_REGS.  */
-  struct trad_frame_saved_reg *saved_regs;
+  /* Saved registers.  */
+  CORE_ADDR saved_regs[I386_NUM_SAVED_REGS];
   CORE_ADDR saved_sp;
   int pc_in_eax;
 
@@ -263,7 +261,7 @@ struct i386_frame_cache
 /* Allocate and initialize a frame cache.  */
 
 static struct i386_frame_cache *
-i386_alloc_frame_cache (struct frame_info *next_frame)
+i386_alloc_frame_cache (void)
 {
   struct i386_frame_cache *cache;
   int i;
@@ -275,7 +273,10 @@ i386_alloc_frame_cache (struct frame_info *next_frame)
   cache->sp_offset = -4;
   cache->pc = 0;
 
-  cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+  /* Saved registers.  We initialize these to -1 since zero is a valid
+     offset (that's where %ebp is supposed to be stored).  */
+  for (i = 0; i < I386_NUM_SAVED_REGS; i++)
+    cache->saved_regs[i] = -1;
   cache->saved_sp = 0;
   cache->pc_in_eax = 0;
 
@@ -439,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;
@@ -449,32 +451,68 @@ i386_analyze_frame_setup (CORE_ADDR pc, CORE_ADDR current_pc,
     {
       /* Take into account that we've executed the `pushl %ebp' that
         starts this instruction sequence.  */
-      cache->saved_regs[I386_EBP_REGNUM].addr = 0;
+      cache->saved_regs[I386_EBP_REGNUM] = 0;
       cache->sp_offset += 4;
 
       /* If that's all, return now.  */
       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)
@@ -534,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].addr = offset;
-         offset -= 4;
-         pc++;
-       }
+      offset -= 4;
+      cache->saved_regs[op - 0x50] = offset;
+      cache->sp_offset += 4;
+      pc++;
     }
 
   return pc;
@@ -609,11 +646,6 @@ i386_skip_prologue (CORE_ADDR start_pc)
   unsigned char op;
   int i;
 
-  /* Allocate space for the maximum number of saved registers.  This
-     should include all registers mentioned above, and %eip.  */
-  cache.saved_regs = alloca (I386_NUM_SAVED_REGS
-                            * sizeof (cache.saved_regs[0]));
-
   cache.locals = -1;
   pc = i386_analyze_prologue (start_pc, 0xffffffff, &cache);
   if (cache.locals < 0)
@@ -695,7 +727,7 @@ i386_frame_cache (struct frame_info *next_frame, void **this_cache)
   if (*this_cache)
     return *this_cache;
 
-  cache = i386_alloc_frame_cache (next_frame);
+  cache = i386_alloc_frame_cache ();
   *this_cache = cache;
 
   /* In principle, for normal frames, %ebp holds the frame pointer,
@@ -713,7 +745,7 @@ i386_frame_cache (struct frame_info *next_frame, void **this_cache)
     return cache;
 
   /* For normal frames, %eip is stored at 4(%ebp).  */
-  cache->saved_regs[I386_EIP_REGNUM].addr = 4;
+  cache->saved_regs[I386_EIP_REGNUM] = 4;
 
   cache->pc = frame_func_unwind (next_frame);
   if (cache->pc != 0)
@@ -740,9 +772,8 @@ i386_frame_cache (struct frame_info *next_frame, void **this_cache)
   /* Adjust all the saved registers such that they contain addresses
      instead of offsets.  */
   for (i = 0; i < I386_NUM_SAVED_REGS; i++)
-    if (cache->saved_regs[i].realnum >= 0
-       && cache->saved_regs[i].addr != -1)
-      cache->saved_regs[i].addr += cache->base;
+    if (cache->saved_regs[i] != -1)
+      cache->saved_regs[i] += cache->base;
 
   return cache;
 }
@@ -801,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);
        }
@@ -830,8 +862,23 @@ i386_frame_prev_register (struct frame_info *next_frame, void **this_cache,
       return;
     }
 
-  trad_frame_prev_register (next_frame, cache->saved_regs, regnum,
-                           optimizedp, lvalp, addrp, realnump, valuep);
+  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;
+    }
+
+  frame_register_unwind (next_frame, regnum,
+                        optimizedp, lvalp, addrp, realnump, valuep);
 }
 
 static const struct frame_unwind i386_frame_unwind =
@@ -842,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;
 }
@@ -861,7 +908,7 @@ i386_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache)
   if (*this_cache)
     return *this_cache;
 
-  cache = i386_alloc_frame_cache (next_frame);
+  cache = i386_alloc_frame_cache ();
 
   frame_unwind_register (next_frame, I386_ESP_REGNUM, buf);
   cache->base = extract_unsigned_integer (buf, 4) - 4;
@@ -875,12 +922,12 @@ i386_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache)
 
       for (i = 0; i < tdep->sc_num_regs; i++)
        if (tdep->sc_reg_offset[i] != -1)
-         cache->saved_regs[i].addr = addr + tdep->sc_reg_offset[i];
+         cache->saved_regs[i] = addr + tdep->sc_reg_offset[i];
     }
   else
     {
-      cache->saved_regs[I386_EIP_REGNUM].addr = addr + tdep->sc_pc_offset;
-      cache->saved_regs[I386_ESP_REGNUM].addr = addr + tdep->sc_sp_offset;
+      cache->saved_regs[I386_EIP_REGNUM] = addr + tdep->sc_pc_offset;
+      cache->saved_regs[I386_ESP_REGNUM] = addr + tdep->sc_sp_offset;
     }
 
   *this_cache = cache;
@@ -920,8 +967,9 @@ 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
@@ -988,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;
 
@@ -1101,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)
        {
@@ -1175,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);
@@ -1290,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);
@@ -1308,7 +1359,7 @@ 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);
     }
@@ -1412,7 +1463,7 @@ i386_register_to_value (struct frame_info *frame, int regnum,
       gdb_assert (regnum != -1);
       gdb_assert (register_size (current_gdbarch, regnum) == 4);
 
-      frame_read_register (frame, regnum, buf);
+      get_frame_register (frame, regnum, buf);
       regnum = i386_next_regnum (regnum);
       len -= 4;
       buf += 4;
@@ -1516,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);
@@ -1680,14 +1731,14 @@ i386_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
 }
 \f
 
-/* Get the ith function argument for the current function.  */
+/* 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 stack;
-  frame_read_register (frame, SP_REGNUM, &stack);
-  return read_memory_unsigned_integer (stack + (4 * (argi + 1)), 4);
+  CORE_ADDR sp = get_frame_register_unsigned  (frame, I386_ESP_REGNUM);
+  return read_memory_unsigned_integer (sp + (4 * (argi + 1)), 4);
 }
 
 \f
@@ -1706,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;
@@ -1731,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);
 
@@ -1802,16 +1866,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_predicate (gdbarch, dwarf2_frame_p);
-  set_gdbarch_dwarf2_build_frame_info (gdbarch, dwarf2_build_frame_info);
+  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.036631 seconds and 4 git commands to generate.