2003-09-04 Andrew Cagney <cagney@redhat.com>
[deliverable/binutils-gdb.git] / gdb / i386-tdep.c
index 3b981806dc2677d6e56e17d8a0d3750abc05c6bf..dd19e2499d01e0e64a1aa6083ba38696ed535306 100644 (file)
@@ -41,6 +41,7 @@
 #include "symtab.h"
 #include "target.h"
 #include "value.h"
+#include "dis-asm.h"
 
 #include "gdb_assert.h"
 #include "gdb_string.h"
@@ -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;
@@ -456,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)
@@ -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] = offset;
-         offset -= 4;
-         pc++;
-       }
+      offset -= 4;
+      cache->saved_regs[op - 0x50] = offset;
+      cache->sp_offset += 4;
+      pc++;
     }
 
   return pc;
@@ -795,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);
        }
@@ -851,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;
 }
@@ -929,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
@@ -997,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;
 
@@ -1110,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)
        {
@@ -1184,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);
@@ -1299,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);
@@ -1317,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);
     }
@@ -1421,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;
@@ -1525,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);
@@ -1689,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
@@ -1715,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;
@@ -1740,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);
 
@@ -1811,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.029142 seconds and 4 git commands to generate.