]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gdb/ppc-linux-tdep.c
Convert struct target_ops to C++
[thirdparty/binutils-gdb.git] / gdb / ppc-linux-tdep.c
index 5f313f85b94d764bc01056a40a9b3e14551d69c8..6d3a64c4f0dfb15181b7dc9a78b476c439781824 100644 (file)
@@ -1,6 +1,6 @@
 /* Target-dependent code for GDB, the GNU debugger.
 
-   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+   Copyright (C) 1986-2018 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -41,7 +41,7 @@
 #include "trad-frame.h"
 #include "frame-unwind.h"
 #include "tramp-frame.h"
-#include "observer.h"
+#include "observable.h"
 #include "auxv.h"
 #include "elf/common.h"
 #include "elf/ppc64.h"
@@ -60,7 +60,7 @@
 #include "parser-defs.h"
 #include "user-regs.h"
 #include <ctype.h>
-#include "elf-bfd.h"            /* for elfcore_write_* */
+#include "elf-bfd.h"
 
 #include "features/rs6000/powerpc-32l.c"
 #include "features/rs6000/powerpc-altivec32l.c"
@@ -256,8 +256,8 @@ ppc_linux_return_value (struct gdbarch *gdbarch, struct value *function,
                                      readbuf, writebuf);
 }
 
-/* PLT stub in executable.  */
-static struct ppc_insn_pattern powerpc32_plt_stub[] =
+/* PLT stub in an executable.  */
+static const struct ppc_insn_pattern powerpc32_plt_stub[] =
   {
     { 0xffff0000, 0x3d600000, 0 },     /* lis   r11, xxxx       */
     { 0xffff0000, 0x816b0000, 0 },     /* lwz   r11, xxxx(r11)  */
@@ -266,16 +266,30 @@ static struct ppc_insn_pattern powerpc32_plt_stub[] =
     {          0,          0, 0 }
   };
 
-/* PLT stub in shared library.  */
-static struct ppc_insn_pattern powerpc32_plt_stub_so[] =
+/* PLT stubs in a shared library or PIE.
+   The first variant is used when the PLT entry is within +/-32k of
+   the GOT pointer (r30).  */
+static const struct ppc_insn_pattern powerpc32_plt_stub_so_1[] =
   {
     { 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)
+
+/* The second variant is used when the PLT entry is more than +/-32k
+   from the GOT pointer (r30).  */
+static const struct ppc_insn_pattern powerpc32_plt_stub_so_2[] =
+  {
+    { 0xffff0000, 0x3d7e0000, 0 },     /* addis r11, r30, xxxx  */
+    { 0xffff0000, 0x816b0000, 0 },     /* lwz   r11, xxxx(r11)  */
+    { 0xffffffff, 0x7d6903a6, 0 },     /* mtctr r11             */
+    { 0xffffffff, 0x4e800420, 0 },     /* bctr                  */
+    {          0,          0, 0 }
+  };
+
+/* The max number of insns we check using ppc_insns_match_pattern.  */
+#define POWERPC32_PLT_CHECK_LEN (ARRAY_SIZE (powerpc32_plt_stub) - 1)
 
 /* 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
@@ -306,13 +320,13 @@ powerpc_linux_in_dynsym_resolve_code (CORE_ADDR pc)
 
    When the execution direction is EXEC_REVERSE, scan backward to
    check whether we are in the middle of a PLT stub.  Currently,
-   we only look-behind at most 4 instructions (the max length of PLT
+   we only look-behind at most 4 instructions (the max length of PLT
    stub sequence.  */
 
 static CORE_ADDR
 ppc_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
 {
-  unsigned int insnbuf[POWERPC32_PLT_STUB_LEN];
+  unsigned int insnbuf[POWERPC32_PLT_CHECK_LEN];
   struct gdbarch *gdbarch = get_frame_arch (frame);
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
@@ -323,40 +337,47 @@ ppc_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
   /* When reverse-debugging, scan backward to check whether we are
      in the middle of trampoline code.  */
   if (execution_direction == EXEC_REVERSE)
-    scan_limit = 4;    /* At more 4 instructions.  */
+    scan_limit = 4;    /* At most 4 instructions.  */
 
   for (i = 0; i < scan_limit; i++)
     {
       if (ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub, insnbuf))
        {
-         /* Insn pattern is
+         /* Calculate PLT entry address from
             lis   r11, xxxx
-            lwz   r11, xxxx(r11)
-            Branch target is in r11.  */
-
-         target = (ppc_insn_d_field (insnbuf[0]) << 16)
-                  | ppc_insn_d_field (insnbuf[1]);
-         target = read_memory_unsigned_integer (target, 4, byte_order);
+            lwz   r11, xxxx(r11).  */
+         target = ((ppc_insn_d_field (insnbuf[0]) << 16)
+                   + ppc_insn_d_field (insnbuf[1]));
+       }
+      else if (i < ARRAY_SIZE (powerpc32_plt_stub_so_1) - 1
+              && ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub_so_1,
+                                          insnbuf))
+       {
+         /* Calculate PLT entry address from
+            lwz   r11, xxxx(r30).  */
+         target = (ppc_insn_d_field (insnbuf[0])
+                   + get_frame_register_unsigned (frame,
+                                                  tdep->ppc_gp0_regnum + 30));
        }
-      else if (ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub_so,
+      else if (ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub_so_2,
                                        insnbuf))
        {
-         /* Insn pattern is
-            lwz   r11, xxxx(r30)
-            Branch target is in r11.  */
-
-         target = get_frame_register_unsigned (frame,
-                                               tdep->ppc_gp0_regnum + 30)
-                  + ppc_insn_d_field (insnbuf[0]);
-         target = read_memory_unsigned_integer (target, 4, byte_order);
+         /* Calculate PLT entry address from
+            addis r11, r30, xxxx
+            lwz   r11, xxxx(r11).  */
+         target = ((ppc_insn_d_field (insnbuf[0]) << 16)
+                   + ppc_insn_d_field (insnbuf[1])
+                   + get_frame_register_unsigned (frame,
+                                                  tdep->ppc_gp0_regnum + 30));
        }
       else
        {
-         /* Scan backward one more instructions if doesn't match.  */
+         /* Scan backward one more instruction if it doesn't match.  */
          pc -= 4;
          continue;
        }
 
+      target = read_memory_unsigned_integer (target, 4, byte_order);
       return target;
     }
 
