2012-04-27 Sergio Durigan Junior <sergiodj@redhat.com>
[deliverable/binutils-gdb.git] / gdb / amd64-tdep.c
index 9b5d5bb43af352c910c3b72dd6b4277a2b01d2c4..685fa486bf6056e2ef30b13cfb371c88ecec0313 100644 (file)
@@ -1,7 +1,6 @@
 /* Target-dependent code for AMD64.
 
-   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
-   2011 Free Software Foundation, Inc.
+   Copyright (C) 2001-2012 Free Software Foundation, Inc.
 
    Contributed by Jiri Smid, SuSE Labs.
 
@@ -45,6 +44,9 @@
 #include "features/i386/amd64.c"
 #include "features/i386/amd64-avx.c"
 
+#include "ax.h"
+#include "ax-gdb.h"
+
 /* Note that the AMD64 architecture was previously known as x86-64.
    The latter is (forever) engraved into the canonical system name as
    returned by config.guess, and used as the name for the AMD64 port
@@ -275,14 +277,21 @@ amd64_pseudo_register_name (struct gdbarch *gdbarch, int regnum)
     return i386_pseudo_register_name (gdbarch, regnum);
 }
 
-static enum register_status
-amd64_pseudo_register_read (struct gdbarch *gdbarch,
-                           struct regcache *regcache,
-                           int regnum, gdb_byte *buf)
+static struct value *
+amd64_pseudo_register_read_value (struct gdbarch *gdbarch,
+                                 struct regcache *regcache,
+                                 int regnum)
 {
   gdb_byte raw_buf[MAX_REGISTER_SIZE];
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   enum register_status status;
+  struct value *result_value;
+  gdb_byte *buf;
+
+  result_value = allocate_value (register_type (gdbarch, regnum));
+  VALUE_LVAL (result_value) = lval_register;
+  VALUE_REGNUM (result_value) = regnum;
+  buf = value_contents_raw (result_value);
 
   if (i386_byte_regnum_p (gdbarch, regnum))
     {
@@ -297,15 +306,19 @@ amd64_pseudo_register_read (struct gdbarch *gdbarch,
                                      raw_buf);
          if (status == REG_VALID)
            memcpy (buf, raw_buf + 1, 1);
+         else
+           mark_value_bytes_unavailable (result_value, 0,
+                                         TYPE_LENGTH (value_type (result_value)));
        }
       else
        {
          status = regcache_raw_read (regcache, gpnum, raw_buf);
          if (status == REG_VALID)
            memcpy (buf, raw_buf, 1);
+         else
+           mark_value_bytes_unavailable (result_value, 0,
+                                         TYPE_LENGTH (value_type (result_value)));
        }
-
-      return status;
     }
   else if (i386_dword_regnum_p (gdbarch, regnum))
     {
@@ -314,11 +327,15 @@ amd64_pseudo_register_read (struct gdbarch *gdbarch,
       status = regcache_raw_read (regcache, gpnum, raw_buf);
       if (status == REG_VALID)
        memcpy (buf, raw_buf, 4);
-
-      return status;
+      else
+       mark_value_bytes_unavailable (result_value, 0,
+                                     TYPE_LENGTH (value_type (result_value)));
     }
   else
-    return i386_pseudo_register_read (gdbarch, regcache, regnum, buf);
+    i386_pseudo_register_read_into_value (gdbarch, regcache, regnum,
+                                         result_value);
+
+  return result_value;
 }
 
 static void
@@ -518,7 +535,7 @@ amd64_classify_aggregate (struct type *type, enum amd64_reg_class class[2])
   if (class[0] == AMD64_MEMORY || class[1] == AMD64_MEMORY)
     class[0] = class[1] = AMD64_MEMORY;
 
-  /* Rule (b): If SSEUP is not preceeded by SSE, it is converted to
+  /* Rule (b): If SSEUP is not preceded by SSE, it is converted to
      SSE.  */
   if (class[0] == AMD64_SSEUP)
     class[0] = AMD64_SSE;
