* psymtab.c (PSYMTAB_TO_SYMTAB): Remove.
[deliverable/binutils-gdb.git] / gdb / ppc-linux-tdep.c
index c6e4b838c09aad1f940e20e39438f7dd924d2495..3392e6799f063f7426c39890e8246adcfd591ed4 100644 (file)
@@ -1,8 +1,7 @@
 /* Target-dependent code for GDB, the GNU debugger.
 
-   Copyright (C) 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
-   Free Software Foundation, Inc.
+   Copyright (C) 1986-1987, 1989, 1991-1997, 2000-2012 Free Software
+   Foundation, Inc.
 
    This file is part of GDB.
 
@@ -38,6 +37,7 @@
 #include "solist.h"
 #include "ppc-tdep.h"
 #include "ppc-linux-tdep.h"
+#include "glibc-tdep.h"
 #include "trad-frame.h"
 #include "frame-unwind.h"
 #include "tramp-frame.h"
 #include "xml-syscall.h"
 #include "linux-tdep.h"
 
+#include "stap-probe.h"
+#include "ax.h"
+#include "ax-gdb.h"
+#include "cli/cli-utils.h"
+#include "parser-defs.h"
+#include "user-regs.h"
+#include <ctype.h>
+
 #include "features/rs6000/powerpc-32l.c"
 #include "features/rs6000/powerpc-altivec32l.c"
 #include "features/rs6000/powerpc-cell32l.c"
@@ -66,6 +74,9 @@
 #include "features/rs6000/powerpc-isa205-vsx64l.c"
 #include "features/rs6000/powerpc-e500l.c"
 
+/* Shared library operations for PowerPC-Linux.  */
+static struct target_so_ops powerpc_so_ops;
+
 /* The syscall's XML filename for PPC and PPC64.  */
 #define XML_SYSCALL_FILENAME_PPC "syscalls/ppc-linux.xml"
 #define XML_SYSCALL_FILENAME_PPC64 "syscalls/ppc64-linux.xml"
@@ -218,7 +229,7 @@ ppc_linux_memory_remove_breakpoint (struct gdbarch *gdbarch,
      program modified the code on us, so it is wrong to put back the
      old value.  */
   if (val == 0 && memcmp (bp, old_contents, bplen) == 0)
-    val = target_write_memory (addr, bp_tgt->shadow_contents, bplen);
+    val = target_write_raw_memory (addr, bp_tgt->shadow_contents, bplen);
 
   do_cleanups (cleanup);
   return val;
@@ -600,6 +611,86 @@ ppc64_standard_linkage3_target (struct frame_info *frame,
   return ppc64_desc_entry_point (gdbarch, desc);
 }
 
+/* PLT stub in executable.  */
+static struct insn_pattern powerpc32_plt_stub[] =
+  {
+    { 0xffff0000, 0x3d600000, 0 },     /* lis   r11, xxxx       */
+    { 0xffff0000, 0x816b0000, 0 },     /* lwz   r11, xxxx(r11)  */
+    { 0xffffffff, 0x7d6903a6, 0 },     /* mtctr r11             */
+    { 0xffffffff, 0x4e800420, 0 },     /* bctr                  */
+    {          0,          0, 0 }
+  };
+
+/* PLT stub in shared library.  */
+static struct insn_pattern powerpc32_plt_stub_so[] =
+  {
+    { 0xffff0000, 0x817e0000, 0 },     /* lwz   r11, xxxx(r30)  */
+    { 0xffffffff, 0x7d6903a6, 0 },     /* mtctr r11             */
+    { 0xffffffff, 0x4e800420, 0 },     /* bctr                  */
+    { 0xffffffff, 0x60000000, 0 },     /* nop                   */
+    {          0,          0, 0 }
+  };
+#define POWERPC32_PLT_STUB_LEN         ARRAY_SIZE (powerpc32_plt_stub)
+
+/* Check if PC is in PLT stub.  For non-secure PLT, stub is in .plt
+   section.  For secure PLT, stub is in .text and we need to check
+   instruction patterns.  */
+
+static int
+powerpc_linux_in_dynsym_resolve_code (CORE_ADDR pc)
+{
+  struct objfile *objfile;
+  struct minimal_symbol *sym;
+
+  /* Check whether PC is in the dynamic linker.  This also checks
+     whether it is in the .plt section, used by non-PIC executables.  */
+  if (svr4_in_dynsym_resolve_code (pc))
+    return 1;
+
+  /* Check if we are in the resolver.  */
+  sym = lookup_minimal_symbol_by_pc (pc);
+  if ((strcmp (SYMBOL_LINKAGE_NAME (sym), "__glink") == 0)
+      || (strcmp (SYMBOL_LINKAGE_NAME (sym), "__glink_PLTresolve") == 0))
+    return 1;
+
+  return 0;
+}
+
+/* Follow PLT stub to actual routine.  */
+
+static CORE_ADDR
+ppc_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
+{
+  int insnbuf[POWERPC32_PLT_STUB_LEN];
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  CORE_ADDR target = 0;
+
+  if (insns_match_pattern (pc, powerpc32_plt_stub, insnbuf))
+    {
+      /* Insn pattern is
+               lis   r11, xxxx
+               lwz   r11, xxxx(r11)
+        Branch target is in r11.  */
+
+      target = (insn_d_field (insnbuf[0]) << 16) | insn_d_field (insnbuf[1]);
+      target = read_memory_unsigned_integer (target, 4, byte_order);
+    }
+
+  if (insns_match_pattern (pc, powerpc32_plt_stub_so, insnbuf))
+    {
+      /* Insn pattern is
+               lwz   r11, xxxx(r30)
+        Branch target is in r11.  */
+
+      target = get_frame_register_unsigned (frame, tdep->ppc_gp0_regnum + 30)
+              + insn_d_field (insnbuf[0]);
+      target = read_memory_unsigned_integer (target, 4, byte_order);
+    }
+
+  return target;
+}
 
 /* Given that we've begun executing a call trampoline at PC, return
    the entry point of the function the trampoline will go to.  */
@@ -1193,6 +1284,75 @@ ppc_linux_core_read_description (struct gdbarch *gdbarch,
     }
 }
 
