gdb/
[deliverable/binutils-gdb.git] / gdb / i386-tdep.c
index f093e48b1de4776cedbd85b59481e1f754e8491e..5fb2efb0deb156b4c73d8ebdb70485f34243b6bc 100644 (file)
@@ -45,7 +45,7 @@
 #include "dis-asm.h"
 #include "disasm.h"
 #include "remote.h"
-
+#include "exceptions.h"
 #include "gdb_assert.h"
 #include "gdb_string.h"
 
@@ -747,7 +747,14 @@ i386_relocate_instruction (struct gdbarch *gdbarch,
       /* Adjust the destination offset.  */
       rel32 = extract_signed_integer (insn + 1, 4, byte_order);
       newrel = (oldloc - *to) + rel32;
-      store_signed_integer (insn + 1, 4, newrel, byte_order);
+      store_signed_integer (insn + 1, 4, byte_order, newrel);
+
+      if (debug_displaced)
+       fprintf_unfiltered (gdb_stdlog,
+                           "Adjusted insn rel32=%s at %s to"
+                           " rel32=%s at %s\n",
+                           hex_string (rel32), paddress (gdbarch, oldloc),
+                           hex_string (newrel), paddress (gdbarch, *to));
 
       /* Write the adjusted jump into its displaced location.  */
       append_insns (to, 5, insn);
@@ -766,11 +773,11 @@ i386_relocate_instruction (struct gdbarch *gdbarch,
     {
       rel32 = extract_signed_integer (insn + offset, 4, byte_order);
       newrel = (oldloc - *to) + rel32;
-      store_signed_integer (insn + offset, 4, newrel, byte_order);
+      store_signed_integer (insn + offset, 4, byte_order, newrel);
       if (debug_displaced)
        fprintf_unfiltered (gdb_stdlog,
-                           "Adjusted insn rel32=0x%s at 0x%s to"
-                           " rel32=0x%s at 0x%s\n",
+                           "Adjusted insn rel32=%s at %s to"
+                           " rel32=%s at %s\n",
                            hex_string (rel32), paddress (gdbarch, oldloc),
                            hex_string (newrel), paddress (gdbarch, *to));
     }
@@ -797,6 +804,7 @@ struct i386_frame_cache
 {
   /* Base address.  */
   CORE_ADDR base;
+  int base_p;
   LONGEST sp_offset;
   CORE_ADDR pc;
 
@@ -821,6 +829,7 @@ i386_alloc_frame_cache (void)
   cache = FRAME_OBSTACK_ZALLOC (struct i386_frame_cache);
 
   /* Base address.  */
+  cache->base_p = 0;
   cache->base = 0;
   cache->sp_offset = -4;
   cache->pc = 0;
@@ -850,7 +859,9 @@ i386_follow_jump (struct gdbarch *gdbarch, CORE_ADDR pc)
   long delta = 0;
   int data16 = 0;
 
-  target_read_memory (pc, &op, 1);
+  if (target_read_memory (pc, &op, 1))
+    return pc;
+
   if (op == 0x66)
     {
       data16 = 1;
@@ -916,12 +927,15 @@ i386_analyze_struct_return (CORE_ADDR pc, CORE_ADDR current_pc,
   if (current_pc <= pc)
     return pc;
 
-  target_read_memory (pc, &op, 1);
+  if (target_read_memory (pc, &op, 1))
+    return pc;
 
   if (op != 0x58)              /* popl %eax */
     return pc;
 
-  target_read_memory (pc + 1, buf, 4);
+  if (target_read_memory (pc + 1, buf, 4))
+    return pc;
+
   if (memcmp (buf, proto1, 3) != 0 && memcmp (buf, proto2, 4) != 0)
     return pc;
 
@@ -960,7 +974,8 @@ i386_skip_probe (CORE_ADDR pc)
   gdb_byte buf[8];
   gdb_byte op;
 
-  target_read_memory (pc, &op, 1);
+  if (target_read_memory (pc, &op, 1))
+    return pc;
 
   if (op == 0x68 || op == 0x6a)
     {
@@ -1111,42 +1126,91 @@ struct i386_insn
   gdb_byte mask[I386_MAX_MATCHED_INSN_LEN];
 };
 
-/* Search for the instruction at PC in the list SKIP_INSNS.  Return
+/* Return whether instruction at PC matches PATTERN.  */
+
+static int
+i386_match_pattern (CORE_ADDR pc, struct i386_insn pattern)
+{
+  gdb_byte op;
+
+  if (target_read_memory (pc, &op, 1))
+    return 0;
+
+  if ((op & pattern.mask[0]) == pattern.insn[0])
+    {
+      gdb_byte buf[I386_MAX_MATCHED_INSN_LEN - 1];
+      int insn_matched = 1;
+      size_t i;
+
+      gdb_assert (pattern.len > 1);
+      gdb_assert (pattern.len <= I386_MAX_MATCHED_INSN_LEN);
+
+      if (target_read_memory (pc + 1, buf, pattern.len - 1))
+       return 0;
+
+      for (i = 1; i < pattern.len; i++)
+       {
+         if ((buf[i - 1] & pattern.mask[i]) != pattern.insn[i])
+           insn_matched = 0;
+       }
+      return insn_matched;
+    }
+  return 0;
+}
+
+/* Search for the instruction at PC in the list INSN_PATTERNS.  Return
    the first instruction description that matches.  Otherwise, return
    NULL.  */
 
 static struct i386_insn *
-i386_match_insn (CORE_ADDR pc, struct i386_insn *skip_insns)
+i386_match_insn (CORE_ADDR pc, struct i386_insn *insn_patterns)
 {
-  struct i386_insn *insn;
+  struct i386_insn *pattern;
+
+  for (pattern = insn_patterns; pattern->len > 0; pattern++)
+    {
+      if (i386_match_pattern (pc, *pattern))
+       return pattern;
+    }
+
+  return NULL;
+}
+
+/* Return whether PC points inside a sequence of instructions that
+   matches INSN_PATTERNS.  */
+
+static int
+i386_match_insn_block (CORE_ADDR pc, struct i386_insn *insn_patterns)
+{
+  CORE_ADDR current_pc;
+  int ix, i;
   gdb_byte op;
+  struct i386_insn *insn;
 
-  target_read_memory (pc, &op, 1);
+  insn = i386_match_insn (pc, insn_patterns);
+  if (insn == NULL)
+    return 0;
 
-  for (insn = skip_insns; insn->len > 0; insn++)
+  current_pc = pc;
+  ix = insn - insn_patterns;
+  for (i = ix - 1; i >= 0; i--)
     {
-      if ((op & insn->mask[0]) == insn->insn[0])
-       {
-         gdb_byte buf[I386_MAX_MATCHED_INSN_LEN - 1];
-         int insn_matched = 1;
-         size_t i;
+      current_pc -= insn_patterns[i].len;
 
-         gdb_assert (insn->len > 1);
-         gdb_assert (insn->len <= I386_MAX_MATCHED_INSN_LEN);
+      if (!i386_match_pattern (current_pc, insn_patterns[i]))
+       return 0;
+    }
 
-         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])
-               insn_matched = 0;
-           }
+  current_pc = pc + insn->len;
+  for (insn = insn_patterns + ix + 1; insn->len > 0; insn++)
+    {
+      if (!i386_match_pattern (current_pc, *insn))
+       return 0;
 
-         if (insn_matched)
-           return insn;
-       }
+      current_pc += insn->len;
     }
 
-  return NULL;
+  return 1;
 }
 
 /* Some special instructions that might be migrated by GCC into the
@@ -1212,7 +1276,8 @@ i386_skip_noop (CORE_ADDR pc)
   gdb_byte op;
   int check = 1;
 
-  target_read_memory (pc, &op, 1);
+  if (target_read_memory (pc, &op, 1))
+    return pc;
 
   while (check) 
     {
@@ -1221,7 +1286,8 @@ i386_skip_noop (CORE_ADDR pc)
       if (op == 0x90) 
        {
          pc += 1;
-         target_read_memory (pc, &op, 1);
+         if (target_read_memory (pc, &op, 1))
+           return pc;
          check = 1;
        }
       /* Ignore no-op instruction `mov %edi, %edi'.
@@ -1237,11 +1303,15 @@ i386_skip_noop (CORE_ADDR pc)
 
       else if (op == 0x8b)
        {
-         target_read_memory (pc + 1, &op, 1);
+         if (target_read_memory (pc + 1, &op, 1))
+           return pc;
+
          if (op == 0xff)
            {
              pc += 2;
-             target_read_memory (pc, &op, 1);
+             if (target_read_memory (pc, &op, 1))
+               return pc;
+
              check = 1;
            }
        }
@@ -1267,7 +1337,8 @@ i386_analyze_frame_setup (struct gdbarch *gdbarch,
   if (limit <= pc)
     return limit;
 
-  target_read_memory (pc, &op, 1);
+  if (target_read_memory (pc, &op, 1))
+    return pc;
 
   if (op == 0x55)              /* pushl %ebp */
     {
@@ -1302,7 +1373,8 @@ i386_analyze_frame_setup (struct gdbarch *gdbarch,
       if (limit <= pc + skip)
        return limit;
 
-      target_read_memory (pc + skip, &op, 1);
+      if (target_read_memory (pc + skip, &op, 1))
+       return pc + skip;
 
       /* Check for `movl %esp, %ebp' -- can be written in two ways.  */
       switch (op)
@@ -1338,7 +1410,8 @@ i386_analyze_frame_setup (struct gdbarch *gdbarch,
 
         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.  */
-      target_read_memory (pc, &op, 1);
+      if (target_read_memory (pc, &op, 1))
+       return pc;
       if (op == 0x83)
        {
          /* `subl' with 8-bit immediate.  */
@@ -1394,7 +1467,8 @@ i386_analyze_register_saves (CORE_ADDR pc, CORE_ADDR current_pc,
     offset -= cache->locals;
   for (i = 0; i < 8 && pc < current_pc; i++)
     {
-      target_read_memory (pc, &op, 1);
+      if (target_read_memory (pc, &op, 1))
+       return pc;
       if (op < 0x50 || op > 0x57)
        break;
 
@@ -1487,7 +1561,9 @@ i386_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc)
 
   for (i = 0; i < 6; i++)
     {
-      target_read_memory (pc + i, &op, 1);
+      if (target_read_memory (pc + i, &op, 1))
+       return pc;
+
       if (pic_pat[i] != op)
        break;
     }
@@ -1495,7 +1571,8 @@ i386_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc)
     {
       int delta = 6;
 
-      target_read_memory (pc + delta, &op, 1);
+      if (target_read_memory (pc + delta, &op, 1))
+       return pc;
 
       if (op == 0x89)          /* movl %ebx, x(%ebp) */
        {
@@ -1508,7 +1585,8 @@ i386_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc)
          else                  /* Unexpected instruction.  */
            delta = 0;
 
-          target_read_memory (pc + delta, &op, 1);
+          if (target_read_memory (pc + delta, &op, 1))
+           return pc;
        }
 
       /* addl y,%ebx */
@@ -1538,7 +1616,8 @@ i386_skip_main_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   gdb_byte op;
 
-  target_read_memory (pc, &op, 1);
+  if (target_read_memory (pc, &op, 1))
+    return pc;
   if (op == 0xe8)
     {
       gdb_byte buf[4];
@@ -1577,20 +1656,16 @@ i386_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
 
 /* Normal frames.  */
 
-static struct i386_frame_cache *
-i386_frame_cache (struct frame_info *this_frame, void **this_cache)
+static void
+i386_frame_cache_1 (struct frame_info *this_frame,
+                   struct i386_frame_cache *cache)
 {
   struct gdbarch *gdbarch = get_frame_arch (this_frame);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-  struct i386_frame_cache *cache;
   gdb_byte buf[4];
   int i;
 
-  if (*this_cache)
-    return *this_cache;
-
-  cache = i386_alloc_frame_cache ();
-  *this_cache = cache;
+  cache->pc = get_frame_func (this_frame);
 
   /* In principle, for normal frames, %ebp holds the frame pointer,
      which holds the base address for the current stack frame.
@@ -1604,23 +1679,15 @@ i386_frame_cache (struct frame_info *this_frame, void **this_cache)
   get_frame_register (this_frame, I386_EBP_REGNUM, buf);
   cache->base = extract_unsigned_integer (buf, 4, byte_order);
   if (cache->base == 0)
-    return cache;
+    return;
 
   /* For normal frames, %eip is stored at 4(%ebp).  */
   cache->saved_regs[I386_EIP_REGNUM] = 4;
 
-  cache->pc = get_frame_func (this_frame);
   if (cache->pc != 0)
     i386_analyze_prologue (gdbarch, 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, byte_order);
-    }
-
   if (cache->locals < 0)
     {
       /* We didn't find a valid frame, which means that CACHE->base
@@ -1633,6 +1700,10 @@ i386_frame_cache (struct frame_info *this_frame, void **this_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, byte_order);
+
          /* We're halfway aligning the stack.  */
          cache->base = ((cache->saved_sp - 4) & 0xfffffff0) - 4;
          cache->saved_regs[I386_EIP_REGNUM] = cache->saved_sp - 4;
@@ -1660,9 +1731,17 @@ i386_frame_cache (struct frame_info *this_frame, void **this_cache)
        cache->saved_regs[I386_EBP_REGNUM] = 0;
     }
 
+  if (cache->saved_sp_reg != -1)
+    {
+      /* Saved stack pointer has been saved (but the SAVED_SP_REG
+        register may be unavailable).  */
+      if (cache->saved_sp == 0
+         && frame_register_read (this_frame, cache->saved_sp_reg, buf))
+       cache->saved_sp = extract_unsigned_integer (buf, 4, byte_order);
+    }
   /* Now that we have the base address for the stack frame we can
      calculate the value of %esp in the calling frame.  */
-  if (cache->saved_sp == 0)
+  else if (cache->saved_sp == 0)
     cache->saved_sp = cache->base + 8;
 
   /* Adjust all the saved registers such that they contain addresses
@@ -1671,6 +1750,28 @@ i386_frame_cache (struct frame_info *this_frame, void **this_cache)
     if (cache->saved_regs[i] != -1)
       cache->saved_regs[i] += cache->base;
 
+  cache->base_p = 1;
+}
+
+static struct i386_frame_cache *
+i386_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+  volatile struct gdb_exception ex;
+  struct i386_frame_cache *cache;
+
+  if (*this_cache)
+    return *this_cache;
+
+  cache = i386_alloc_frame_cache ();
+  *this_cache = cache;
+
+  TRY_CATCH (ex, RETURN_MASK_ERROR)
+    {
+      i386_frame_cache_1 (this_frame, cache);
+    }
+  if (ex.reason < 0 && ex.error != NOT_AVAILABLE_ERROR)
+    throw_exception (ex);
+
   return cache;
 }
 
@@ -1688,6 +1789,22 @@ i386_frame_this_id (struct frame_info *this_frame, void **this_cache,
   (*this_id) = frame_id_build (cache->base + 8, cache->pc);
 }
 
+static enum unwind_stop_reason
+i386_frame_unwind_stop_reason (struct frame_info *this_frame,
+                              void **this_cache)
+{
+  struct i386_frame_cache *cache = i386_frame_cache (this_frame, this_cache);
+
+  if (!cache->base_p)
+    return UNWIND_UNAVAILABLE;
+
+  /* This marks the outermost frame.  */
+  if (cache->base == 0)
+    return UNWIND_OUTERMOST;
+
+  return UNWIND_NO_REASON;
+}
+
 static struct value *
 i386_frame_prev_register (struct frame_info *this_frame, void **this_cache,
                          int regnum)
@@ -1727,8 +1844,19 @@ i386_frame_prev_register (struct frame_info *this_frame, void **this_cache,
   if (regnum == I386_EIP_REGNUM && cache->pc_in_eax)
     return frame_unwind_got_register (this_frame, regnum, I386_EAX_REGNUM);
 
-  if (regnum == I386_ESP_REGNUM && cache->saved_sp)
-    return frame_unwind_got_constant (this_frame, regnum, cache->saved_sp);
+  if (regnum == I386_ESP_REGNUM
+      && (cache->saved_sp != 0 || cache->saved_sp_reg != -1))
+    {
+      /* If the SP has been saved, but we don't know where, then this
+        means that SAVED_SP_REG register was found unavailable back
+        when we built the cache.  */
+      if (cache->saved_sp == 0)
+       return frame_unwind_got_register (this_frame, regnum,
+                                         cache->saved_sp_reg);
+      else
+       return frame_unwind_got_constant (this_frame, regnum,
+                                         cache->saved_sp);
+    }
 
   if (regnum < I386_NUM_SAVED_REGS && cache->saved_regs[regnum] != -1)
     return frame_unwind_got_memory (this_frame, regnum,
@@ -1740,6 +1868,7 @@ i386_frame_prev_register (struct frame_info *this_frame, void **this_cache,
 static const struct frame_unwind i386_frame_unwind =
 {
   NORMAL_FRAME,
+  i386_frame_unwind_stop_reason,
   i386_frame_this_id,
   i386_frame_prev_register,
   NULL,
@@ -1756,6 +1885,11 @@ static int
 i386_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
 {
   gdb_byte insn;
+  struct symtab *symtab;
+
+  symtab = find_pc_symtab (pc);
+  if (symtab && symtab->epilogue_unwind_valid)
+    return 0;
 
   if (target_read_memory (pc, &insn, 1))
     return 0;  /* Can't read memory at pc.  */
@@ -1781,10 +1915,9 @@ i386_epilogue_frame_sniffer (const struct frame_unwind *self,
 static struct i386_frame_cache *
 i386_epilogue_frame_cache (struct frame_info *this_frame, void **this_cache)
 {
-  struct gdbarch *gdbarch = get_frame_arch (this_frame);
-  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  volatile struct gdb_exception ex;
   struct i386_frame_cache *cache;
-  gdb_byte buf[4];
+  CORE_ADDR sp;
 
   if (*this_cache)
     return *this_cache;
@@ -1792,44 +1925,156 @@ i386_epilogue_frame_cache (struct frame_info *this_frame, void **this_cache)
   cache = i386_alloc_frame_cache ();
   *this_cache = cache;
 
-  /* Cache base will be %esp plus cache->sp_offset (-4).  */
-  get_frame_register (this_frame, I386_ESP_REGNUM, buf);
-  cache->base = extract_unsigned_integer (buf, 4, 
-                                         byte_order) + cache->sp_offset;
-
-  /* Cache pc will be the frame func.  */
-  cache->pc = get_frame_pc (this_frame);
+  TRY_CATCH (ex, RETURN_MASK_ERROR)
+    {
+      cache->pc = get_frame_func (this_frame);
 
-  /* The saved %esp will be at cache->base plus 8.  */
-  cache->saved_sp = cache->base + 8;
+      /* At this point the stack looks as if we just entered the
+        function, with the return address at the top of the
+        stack.  */
+      sp = get_frame_register_unsigned (this_frame, I386_ESP_REGNUM);
+      cache->base = sp + cache->sp_offset;
+      cache->saved_sp = cache->base + 8;
+      cache->saved_regs[I386_EIP_REGNUM] = cache->base + 4;
 
-  /* The saved %eip will be at cache->base plus 4.  */
-  cache->saved_regs[I386_EIP_REGNUM] = cache->base + 4;
+      cache->base_p = 1;
+    }
+  if (ex.reason < 0 && ex.error != NOT_AVAILABLE_ERROR)
+    throw_exception (ex);
 
   return cache;
 }
 
+static enum unwind_stop_reason
+i386_epilogue_frame_unwind_stop_reason (struct frame_info *this_frame,
+                                       void **this_cache)
+{
+  struct i386_frame_cache *cache =
+    i386_epilogue_frame_cache (this_frame, this_cache);
+
+  if (!cache->base_p)
+    return UNWIND_UNAVAILABLE;
+
+  return UNWIND_NO_REASON;
+}
+
 static void
 i386_epilogue_frame_this_id (struct frame_info *this_frame,
                             void **this_cache,
                             struct frame_id *this_id)
 {
-  struct i386_frame_cache *cache = i386_epilogue_frame_cache (this_frame,
-                                                             this_cache);
+  struct i386_frame_cache *cache =
+    i386_epilogue_frame_cache (this_frame, this_cache);
+
+  if (!cache->base_p)
+    return;
 
   (*this_id) = frame_id_build (cache->base + 8, cache->pc);
 }
 
+static struct value *
+i386_epilogue_frame_prev_register (struct frame_info *this_frame,
+                                  void **this_cache, int regnum)
+{
+  /* Make sure we've initialized the cache.  */
+  i386_epilogue_frame_cache (this_frame, this_cache);
+
+  return i386_frame_prev_register (this_frame, this_cache, regnum);
+}
+
 static const struct frame_unwind i386_epilogue_frame_unwind =
 {
   NORMAL_FRAME,
+  i386_epilogue_frame_unwind_stop_reason,
   i386_epilogue_frame_this_id,
-  i386_frame_prev_register,
+  i386_epilogue_frame_prev_register,
   NULL, 
   i386_epilogue_frame_sniffer
 };
 \f
 
+/* Stack-based trampolines.  */
+
+/* These trampolines are used on cross x86 targets, when taking the
+   address of a nested function.  When executing these trampolines,
+   no stack frame is set up, so we are in a similar situation as in
+   epilogues and i386_epilogue_frame_this_id can be re-used.  */
+
+/* Static chain passed in register.  */
+
+struct i386_insn i386_tramp_chain_in_reg_insns[] =
+{
+  /* `movl imm32, %eax' and `movl imm32, %ecx' */
+  { 5, { 0xb8 }, { 0xfe } },
+
+  /* `jmp imm32' */
+  { 5, { 0xe9 }, { 0xff } },
+
+  {0}
+};
+
+/* Static chain passed on stack (when regparm=3).  */
+
+struct i386_insn i386_tramp_chain_on_stack_insns[] =
+{
+  /* `push imm32' */
+  { 5, { 0x68 }, { 0xff } },
+
+  /* `jmp imm32' */
+  { 5, { 0xe9 }, { 0xff } },
+
+  {0}
+};
+
+/* Return whether PC points inside a stack trampoline.   */
+
+static int
+i386_in_stack_tramp_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  gdb_byte insn;
+  char *name;
+
+  /* A stack trampoline is detected if no name is associated
+    to the current pc and if it points inside a trampoline
+    sequence.  */
+
+  find_pc_partial_function (pc, &name, NULL, NULL);
+  if (name)
+    return 0;
+
+  if (target_read_memory (pc, &insn, 1))
+    return 0;
+
+  if (!i386_match_insn_block (pc, i386_tramp_chain_in_reg_insns)
+      && !i386_match_insn_block (pc, i386_tramp_chain_on_stack_insns))
+    return 0;
+
+  return 1;
+}
+
+static int
+i386_stack_tramp_frame_sniffer (const struct frame_unwind *self,
+                               struct frame_info *this_frame,
+                               void **this_cache)
+{
+  if (frame_relative_level (this_frame) == 0)
+    return i386_in_stack_tramp_p (get_frame_arch (this_frame),
+                                 get_frame_pc (this_frame));
+  else
+    return 0;
+}
+
+static const struct frame_unwind i386_stack_tramp_frame_unwind =
+{
+  NORMAL_FRAME,
+  i386_epilogue_frame_unwind_stop_reason,
+  i386_epilogue_frame_this_id,
+  i386_epilogue_frame_prev_register,
+  NULL, 
+  i386_stack_tramp_frame_sniffer
+};
+\f
+
 /* Signal trampolines.  */
 
 static struct i386_frame_cache *
@@ -1838,6 +2083,7 @@ i386_sigtramp_frame_cache (struct frame_info *this_frame, void **this_cache)
   struct gdbarch *gdbarch = get_frame_arch (this_frame);
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  volatile struct gdb_exception ex;
   struct i386_frame_cache *cache;
   CORE_ADDR addr;
   gdb_byte buf[4];
@@ -1847,30 +2093,50 @@ i386_sigtramp_frame_cache (struct frame_info *this_frame, void **this_cache)
 
   cache = i386_alloc_frame_cache ();
 
-  get_frame_register (this_frame, I386_ESP_REGNUM, buf);
-  cache->base = extract_unsigned_integer (buf, 4, byte_order) - 4;
-
-  addr = tdep->sigcontext_addr (this_frame);
-  if (tdep->sc_reg_offset)
+  TRY_CATCH (ex, RETURN_MASK_ERROR)
     {
-      int i;
+      get_frame_register (this_frame, I386_ESP_REGNUM, buf);
+      cache->base = extract_unsigned_integer (buf, 4, byte_order) - 4;
 
-      gdb_assert (tdep->sc_num_regs <= I386_NUM_SAVED_REGS);
+      addr = tdep->sigcontext_addr (this_frame);
+      if (tdep->sc_reg_offset)
+       {
+         int i;
 
-      for (i = 0; i < tdep->sc_num_regs; i++)
-       if (tdep->sc_reg_offset[i] != -1)
-         cache->saved_regs[i] = addr + tdep->sc_reg_offset[i];
-    }
-  else
-    {
-      cache->saved_regs[I386_EIP_REGNUM] = addr + tdep->sc_pc_offset;
-      cache->saved_regs[I386_ESP_REGNUM] = addr + tdep->sc_sp_offset;
+         gdb_assert (tdep->sc_num_regs <= I386_NUM_SAVED_REGS);
+
+         for (i = 0; i < tdep->sc_num_regs; i++)
+           if (tdep->sc_reg_offset[i] != -1)
+             cache->saved_regs[i] = addr + tdep->sc_reg_offset[i];
+       }
+      else
+       {
+         cache->saved_regs[I386_EIP_REGNUM] = addr + tdep->sc_pc_offset;
+         cache->saved_regs[I386_ESP_REGNUM] = addr + tdep->sc_sp_offset;
+       }
+
+      cache->base_p = 1;
     }
+  if (ex.reason < 0 && ex.error != NOT_AVAILABLE_ERROR)
+    throw_exception (ex);
 
   *this_cache = cache;
   return cache;
 }
 
+static enum unwind_stop_reason
+i386_sigtramp_frame_unwind_stop_reason (struct frame_info *this_frame,
+                                       void **this_cache)
+{
+  struct i386_frame_cache *cache =
+    i386_sigtramp_frame_cache (this_frame, this_cache);
+
+  if (!cache->base_p)
+    return UNWIND_UNAVAILABLE;
+
+  return UNWIND_NO_REASON;
+}
+
 static void
 i386_sigtramp_frame_this_id (struct frame_info *this_frame, void **this_cache,
                             struct frame_id *this_id)
@@ -1878,6 +2144,9 @@ i386_sigtramp_frame_this_id (struct frame_info *this_frame, void **this_cache,
   struct i386_frame_cache *cache =
     i386_sigtramp_frame_cache (this_frame, this_cache);
 
+  if (!cache->base_p)
+    return;
+
   /* See the end of i386_push_dummy_call.  */
   (*this_id) = frame_id_build (cache->base + 8, get_frame_pc (this_frame));
 }
@@ -1925,6 +2194,7 @@ i386_sigtramp_frame_sniffer (const struct frame_unwind *self,
 static const struct frame_unwind i386_sigtramp_frame_unwind =
 {
   SIGTRAMP_FRAME,
+  i386_sigtramp_frame_unwind_stop_reason,
   i386_sigtramp_frame_this_id,
   i386_sigtramp_frame_prev_register,
   NULL,
@@ -2510,19 +2780,31 @@ i386_mmx_regnum_to_fp_regnum (struct regcache *regcache, int regnum)
   return (I387_ST0_REGNUM (tdep) + fpreg);
 }
 
+/* A helper function for us by i386_pseudo_register_read_value and
+   amd64_pseudo_register_read_value.  It does all the work but reads
+   the data into an already-allocated value.  */
+
 void
-i386_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
-                          int regnum, gdb_byte *buf)
+i386_pseudo_register_read_into_value (struct gdbarch *gdbarch,
+                                     struct regcache *regcache,
+                                     int regnum,
+                                     struct value *result_value)
 {
   gdb_byte raw_buf[MAX_REGISTER_SIZE];
+  enum register_status status;
+  gdb_byte *buf = value_contents_raw (result_value);
 
   if (i386_mmx_regnum_p (gdbarch, regnum))
     {
       int fpnum = i386_mmx_regnum_to_fp_regnum (regcache, regnum);
 
       /* Extract (always little endian).  */
-      regcache_raw_read (regcache, fpnum, raw_buf);
-      memcpy (buf, raw_buf, register_size (gdbarch, regnum));
+      status = regcache_raw_read (regcache, fpnum, raw_buf);
+      if (status != REG_VALID)
+       mark_value_bytes_unavailable (result_value, 0,
+                                     TYPE_LENGTH (value_type (result_value)));
+      else
+       memcpy (buf, raw_buf, register_size (gdbarch, regnum));
     }
   else
     {
@@ -2533,23 +2815,33 @@ i386_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
          regnum -= tdep->ymm0_regnum;
 
          /* Extract (always little endian).  Read lower 128bits.  */
-         regcache_raw_read (regcache,
-                            I387_XMM0_REGNUM (tdep) + regnum,
-                            raw_buf);
-         memcpy (buf, raw_buf, 16);
+         status = regcache_raw_read (regcache,
+                                     I387_XMM0_REGNUM (tdep) + regnum,
+                                     raw_buf);
+         if (status != REG_VALID)
+           mark_value_bytes_unavailable (result_value, 0, 16);
+         else
+           memcpy (buf, raw_buf, 16);
          /* Read upper 128bits.  */
-         regcache_raw_read (regcache,
-                            tdep->ymm0h_regnum + regnum,
-                            raw_buf);
-         memcpy (buf + 16, raw_buf, 16);
+         status = regcache_raw_read (regcache,
+                                     tdep->ymm0h_regnum + regnum,
+                                     raw_buf);
+         if (status != REG_VALID)
+           mark_value_bytes_unavailable (result_value, 16, 32);
+         else
+           memcpy (buf + 16, raw_buf, 16);
        }
       else if (i386_word_regnum_p (gdbarch, regnum))
        {
          int gpnum = regnum - tdep->ax_regnum;
 
          /* Extract (always little endian).  */
-         regcache_raw_read (regcache, gpnum, raw_buf);
-         memcpy (buf, raw_buf, 2);
+         status = regcache_raw_read (regcache, gpnum, raw_buf);
+         if (status != REG_VALID)
+           mark_value_bytes_unavailable (result_value, 0,
+                                         TYPE_LENGTH (value_type (result_value)));
+         else
+           memcpy (buf, raw_buf, 2);
        }
       else if (i386_byte_regnum_p (gdbarch, regnum))
        {
@@ -2560,8 +2852,11 @@ i386_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
 
          /* Extract (always little endian).  We read both lower and
             upper registers.  */
-         regcache_raw_read (regcache, gpnum % 4, raw_buf);
-         if (gpnum >= 4)
+         status = regcache_raw_read (regcache, gpnum % 4, raw_buf);
+         if (status != REG_VALID)
+           mark_value_bytes_unavailable (result_value, 0,
+                                         TYPE_LENGTH (value_type (result_value)));
+         else if (gpnum >= 4)
            memcpy (buf, raw_buf + 1, 1);
          else
            memcpy (buf, raw_buf, 1);
@@ -2571,6 +2866,22 @@ i386_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
     }
 }
 
+static struct value *
+i386_pseudo_register_read_value (struct gdbarch *gdbarch,
+                                struct regcache *regcache,
+                                int regnum)
+{
+  struct value *result;
+
+  result = allocate_value (register_type (gdbarch, regnum));
+  VALUE_LVAL (result) = lval_register;
+  VALUE_REGNUM (result) = regnum;
+
+  i386_pseudo_register_read_into_value (gdbarch, regcache, regnum, result);
+
+  return result;
+}
+
 void
 i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
                            int regnum, const gdb_byte *buf)
@@ -2702,21 +3013,17 @@ i386_convert_register_p (struct gdbarch *gdbarch,
 /* Read a value of type TYPE from register REGNUM in frame FRAME, and
    return its contents in TO.  */
 
-static void
+static int
 i386_register_to_value (struct frame_info *frame, int regnum,
-                       struct type *type, gdb_byte *to)
+                       struct type *type, gdb_byte *to,
+                       int *optimizedp, int *unavailablep)
 {
   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 (gdbarch, regnum))
-    {
-      i387_register_to_value (frame, regnum, type, to);
-      return;
-    }
+    return i387_register_to_value (frame, regnum, type, to,
+                                  optimizedp, unavailablep);
 
   /* Read a value spread across multiple registers.  */
 
@@ -2727,11 +3034,18 @@ i386_register_to_value (struct frame_info *frame, int regnum,
       gdb_assert (regnum != -1);
       gdb_assert (register_size (gdbarch, regnum) == 4);
 
-      get_frame_register (frame, regnum, to);
+      if (!get_frame_register_bytes (frame, regnum, 0,
+                                    register_size (gdbarch, regnum),
+                                    to, optimizedp, unavailablep))
+       return 0;
+
       regnum = i386_next_regnum (regnum);
       len -= 4;
       to += 4;
     }
+
+  *optimizedp = *unavailablep = 0;
+  return 1;
 }
 
 /* Write the contents FROM of a value of type TYPE into register
@@ -4543,6 +4857,7 @@ Do you want to stop the program?"),
          ir.addr -= 1;
          goto no_support;
        }
+      /* FALLTHROUGH */
     case 0x0fb2:    /* lss Gv */
     case 0x0fb4:    /* lfs Gv */
     case 0x0fb5:    /* lgs Gv */
@@ -5322,6 +5637,7 @@ Do you want to stop the program?"),
           ir.addr -= 1;
           goto no_support;
         }
+      /* FALLTHROUGH */
     case 0xf5:    /* cmc */
     case 0xf8:    /* clc */
     case 0xf9:    /* stc */
@@ -6347,7 +6663,7 @@ reswitch_prefix_add:
         case 0x660f63:      /* packsswb */
         case 0x660f64:      /* pcmpgtb */
         case 0x660f65:      /* pcmpgtw */
-        case 0x660f66:      /* pcmpgtl */
+        case 0x660f66:      /* pcmpgtd */
         case 0x660f67:      /* packuswb */
         case 0x660f68:      /* punpckhbw */
         case 0x660f69:      /* punpckhwd */
@@ -6363,7 +6679,7 @@ reswitch_prefix_add:
         case 0xf30f70:      /* pshufhw */
         case 0x660f74:      /* pcmpeqb */
         case 0x660f75:      /* pcmpeqw */
-        case 0x660f76:      /* pcmpeql */
+        case 0x660f76:      /* pcmpeqd */
         case 0x660f7c:      /* haddpd */
         case 0xf20f7c:      /* haddps */
         case 0x660f7d:      /* hsubpd */
@@ -6418,11 +6734,11 @@ reswitch_prefix_add:
         case 0x660ff6:      /* psadbw */
         case 0x660ff8:      /* psubb */
         case 0x660ff9:      /* psubw */
-        case 0x660ffa:      /* psubl */
+        case 0x660ffa:      /* psubd */
         case 0x660ffb:      /* psubq */
         case 0x660ffc:      /* paddb */
         case 0x660ffd:      /* paddw */
-        case 0x660ffe:      /* paddl */
+        case 0x660ffe:      /* paddd */
           if (i386_record_modrm (&ir))
            return -1;
           ir.reg |= rex_r;
@@ -6558,7 +6874,7 @@ reswitch_prefix_add:
         case 0x0f63:      /* packsswb */
         case 0x0f64:      /* pcmpgtb */
         case 0x0f65:      /* pcmpgtw */
-        case 0x0f66:      /* pcmpgtl */
+        case 0x0f66:      /* pcmpgtd */
         case 0x0f67:      /* packuswb */
         case 0x0f68:      /* punpckhbw */
         case 0x0f69:      /* punpckhwd */
@@ -6569,7 +6885,7 @@ reswitch_prefix_add:
         case 0x0f70:      /* pshufw */
         case 0x0f74:      /* pcmpeqb */
         case 0x0f75:      /* pcmpeqw */
-        case 0x0f76:      /* pcmpeql */
+        case 0x0f76:      /* pcmpeqd */
         case 0x0fc4:      /* pinsrw */
         case 0x0fd1:      /* psrlw */
         case 0x0fd2:      /* psrld */
@@ -6607,11 +6923,11 @@ reswitch_prefix_add:
         case 0x0ff6:      /* psadbw */
         case 0x0ff8:      /* psubb */
         case 0x0ff9:      /* psubw */
-        case 0x0ffa:      /* psubl */
+        case 0x0ffa:      /* psubd */
         case 0x0ffb:      /* psubq */
         case 0x0ffc:      /* paddb */
         case 0x0ffd:      /* paddw */
-        case 0x0ffe:      /* paddl */
+        case 0x0ffe:      /* paddd */
           if (i386_record_modrm (&ir))
            return -1;
           if (!i386_mmx_regnum_p (gdbarch, I387_MM0_REGNUM (tdep) + ir.reg))
@@ -7032,20 +7348,21 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_fetch_pointer_argument (gdbarch, i386_fetch_pointer_argument);
 
   /* Hook the function epilogue frame unwinder.  This unwinder is
-     appended to the list first, so that it supercedes the Dwarf
-     unwinder in function epilogues (where the Dwarf unwinder
+     appended to the list first, so that it supercedes the DWARF
+     unwinder in function epilogues (where the DWARF unwinder
      currently fails).  */
   frame_unwind_append_unwinder (gdbarch, &i386_epilogue_frame_unwind);
 
   /* Hook in the DWARF CFI frame unwinder.  This unwinder is appended
-     to the list before the prologue-based unwinders, so that Dwarf
+     to the list before the prologue-based unwinders, so that DWARF
      CFI info will be used if it is available.  */
   dwarf2_append_unwinders (gdbarch);
 
   frame_base_set_default (gdbarch, &i386_frame_base);
 
   /* Pseudo registers may be changed by amd64_init_abi.  */
-  set_gdbarch_pseudo_register_read (gdbarch, i386_pseudo_register_read);
+  set_gdbarch_pseudo_register_read_value (gdbarch,
+                                         i386_pseudo_register_read_value);
   set_gdbarch_pseudo_register_write (gdbarch, i386_pseudo_register_write);
 
   set_tdesc_pseudo_register_type (gdbarch, i386_pseudo_register_type);
@@ -7144,6 +7461,7 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
     tdep->mm0_regnum = -1;
 
   /* Hook in the legacy prologue-based unwinders last (fallback).  */
+  frame_unwind_append_unwinder (gdbarch, &i386_stack_tramp_frame_unwind);
   frame_unwind_append_unwinder (gdbarch, &i386_sigtramp_frame_unwind);
   frame_unwind_append_unwinder (gdbarch, &i386_frame_unwind);
 
This page took 0.036174 seconds and 4 git commands to generate.