@@ -860,7 +877,6 @@ amd64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   /* Pass "hidden" argument".  */
   if (struct_return)
     {
-      struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
       /* The "hidden" argument is passed throught the first argument
          register.  */
       const int arg_regnum = tdep->call_dummy_integer_regs[0];
@@ -1064,9 +1080,9 @@ amd64_get_unused_input_int_reg (const struct amd64_insn *details)
       if (have_sib)
        {
          int base = SIB_BASE_FIELD (details->raw_insn[details->modrm_offset + 1]);
-         int index = SIB_INDEX_FIELD (details->raw_insn[details->modrm_offset + 1]);
+         int idx = SIB_INDEX_FIELD (details->raw_insn[details->modrm_offset + 1]);
          used_regs_mask |= 1 << base;
-         used_regs_mask |= 1 << index;
+         used_regs_mask |= 1 << idx;
        }
       else
        {
@@ -1242,7 +1258,7 @@ amd64_displaced_step_copy_insn (struct gdbarch *gdbarch,
                                struct regcache *regs)
 {
   int len = gdbarch_max_insn_length (gdbarch);
-  /* Extra space for sentinels so fixup_{riprel,displaced_copy don't have to
+  /* Extra space for sentinels so fixup_{riprel,displaced_copy} don't have to
      continually watch for running off the end of the buffer.  */
   int fixup_sentinel_space = len;
   struct displaced_step_closure *dsc =
@@ -1533,7 +1549,7 @@ append_insns (CORE_ADDR *to, ULONGEST len, const gdb_byte *buf)
   *to += len;
 }
 
-void
+static void
 amd64_relocate_instruction (struct gdbarch *gdbarch,
                            CORE_ADDR *to, CORE_ADDR oldloc)
 {
@@ -1849,7 +1865,7 @@ amd64_analyze_stack_align (CORE_ADDR pc, CORE_ADDR current_pc,
    We will handle only functions beginning with:
 
       pushq %rbp        0x55
-      movq %rsp, %rbp   0x48 0x89 0xe5
+      movq %rsp, %rbp   0x48 0x89 0xe5 (or 0x48 0x8b 0xec)
 
    Any function that doesn't start with this sequence will be assumed
    to have no prologue and thus no valid frame pointer in %rbp.  */
@@ -1860,7 +1876,9 @@ amd64_analyze_prologue (struct gdbarch *gdbarch,
                        struct amd64_frame_cache *cache)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-  static gdb_byte proto[3] = { 0x48, 0x89, 0xe5 }; /* movq %rsp, %rbp */
+  /* There are two variations of movq %rsp, %rbp.  */
+  static const gdb_byte mov_rsp_rbp_1[3] = { 0x48, 0x89, 0xe5 };
+  static const gdb_byte mov_rsp_rbp_2[3] = { 0x48, 0x8b, 0xec };
   gdb_byte buf[3];
   gdb_byte op;
 
@@ -1884,7 +1902,8 @@ amd64_analyze_prologue (struct gdbarch *gdbarch,
 
       /* Check for `movq %rsp, %rbp'.  */
       read_memory (pc + 1, buf, 3);
-      if (memcmp (buf, proto, 3) != 0)
+      if (memcmp (buf, mov_rsp_rbp_1, 3) != 0
+         && memcmp (buf, mov_rsp_rbp_2, 3) != 0)
        return pc + 1;
 
       /* OK, we actually have a frame.  */
@@ -1895,6 +1914,86 @@ amd64_analyze_prologue (struct gdbarch *gdbarch,
   return pc;
 }
 
+/* Work around false termination of prologue - GCC PR debug/48827.
+
+   START_PC is the first instruction of a function, PC is its minimal already
+   determined advanced address.  Function returns PC if it has nothing to do.
+
+   84 c0                test   %al,%al
+   74 23                je     after
+   <-- here is 0 lines advance - the false prologue end marker.
+   0f 29 85 70 ff ff ff movaps %xmm0,-0x90(%rbp)
+   0f 29 4d 80          movaps %xmm1,-0x80(%rbp)
+   0f 29 55 90          movaps %xmm2,-0x70(%rbp)
+   0f 29 5d a0          movaps %xmm3,-0x60(%rbp)
+   0f 29 65 b0          movaps %xmm4,-0x50(%rbp)
+   0f 29 6d c0          movaps %xmm5,-0x40(%rbp)
+   0f 29 75 d0          movaps %xmm6,-0x30(%rbp)
+   0f 29 7d e0          movaps %xmm7,-0x20(%rbp)
+   after:  */
+
+static CORE_ADDR
+amd64_skip_xmm_prologue (CORE_ADDR pc, CORE_ADDR start_pc)
+{
+  struct symtab_and_line start_pc_sal, next_sal;
+  gdb_byte buf[4 + 8 * 7];
+  int offset, xmmreg;
+
+  if (pc == start_pc)
+    return pc;
+
+  start_pc_sal = find_pc_sect_line (start_pc, NULL, 0);
+  if (start_pc_sal.symtab == NULL
+      || producer_is_gcc_ge_4 (start_pc_sal.symtab->producer) < 6
+      || start_pc_sal.pc != start_pc || pc >= start_pc_sal.end)
+    return pc;
+
+  next_sal = find_pc_sect_line (start_pc_sal.end, NULL, 0);
+  if (next_sal.line != start_pc_sal.line)
+    return pc;
+
+  /* START_PC can be from overlayed memory, ignored here.  */
+  if (target_read_memory (next_sal.pc - 4, buf, sizeof (buf)) != 0)
+    return pc;
+
+  /* test %al,%al */
+  if (buf[0] != 0x84 || buf[1] != 0xc0)
+    return pc;
+  /* je AFTER */
+  if (buf[2] != 0x74)
+    return pc;
+
+  offset = 4;
+  for (xmmreg = 0; xmmreg < 8; xmmreg++)
+    {
+      /* 0x0f 0x29 0b??000101 movaps %xmmreg?,-0x??(%rbp) */
+      if (buf[offset] != 0x0f || buf[offset + 1] != 0x29
+          || (buf[offset + 2] & 0x3f) != (xmmreg << 3 | 0x5))
+       return pc;
+
+      /* 0b01?????? */
+      if ((buf[offset + 2] & 0xc0) == 0x40)
+       {
+         /* 8-bit displacement.  */
+         offset += 4;
+       }
+      /* 0b10?????? */
+      else if ((buf[offset + 2] & 0xc0) == 0x80)
+       {
+         /* 32-bit displacement.  */
+         offset += 7;
+       }
+      else
+       return pc;
+    }
+
+  /* je AFTER */
+  if (offset - 4 != buf[3])
+    return pc;
+
+  return next_sal.end;
+}
+
 /* Return PC of first real instruction.  */
 
 static CORE_ADDR
@@ -1909,7 +2008,7 @@ amd64_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc)
   if (cache.frameless_p)
     return start_pc;
 
-  return pc;
+  return amd64_skip_xmm_prologue (pc, start_pc);
 }
 \f
 
@@ -2070,6 +2169,22 @@ static const struct frame_unwind amd64_frame_unwind =
   default_frame_sniffer
 };
 \f
+/* Generate a bytecode expression to get the value of the saved PC.  */
+
+static void
+amd64_gen_return_address (struct gdbarch *gdbarch,
+                         struct agent_expr *ax, struct axs_value *value,
+                         CORE_ADDR scope)
+{
+  /* The following sequence assumes the traditional use of the base
+     register.  */
+  ax_reg (ax, AMD64_RBP_REGNUM);
+  ax_const_l (ax, 8);
+  ax_simple (ax, aop_add);
+  value->type = register_type (gdbarch, AMD64_RIP_REGNUM);
+  value->kind = axs_lvalue_memory;
+}
+\f
 
 /* Signal trampolines.  */
 
@@ -2219,6 +2334,11 @@ static int
 amd64_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.  */
@@ -2489,8 +2609,8 @@ amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   /* Avoid wiring in the MMX registers for now.  */
   tdep->num_mmx_regs = 0;
 
-  set_gdbarch_pseudo_register_read (gdbarch,
-                                   amd64_pseudo_register_read);
+  set_gdbarch_pseudo_register_read_value (gdbarch,
+                                         amd64_pseudo_register_read_value);
   set_gdbarch_pseudo_register_write (gdbarch,
                                     amd64_pseudo_register_write);
 
@@ -2569,6 +2689,18 @@ amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   set_gdbarch_get_longjmp_target (gdbarch, amd64_get_longjmp_target);
 
   set_gdbarch_relocate_instruction (gdbarch, amd64_relocate_instruction);
+
+  set_gdbarch_gen_return_address (gdbarch, amd64_gen_return_address);
+
+  /* SystemTap variables and functions.  */
+  set_gdbarch_stap_integer_prefix (gdbarch, "$");
+  set_gdbarch_stap_register_prefix (gdbarch, "%");
+  set_gdbarch_stap_register_indirection_prefix (gdbarch, "(");
+  set_gdbarch_stap_register_indirection_suffix (gdbarch, ")");
+  set_gdbarch_stap_is_single_operand (gdbarch,
+                                     i386_stap_is_single_operand);
+  set_gdbarch_stap_parse_special_token (gdbarch,
+                                       i386_stap_parse_special_token);
 }
 
 /* Provide a prototype to silence -Wmissing-prototypes.  */
@@ -2662,7 +2794,7 @@ amd64_collect_fxsave (const struct regcache *regcache, int regnum,
     }
 }
 
-/* Similar to amd64_collect_fxsave, but but use XSAVE extended state.  */
+/* Similar to amd64_collect_fxsave, but use XSAVE extended state.  */
 
 void
 amd64_collect_xsave (const struct regcache *regcache, int regnum,
This page took 0.031684 seconds and 4 git commands to generate.