@@ -375,7 +396,7 @@ ppc_linux_supply_gregset (const struct regset *regset,
 
   ppc_supply_gregset (regset, regcache, regnum, gregs, len);
 
-  if (ppc_linux_trap_reg_p (get_regcache_arch (regcache)))
+  if (ppc_linux_trap_reg_p (regcache->arch ()))
     {
       /* "orig_r3" is stored 2 slots after "pc".  */
       if (regnum == -1 || regnum == PPC_ORIG_R3_REGNUM)
@@ -405,7 +426,7 @@ ppc_linux_collect_gregset (const struct regset *regset,
 
   ppc_collect_gregset (regset, regcache, regnum, gregs, len);
 
-  if (ppc_linux_trap_reg_p (get_regcache_arch (regcache)))
+  if (ppc_linux_trap_reg_p (regcache->arch ()))
     {
       /* "orig_r3" is stored 2 slots after "pc".  */
       if (regnum == -1 || regnum == PPC_ORIG_R3_REGNUM)
@@ -725,28 +746,19 @@ ppc_linux_get_syscall_number (struct gdbarch *gdbarch,
   struct regcache *regcache = get_thread_regcache (ptid);
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-  struct cleanup *cleanbuf;
-  /* The content of a register */
-  gdb_byte *buf;
-  /* The result */
-  LONGEST ret;
 
   /* Make sure we're in a 32- or 64-bit machine */
   gdb_assert (tdep->wordsize == 4 || tdep->wordsize == 8);
 
-  buf = (gdb_byte *) xmalloc (tdep->wordsize * sizeof (gdb_byte));
-
-  cleanbuf = make_cleanup (xfree, buf);
+  /* The content of a register */
+  gdb::byte_vector buf (tdep->wordsize);
 
   /* Getting the system call number from the register.
      When dealing with PowerPC architecture, this information
      is stored at 0th register.  */
-  regcache_cooked_read (regcache, tdep->ppc_gp0_regnum, buf);
-
-  ret = extract_signed_integer (buf, tdep->wordsize, byte_order);
-  do_cleanups (cleanbuf);
+  regcache_cooked_read (regcache, tdep->ppc_gp0_regnum, buf.data ());
 
-  return ret;
+  return extract_signed_integer (buf.data (), tdep->wordsize, byte_order);
 }
 
 /* PPC process record-replay */
@@ -798,7 +810,7 @@ ppc_canonicalize_syscall (int syscall)
 static int
 ppc_linux_syscall_record (struct regcache *regcache)
 {
-  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct gdbarch *gdbarch = regcache->arch ();
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   ULONGEST scnum;
   enum gdb_syscall syscall_gdb;
@@ -927,7 +939,7 @@ ppc_linux_record_signal (struct gdbarch *gdbarch, struct regcache *regcache,
 static void
 ppc_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
 {
-  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct gdbarch *gdbarch = regcache->arch ();
 
   regcache_cooked_write_unsigned (regcache, gdbarch_pc_regnum (gdbarch), pc);
 
@@ -1191,7 +1203,7 @@ ppc_linux_spe_context (int wordsize, enum bfd_endian byte_order,
   /* Look up cached address of thread-local variable.  */
   if (!ptid_equal (spe_context_cache_ptid, inferior_ptid))
     {
-      struct target_ops *target = &current_target;
+      struct target_ops *target = target_stack;
 
       TRY
        {
@@ -1202,9 +1214,9 @@ ppc_linux_spe_context (int wordsize, enum bfd_endian byte_order,
             Instead, we have cached the lm_addr value, and use that to
             directly call the target's to_get_thread_local_address.  */
          spe_context_cache_address
-           = target->to_get_thread_local_address (target, inferior_ptid,
-                                                  spe_context_lm_addr,
-                                                  spe_context_offset);
+           = target->get_thread_local_address (inferior_ptid,
+                                               spe_context_lm_addr,
+                                               spe_context_offset);
          spe_context_cache_ptid = inferior_ptid;
        }
 
@@ -1250,14 +1262,14 @@ ppc_linux_spe_context (int wordsize, enum bfd_endian byte_order,
 struct ppu2spu_cache
 {
   struct frame_id frame_id;
-  struct regcache *regcache;
+  readonly_detached_regcache *regcache;
 };
 
 static struct gdbarch *
 ppu2spu_prev_arch (struct frame_info *this_frame, void **this_cache)
 {
   struct ppu2spu_cache *cache = (struct ppu2spu_cache *) *this_cache;
-  return get_regcache_arch (cache->regcache);
+  return cache->regcache->arch ();
 }
 
 static void
@@ -1273,16 +1285,12 @@ ppu2spu_prev_register (struct frame_info *this_frame,
                       void **this_cache, int regnum)
 {
   struct ppu2spu_cache *cache = (struct ppu2spu_cache *) *this_cache;
-  struct gdbarch *gdbarch = get_regcache_arch (cache->regcache);
+  struct gdbarch *gdbarch = cache->regcache->arch ();
   gdb_byte *buf;
 
   buf = (gdb_byte *) alloca (register_size (gdbarch, regnum));
 
-  if (regnum < gdbarch_num_regs (gdbarch))
-    regcache_raw_read (cache->regcache, regnum, buf);
-  else
-    gdbarch_pseudo_register_read (gdbarch, cache->regcache, regnum, buf);
-
+  cache->regcache->cooked_read (regnum, buf);
   return frame_unwind_got_bytes (this_frame, regnum, buf);
 }
 
@@ -1355,17 +1363,16 @@ ppu2spu_sniffer (const struct frame_unwind *self,
        return 0;
 
       xsnprintf (annex, sizeof annex, "%d/regs", data.id);
-      if (target_read (&current_target, TARGET_OBJECT_SPU, annex,
+      if (target_read (target_stack, TARGET_OBJECT_SPU, annex,
                       data.gprs, 0, sizeof data.gprs)
          == sizeof data.gprs)
        {
          struct ppu2spu_cache *cache
            = FRAME_OBSTACK_CALLOC (1, struct ppu2spu_cache);
-
-         struct address_space *aspace = get_frame_address_space (this_frame);
-         std::unique_ptr<struct regcache> regcache
-           (new struct regcache (data.gdbarch, aspace));
-         regcache_save (regcache.get (), ppu2spu_unwind_register, &data);
+         std::unique_ptr<readonly_detached_regcache> regcache
+           (new readonly_detached_regcache (data.gdbarch,
+                                            ppu2spu_unwind_register,
+                                            &data));
 
          cache->frame_id = frame_id_build (base, func);
          cache->regcache = regcache.release ();
@@ -1633,12 +1640,17 @@ ppc_floatformat_for_type (struct gdbarch *gdbarch,
                           const char *name, int len)
 {
   if (len == 128 && name)
-    if (strcmp (name, "__float128") == 0
-        || strcmp (name, "_Float128") == 0
-        || strcmp (name, "_Float64x") == 0
-        || strcmp (name, "complex _Float128") == 0
-        || strcmp (name, "complex _Float64x") == 0)
-      return floatformats_ia64_quad;
+    {
+      if (strcmp (name, "__float128") == 0
+         || strcmp (name, "_Float128") == 0
+         || strcmp (name, "_Float64x") == 0
+         || strcmp (name, "complex _Float128") == 0
+         || strcmp (name, "complex _Float64x") == 0)
+       return floatformats_ia64_quad;
+
+      if (strcmp (name, "__ibm128") == 0)
+       return floatformats_ibm_long_double;
+    }
 
   return default_floatformat_for_type (gdbarch, name, len);
 }
@@ -1658,12 +1670,15 @@ ppc_linux_init_abi (struct gdbarch_info info,
   linux_init_abi (info, gdbarch);
 
   /* PPC GNU/Linux uses either 64-bit or 128-bit long doubles; where
-     128-bit, they are IBM long double, not IEEE quad long double as
-     in the System V ABI PowerPC Processor Supplement.  We can safely
-     let them default to 128-bit, since the debug info will give the
-     size of type actually used in each case.  */
+     128-bit, they can be either IBM long double or IEEE quad long double.
+     The 64-bit long double case will be detected automatically using
+     the size specified in debug info.  We use a .gnu.attribute flag
+     to distinguish between the IBM long double and IEEE quad cases.  */
   set_gdbarch_long_double_bit (gdbarch, 16 * TARGET_CHAR_BIT);
-  set_gdbarch_long_double_format (gdbarch, floatformats_ibm_long_double);
+  if (tdep->long_double_abi == POWERPC_LONG_DOUBLE_IEEE128)
+    set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad);
+  else
+    set_gdbarch_long_double_format (gdbarch, floatformats_ibm_long_double);
 
   /* Support for floating-point data type variants.  */
   set_gdbarch_floatformat_for_type (gdbarch, ppc_floatformat_for_type);
@@ -1772,12 +1787,6 @@ ppc_linux_init_abi (struct gdbarch_info info,
        set_gdbarch_gcore_bfd_target (gdbarch, "elf64-powerpc");
     }
 
-  /* PPC32 uses a different prpsinfo32 compared to most other Linux
-     archs.  */
-  if (tdep->wordsize == 4)
-    set_gdbarch_elfcore_write_linux_prpsinfo (gdbarch,
-                                             elfcore_write_ppc_linux_prpsinfo32);
-
   set_gdbarch_core_read_description (gdbarch, ppc_linux_core_read_description);
   set_gdbarch_iterate_over_regset_sections (gdbarch,
                                            ppc_linux_iterate_over_regset_sections);
@@ -1817,6 +1826,10 @@ ppc_linux_init_abi (struct gdbarch_info info,
 
       /* Cell/B.E. cross-architecture unwinder support.  */
       frame_unwind_prepend_unwinder (gdbarch, &ppu2spu_unwind);
+
+      /* We need to support more than "addr_bit" significant address bits
+         in order to support SPUADDR_ADDR encoded values.  */
+      set_gdbarch_significant_addr_bit (gdbarch, 64);
     }
 
   set_gdbarch_displaced_step_location (gdbarch,
@@ -1844,9 +1857,9 @@ _initialize_ppc_linux_tdep (void)
                          ppc_linux_init_abi);
 
   /* Attach to observers to track __spe_current_active_context.  */
-  observer_attach_inferior_created (ppc_linux_spe_context_inferior_created);
-  observer_attach_solib_loaded (ppc_linux_spe_context_solib_loaded);
-  observer_attach_solib_unloaded (ppc_linux_spe_context_solib_unloaded);
+  gdb::observers::inferior_created.attach (ppc_linux_spe_context_inferior_created);
+  gdb::observers::solib_loaded.attach (ppc_linux_spe_context_solib_loaded);
+  gdb::observers::solib_unloaded.attach (ppc_linux_spe_context_solib_unloaded);
 
   /* Initialize the Linux target descriptions.  */
   initialize_tdesc_powerpc_32l ();