+/* Implementation of `gdbarch_stap_is_single_operand', as defined in
+   gdbarch.h.  */
+
+static int
+ppc_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
+{
+  return (*s == 'i' /* Literal number.  */
+         || (isdigit (*s) && s[1] == '('
+             && isdigit (s[2])) /* Displacement.  */
+         || (*s == '(' && isdigit (s[1])) /* Register indirection.  */
+         || isdigit (*s)); /* Register value.  */
+}
+
+/* Implementation of `gdbarch_stap_parse_special_token', as defined in
+   gdbarch.h.  */
+
+static int
+ppc_stap_parse_special_token (struct gdbarch *gdbarch,
+                             struct stap_parse_info *p)
+{
+  if (isdigit (*p->arg))
+    {
+      /* This temporary pointer is needed because we have to do a lookahead.
+         We could be dealing with a register displacement, and in such case
+         we would not need to do anything.  */
+      const char *s = p->arg;
+      char *regname;
+      int len;
+      struct stoken str;
+
+      while (isdigit (*s))
+       ++s;
+
+      if (*s == '(')
+       {
+         /* It is a register displacement indeed.  Returning 0 means we are
+            deferring the treatment of this case to the generic parser.  */
+         return 0;
+       }
+
+      len = s - p->arg;
+      regname = alloca (len + 2);
+      regname[0] = 'r';
+
+      strncpy (regname + 1, p->arg, len);
+      ++len;
+      regname[len] = '\0';
+
+      if (user_reg_map_name_to_regnum (gdbarch, regname, len) == -1)
+       error (_("Invalid register name `%s' on expression `%s'."),
+              regname, p->saved_arg);
+
+      write_exp_elt_opcode (OP_REGISTER);
+      str.ptr = regname;
+      str.length = len;
+      write_exp_string (str);
+      write_exp_elt_opcode (OP_REGISTER);
+
+      p->arg = s;
+    }
+  else
+    {
+      /* All the other tokens should be handled correctly by the generic
+        parser.  */
+      return 0;
+    }
+
+  return 1;
+}
 
 /* Cell/B.E. active SPE context tracking support.  */
 
@@ -1367,7 +1527,12 @@ ppu2spu_prev_register (struct frame_info *this_frame,
   gdb_byte *buf;
 
   buf = alloca (register_size (gdbarch, regnum));
-  regcache_cooked_read (cache->regcache, regnum, buf);
+
+  if (regnum < gdbarch_num_regs (gdbarch))
+    regcache_raw_read (cache->regcache, regnum, buf);
+  else
+    gdbarch_pseudo_register_read (gdbarch, cache->regcache, regnum, buf);
+
   return frame_unwind_got_bytes (this_frame, regnum, buf);
 }
 
@@ -1392,9 +1557,9 @@ ppu2spu_unwind_register (void *src, int regnum, gdb_byte *buf)
   else if (regnum == SPU_PC_REGNUM)
     store_unsigned_integer (buf, 4, byte_order, data->npc);
   else
-    return 0;
+    return REG_UNAVAILABLE;
 
-  return 1;
+  return REG_VALID;
 }
 
 static int
@@ -1505,6 +1670,15 @@ ppc_linux_init_abi (struct gdbarch_info info,
   /* Get the syscall number from the arch's register.  */
   set_gdbarch_get_syscall_number (gdbarch, ppc_linux_get_syscall_number);
 
+  /* SystemTap functions.  */
+  set_gdbarch_stap_integer_prefix (gdbarch, "i");
+  set_gdbarch_stap_register_indirection_prefix (gdbarch, "(");
+  set_gdbarch_stap_register_indirection_suffix (gdbarch, ")");
+  set_gdbarch_stap_gdb_register_prefix (gdbarch, "r");
+  set_gdbarch_stap_is_single_operand (gdbarch, ppc_stap_is_single_operand);
+  set_gdbarch_stap_parse_special_token (gdbarch,
+                                       ppc_stap_parse_special_token);
+
   if (tdep->wordsize == 4)
     {
       /* Until November 2001, gcc did not comply with the 32 bit SysV
@@ -1520,7 +1694,7 @@ ppc_linux_init_abi (struct gdbarch_info info,
                                             ppc_linux_memory_remove_breakpoint);
 
       /* Shared library handling.  */
-      set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+      set_gdbarch_skip_trampoline_code (gdbarch, ppc_skip_trampoline_code);
       set_solib_svr4_fetch_link_map_offsets
         (gdbarch, svr4_ilp32_fetch_link_map_offsets);
 
@@ -1551,6 +1725,17 @@ ppc_linux_init_abi (struct gdbarch_info info,
       else
        set_gdbarch_core_regset_sections (gdbarch,
                                          ppc_linux_fp_regset_sections);
+
+      if (powerpc_so_ops.in_dynsym_resolve_code == NULL)
+       {
+         powerpc_so_ops = svr4_so_ops;
+         /* Override dynamic resolve function.  */
+         powerpc_so_ops.in_dynsym_resolve_code =
+           powerpc_linux_in_dynsym_resolve_code;
+       }
+      set_solib_ops (gdbarch, &powerpc_so_ops);
+
+      set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
     }
   
   if (tdep->wordsize == 8)
This page took 0.027415 seconds and 4 git commands to generate.