]> 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 fa51ed05efaa81179a73e9b051d8716b72746609..6d3a64c4f0dfb15181b7dc9a78b476c439781824 100644 (file)
@@ -1,6 +1,6 @@
 /* Target-dependent code for GDB, the GNU debugger.
 
-   Copyright (C) 1986-2014 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"
@@ -49,6 +49,9 @@
 #include "spu-tdep.h"
 #include "xml-syscall.h"
 #include "linux-tdep.h"
+#include "linux-record.h"
+#include "record-full.h"
+#include "infrun.h"
 
 #include "stap-probe.h"
 #include "ax.h"
@@ -57,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"
@@ -215,15 +218,13 @@ ppc_linux_memory_remove_breakpoint (struct gdbarch *gdbarch,
   int val;
   int bplen;
   gdb_byte old_contents[BREAKPOINT_MAX];
-  struct cleanup *cleanup;
 
   /* Determine appropriate breakpoint contents and size for this address.  */
   bp = gdbarch_breakpoint_from_pc (gdbarch, &addr, &bplen);
-  if (bp == NULL)
-    error (_("Software breakpoints not implemented for this target."));
 
   /* Make sure we see the memory breakpoints.  */
-  cleanup = make_show_memory_breakpoints_cleanup (1);
+  scoped_restore restore_memory
+    = make_scoped_restore_show_memory_breakpoints (1);
   val = target_read_memory (addr, old_contents, bplen);
 
   /* If our breakpoint is no longer at the address, this means that the
@@ -232,7 +233,6 @@ ppc_linux_memory_remove_breakpoint (struct gdbarch *gdbarch,
   if (val == 0 && memcmp (bp, old_contents, bplen) == 0)
     val = target_write_raw_memory (addr, bp_tgt->shadow_contents, bplen);
 
-  do_cleanups (cleanup);
   return val;
 }
 
@@ -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
@@ -302,41 +316,72 @@ powerpc_linux_in_dynsym_resolve_code (CORE_ADDR pc)
   return 0;
 }
 
-/* Follow PLT stub to actual routine.  */
+/* Follow PLT stub to actual routine.
+
+   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 a 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);
   CORE_ADDR target = 0;
+  int scan_limit, i;
 
-  if (ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub, insnbuf))
-    {
-      /* Insn pattern is
-               lis   r11, xxxx
-               lwz   r11, xxxx(r11)
-        Branch target is in r11.  */
+  scan_limit = 1;
+  /* 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 most 4 instructions.  */
 
-      target = (ppc_insn_d_field (insnbuf[0]) << 16)
-       | ppc_insn_d_field (insnbuf[1]);
-      target = read_memory_unsigned_integer (target, 4, byte_order);
-    }
-
-  if (ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub_so, insnbuf))
+  for (i = 0; i < scan_limit; i++)
     {
-      /* Insn pattern is
-               lwz   r11, xxxx(r30)
-        Branch target is in r11.  */
+      if (ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub, insnbuf))
+       {
+         /* Calculate PLT entry address from
+            lis   r11, xxxx
+            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_2,
+                                       insnbuf))
+       {
+         /* 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 instruction if it doesn't match.  */
+         pc -= 4;
+         continue;
+       }
 
-      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);
+      return target;
     }
 
-  return target;
+  return 0;
 }
 
 /* Wrappers to handle Linux-only registers.  */
@@ -346,21 +391,22 @@ ppc_linux_supply_gregset (const struct regset *regset,
                          struct regcache *regcache,
                          int regnum, const void *gregs, size_t len)
 {
-  const struct ppc_reg_offsets *offsets = regset->regmap;
+  const struct ppc_reg_offsets *offsets
+    = (const struct ppc_reg_offsets *) regset->regmap;
 
   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)
-       ppc_supply_reg (regcache, PPC_ORIG_R3_REGNUM, gregs,
+       ppc_supply_reg (regcache, PPC_ORIG_R3_REGNUM, (const gdb_byte *) gregs,
                        offsets->pc_offset + 2 * offsets->gpr_size,
                        offsets->gpr_size);
 
       /* "trap" is stored 8 slots after "pc".  */
       if (regnum == -1 || regnum == PPC_TRAP_REGNUM)
-       ppc_supply_reg (regcache, PPC_TRAP_REGNUM, gregs,
+       ppc_supply_reg (regcache, PPC_TRAP_REGNUM, (const gdb_byte *) gregs,
                        offsets->pc_offset + 8 * offsets->gpr_size,
                        offsets->gpr_size);
     }
@@ -371,7 +417,8 @@ ppc_linux_collect_gregset (const struct regset *regset,
                           const struct regcache *regcache,
                           int regnum, void *gregs, size_t len)
 {
-  const struct ppc_reg_offsets *offsets = regset->regmap;
+  const struct ppc_reg_offsets *offsets
+    = (const struct ppc_reg_offsets *) regset->regmap;
 
   /* Clear areas in the linux gregset not written elsewhere.  */
   if (regnum == -1)
@@ -379,17 +426,17 @@ 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)
-       ppc_collect_reg (regcache, PPC_ORIG_R3_REGNUM, gregs,
+       ppc_collect_reg (regcache, PPC_ORIG_R3_REGNUM, (gdb_byte *) gregs,
                         offsets->pc_offset + 2 * offsets->gpr_size,
                         offsets->gpr_size);
 
       /* "trap" is stored 8 slots after "pc".  */
       if (regnum == -1 || regnum == PPC_TRAP_REGNUM)
-       ppc_collect_reg (regcache, PPC_TRAP_REGNUM, gregs,
+       ppc_collect_reg (regcache, PPC_TRAP_REGNUM, (gdb_byte *) gregs,
                         offsets->pc_offset + 8 * offsets->gpr_size,
                         offsets->gpr_size);
     }
@@ -676,47 +723,6 @@ static struct tramp_frame ppc64_linux_sighandler_tramp_frame = {
   ppc64_linux_sighandler_cache_init
 };
 
-
-/* Address to use for displaced stepping.  When debugging a stand-alone
-   SPU executable, entry_point_address () will point to an SPU local-store
-   address and is thus not usable as displaced stepping location.  We use
-   the auxiliary vector to determine the PowerPC-side entry point address
-   instead.  */
-
-static CORE_ADDR ppc_linux_entry_point_addr = 0;
-
-static void
-ppc_linux_inferior_created (struct target_ops *target, int from_tty)
-{
-  ppc_linux_entry_point_addr = 0;
-}
-
-static CORE_ADDR
-ppc_linux_displaced_step_location (struct gdbarch *gdbarch)
-{
-  if (ppc_linux_entry_point_addr == 0)
-    {
-      CORE_ADDR addr;
-
-      /* Determine entry point from target auxiliary vector.  */
-      if (target_auxv_search (&current_target, AT_ENTRY, &addr) <= 0)
-       error (_("Cannot find AT_ENTRY auxiliary vector entry."));
-
-      /* Make certain that the address points at real code, and not a
-        function descriptor.  */
-      addr = gdbarch_convert_from_func_ptr_addr (gdbarch, addr,
-                                                &current_target);
-
-      /* Inferior calls also use the entry point as a breakpoint location.
-        We don't want displaced stepping to interfere with those
-        breakpoints, so leave space.  */
-      ppc_linux_entry_point_addr = addr + 2 * PPC_INSN_SIZE;
-    }
-
-  return ppc_linux_entry_point_addr;
-}
-
-
 /* Return 1 if PPC_ORIG_R3_REGNUM and PPC_TRAP_REGNUM are usable.  */
 int
 ppc_linux_trap_reg_p (struct gdbarch *gdbarch)
@@ -740,34 +746,200 @@ 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);
+  regcache_cooked_read (regcache, tdep->ppc_gp0_regnum, buf.data ());
 
-  ret = extract_signed_integer (buf, tdep->wordsize, byte_order);
-  do_cleanups (cleanbuf);
+  return extract_signed_integer (buf.data (), tdep->wordsize, byte_order);
+}
+
+/* PPC process record-replay */
+
+static struct linux_record_tdep ppc_linux_record_tdep;
+static struct linux_record_tdep ppc64_linux_record_tdep;
+
+/* ppc_canonicalize_syscall maps from the native PowerPC Linux set of
+   syscall ids into a canonical set of syscall ids used by process
+   record.  (See arch/powerpc/include/uapi/asm/unistd.h in kernel tree.)
+   Return -1 if this system call is not supported by process record.
+   Otherwise, return the syscall number for preocess reocrd of given
+   SYSCALL.  */
 
-  return ret;
+static enum gdb_syscall
+ppc_canonicalize_syscall (int syscall)
+{
+  int result = -1;
+
+  if (syscall <= 165)
+    result = syscall;
+  else if (syscall >= 167 && syscall <= 190)   /* Skip query_module 166 */
+    result = syscall + 1;
+  else if (syscall >= 192 && syscall <= 197)   /* mmap2 */
+    result = syscall;
+  else if (syscall == 208)                     /* tkill */
+    result = gdb_sys_tkill;
+  else if (syscall >= 207 && syscall <= 220)   /* gettid */
+    result = syscall + 224 - 207;
+  else if (syscall >= 234 && syscall <= 239)   /* exit_group */
+    result = syscall + 252 - 234;
+  else if (syscall >= 240 && syscall <= 248)   /* timer_create */
+    result = syscall += 259 - 240;
+  else if (syscall >= 250 && syscall <= 251)   /* tgkill */
+    result = syscall + 270 - 250;
+  else if (syscall == 336)
+    result = gdb_sys_recv;
+  else if (syscall == 337)
+    result = gdb_sys_recvfrom;
+  else if (syscall == 342)
+    result = gdb_sys_recvmsg;
+
+  return (enum gdb_syscall) result;
+}
+
+/* Record registers which might be clobbered during system call.
+   Return 0 if successful.  */
+
+static int
+ppc_linux_syscall_record (struct regcache *regcache)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  ULONGEST scnum;
+  enum gdb_syscall syscall_gdb;
+  int ret;
+  int i;
+
+  regcache_raw_read_unsigned (regcache, tdep->ppc_gp0_regnum, &scnum);
+  syscall_gdb = ppc_canonicalize_syscall (scnum);
+
+  if (syscall_gdb < 0)
+    {
+      printf_unfiltered (_("Process record and replay target doesn't "
+                          "support syscall number %d\n"), (int) scnum);
+      return 0;
+    }
+
+  if (syscall_gdb == gdb_sys_sigreturn
+      || syscall_gdb == gdb_sys_rt_sigreturn)
+   {
+     int i, j;
+     int regsets[] = { tdep->ppc_gp0_regnum,
+                      tdep->ppc_fp0_regnum,
+                      tdep->ppc_vr0_regnum,
+                      tdep->ppc_vsr0_upper_regnum };
+
+     for (j = 0; j < 4; j++)
+       {
+        if (regsets[j] == -1)
+          continue;
+        for (i = 0; i < 32; i++)
+          {
+            if (record_full_arch_list_add_reg (regcache, regsets[j] + i))
+              return -1;
+          }
+       }
+
+     if (record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum))
+       return -1;
+     if (record_full_arch_list_add_reg (regcache, tdep->ppc_ctr_regnum))
+       return -1;
+     if (record_full_arch_list_add_reg (regcache, tdep->ppc_lr_regnum))
+       return -1;
+     if (record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum))
+       return -1;
+
+     return 0;
+   }
+
+  if (tdep->wordsize == 8)
+    ret = record_linux_system_call (syscall_gdb, regcache,
+                                   &ppc64_linux_record_tdep);
+  else
+    ret = record_linux_system_call (syscall_gdb, regcache,
+                                   &ppc_linux_record_tdep);
+
+  if (ret != 0)
+    return ret;
+
+  /* Record registers clobbered during syscall.  */
+  for (i = 3; i <= 12; i++)
+    {
+      if (record_full_arch_list_add_reg (regcache, tdep->ppc_gp0_regnum + i))
+       return -1;
+    }
+  if (record_full_arch_list_add_reg (regcache, tdep->ppc_gp0_regnum + 0))
+    return -1;
+  if (record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum))
+    return -1;
+  if (record_full_arch_list_add_reg (regcache, tdep->ppc_ctr_regnum))
+    return -1;
+  if (record_full_arch_list_add_reg (regcache, tdep->ppc_lr_regnum))
+    return -1;
+
+  return 0;
+}
+
+/* Record registers which might be clobbered during signal handling.
+   Return 0 if successful.  */
+
+static int
+ppc_linux_record_signal (struct gdbarch *gdbarch, struct regcache *regcache,
+                        enum gdb_signal signal)
+{
+  /* See handle_rt_signal64 in arch/powerpc/kernel/signal_64.c
+        handle_rt_signal32 in arch/powerpc/kernel/signal_32.c
+        arch/powerpc/include/asm/ptrace.h
+     for details.  */
+  const int SIGNAL_FRAMESIZE = 128;
+  const int sizeof_rt_sigframe = 1440 * 2 + 8 * 2 + 4 * 6 + 8 + 8 + 128 + 512;
+  ULONGEST sp;
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int i;
+
+  for (i = 3; i <= 12; i++)
+    {
+      if (record_full_arch_list_add_reg (regcache, tdep->ppc_gp0_regnum + i))
+       return -1;
+    }
+
+  if (record_full_arch_list_add_reg (regcache, tdep->ppc_lr_regnum))
+    return -1;
+  if (record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum))
+    return -1;
+  if (record_full_arch_list_add_reg (regcache, tdep->ppc_ctr_regnum))
+    return -1;
+  if (record_full_arch_list_add_reg (regcache, gdbarch_pc_regnum (gdbarch)))
+    return -1;
+  if (record_full_arch_list_add_reg (regcache, gdbarch_sp_regnum (gdbarch)))
+    return -1;
+
+  /* Record the change in the stack.
+     frame-size = sizeof (struct rt_sigframe) + SIGNAL_FRAMESIZE  */
+  regcache_raw_read_unsigned (regcache, gdbarch_sp_regnum (gdbarch), &sp);
+  sp -= SIGNAL_FRAMESIZE;
+  sp -= sizeof_rt_sigframe;
+
+  if (record_full_arch_list_add_mem (sp, SIGNAL_FRAMESIZE + sizeof_rt_sigframe))
+    return -1;
+
+  if (record_full_arch_list_add_end ())
+    return -1;
+
+  return 0;
 }
 
 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);
 
@@ -786,7 +958,7 @@ ppc_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
 static int
 ppc_linux_spu_section (bfd *abfd, asection *asect, void *user_data)
 {
-  return strncmp (bfd_section_name (abfd, asect), "SPU/", 4) == 0;
+  return startswith (bfd_section_name (abfd, asect), "SPU/");
 }
 
 static const struct target_desc *
@@ -918,7 +1090,7 @@ ppc_stap_parse_special_token (struct gdbarch *gdbarch,
        }
 
       len = s - p->arg;
-      regname = alloca (len + 2);
+      regname = (char *) alloca (len + 2);
       regname[0] = 'r';
 
       strncpy (regname + 1, p->arg, len);
@@ -979,7 +1151,7 @@ ppc_linux_spe_context_lookup (struct objfile *objfile)
     {
       spe_context_objfile = objfile;
       spe_context_lm_addr = svr4_fetch_objfile_link_map (objfile);
-      spe_context_offset = BMSYMBOL_VALUE_ADDRESS (sym);
+      spe_context_offset = MSYMBOL_VALUE_RAW_ADDRESS (sym.minsym);
       spe_context_cache_ptid = minus_one_ptid;
       spe_context_cache_address = 0;
       return;
@@ -1031,10 +1203,9 @@ 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;
-      volatile struct gdb_exception ex;
+      struct target_ops *target = target_stack;
 
-      TRY_CATCH (ex, RETURN_MASK_ERROR)
+      TRY
        {
          /* We do not call target_translate_tls_address here, because
             svr4_fetch_objfile_link_map may invalidate the frame chain,
@@ -1043,14 +1214,17 @@ 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;
        }
 
-      if (ex.reason < 0)
-       return 0;
+      CATCH (ex, RETURN_MASK_ERROR)
+       {
+         return 0;
+       }
+      END_CATCH
     }
 
   /* Read variable value.  */
@@ -1088,21 +1262,21 @@ 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 = *this_cache;
-  return get_regcache_arch (cache->regcache);
+  struct ppu2spu_cache *cache = (struct ppu2spu_cache *) *this_cache;
+  return cache->regcache->arch ();
 }
 
 static void
 ppu2spu_this_id (struct frame_info *this_frame,
                 void **this_cache, struct frame_id *this_id)
 {
-  struct ppu2spu_cache *cache = *this_cache;
+  struct ppu2spu_cache *cache = (struct ppu2spu_cache *) *this_cache;
   *this_id = cache->frame_id;
 }
 
@@ -1110,17 +1284,13 @@ static struct value *
 ppu2spu_prev_register (struct frame_info *this_frame,
                       void **this_cache, int regnum)
 {
-  struct ppu2spu_cache *cache = *this_cache;
-  struct gdbarch *gdbarch = get_regcache_arch (cache->regcache);
+  struct ppu2spu_cache *cache = (struct ppu2spu_cache *) *this_cache;
+  struct gdbarch *gdbarch = cache->regcache->arch ();
   gdb_byte *buf;
 
-  buf = 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);
+  buf = (gdb_byte *) alloca (register_size (gdbarch, regnum));
 
+  cache->regcache->cooked_read (regnum, buf);
   return frame_unwind_got_bytes (this_frame, regnum, buf);
 }
 
@@ -1132,10 +1302,10 @@ struct ppu2spu_data
   gdb_byte gprs[128*16];
 };
 
-static int
+static enum register_status
 ppu2spu_unwind_register (void *src, int regnum, gdb_byte *buf)
 {
-  struct ppu2spu_data *data = src;
+  struct ppu2spu_data *data = (struct ppu2spu_data *) src;
   enum bfd_endian byte_order = gdbarch_byte_order (data->gdbarch);
 
   if (regnum >= 0 && regnum < SPU_NUM_GPRS)
@@ -1187,27 +1357,25 @@ ppu2spu_sniffer (const struct frame_unwind *self,
       info.bfd_arch_info = bfd_lookup_arch (bfd_arch_spu, bfd_mach_spu);
       info.byte_order = BFD_ENDIAN_BIG;
       info.osabi = GDB_OSABI_LINUX;
-      info.tdep_info = (void *) &data.id;
+      info.id = &data.id;
       data.gdbarch = gdbarch_find_by_info (info);
       if (!data.gdbarch)
        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);
-         struct regcache *regcache = regcache_xmalloc (data.gdbarch, aspace);
-         struct cleanup *cleanups = make_cleanup_regcache_xfree (regcache);
-         regcache_save (regcache, ppu2spu_unwind_register, &data);
-         discard_cleanups (cleanups);
+         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;
+         cache->regcache = regcache.release ();
          *this_prologue_cache = cache;
          return 1;
        }
@@ -1219,8 +1387,8 @@ ppu2spu_sniffer (const struct frame_unwind *self,
 static void
 ppu2spu_dealloc_cache (struct frame_info *self, void *this_cache)
 {
-  struct ppu2spu_cache *cache = this_cache;
-  regcache_xfree (cache->regcache);
+  struct ppu2spu_cache *cache = (struct ppu2spu_cache *) this_cache;
+  delete cache->regcache;
 }
 
 static const struct frame_unwind ppu2spu_unwind = {
@@ -1234,13 +1402,265 @@ static const struct frame_unwind ppu2spu_unwind = {
   ppu2spu_prev_arch,
 };
 
+/* Initialize linux_record_tdep if not initialized yet.
+   WORDSIZE is 4 or 8 for 32- or 64-bit PowerPC Linux respectively.
+   Sizes of data structures are initialized accordingly.  */
+
+static void
+ppc_init_linux_record_tdep (struct linux_record_tdep *record_tdep,
+                           int wordsize)
+{
+  /* Simply return if it had been initialized.  */
+  if (record_tdep->size_pointer != 0)
+    return;
+
+  /* These values are the size of the type that will be used in a system
+     call.  They are obtained from Linux Kernel source.  */
+
+  if (wordsize == 8)
+    {
+      record_tdep->size_pointer = 8;
+      record_tdep->size__old_kernel_stat = 32;
+      record_tdep->size_tms = 32;
+      record_tdep->size_loff_t = 8;
+      record_tdep->size_flock = 32;
+      record_tdep->size_oldold_utsname = 45;
+      record_tdep->size_ustat = 32;
+      record_tdep->size_old_sigaction = 32;
+      record_tdep->size_old_sigset_t = 8;
+      record_tdep->size_rlimit = 16;
+      record_tdep->size_rusage = 144;
+      record_tdep->size_timeval = 16;
+      record_tdep->size_timezone = 8;
+      record_tdep->size_old_gid_t = 4;
+      record_tdep->size_old_uid_t = 4;
+      record_tdep->size_fd_set = 128;
+      record_tdep->size_old_dirent = 280;
+      record_tdep->size_statfs = 120;
+      record_tdep->size_statfs64 = 120;
+      record_tdep->size_sockaddr = 16;
+      record_tdep->size_int = 4;
+      record_tdep->size_long = 8;
+      record_tdep->size_ulong = 8;
+      record_tdep->size_msghdr = 56;
+      record_tdep->size_itimerval = 32;
+      record_tdep->size_stat = 144;
+      record_tdep->size_old_utsname = 325;
+      record_tdep->size_sysinfo = 112;
+      record_tdep->size_msqid_ds = 120;
+      record_tdep->size_shmid_ds = 112;
+      record_tdep->size_new_utsname = 390;
+      record_tdep->size_timex = 208;
+      record_tdep->size_mem_dqinfo = 24;
+      record_tdep->size_if_dqblk = 72;
+      record_tdep->size_fs_quota_stat = 80;
+      record_tdep->size_timespec = 16;
+      record_tdep->size_pollfd = 8;
+      record_tdep->size_NFS_FHSIZE = 32;
+      record_tdep->size_knfsd_fh = 132;
+      record_tdep->size_TASK_COMM_LEN = 16;
+      record_tdep->size_sigaction = 32;
+      record_tdep->size_sigset_t = 8;
+      record_tdep->size_siginfo_t = 128;
+      record_tdep->size_cap_user_data_t = 8;
+      record_tdep->size_stack_t = 24;
+      record_tdep->size_off_t = 8;
+      record_tdep->size_stat64 = 104;
+      record_tdep->size_gid_t = 4;
+      record_tdep->size_uid_t = 4;
+      record_tdep->size_PAGE_SIZE = 0x10000;   /* 64KB */
+      record_tdep->size_flock64 = 32;
+      record_tdep->size_io_event = 32;
+      record_tdep->size_iocb = 64;
+      record_tdep->size_epoll_event = 16;
+      record_tdep->size_itimerspec = 32;
+      record_tdep->size_mq_attr = 64;
+      record_tdep->size_termios = 44;
+      record_tdep->size_pid_t = 4;
+      record_tdep->size_winsize = 8;
+      record_tdep->size_serial_struct = 72;
+      record_tdep->size_serial_icounter_struct = 80;
+      record_tdep->size_size_t = 8;
+      record_tdep->size_iovec = 16;
+      record_tdep->size_time_t = 8;
+    }
+  else if (wordsize == 4)
+    {
+      record_tdep->size_pointer = 4;
+      record_tdep->size__old_kernel_stat = 32;
+      record_tdep->size_tms = 16;
+      record_tdep->size_loff_t = 8;
+      record_tdep->size_flock = 16;
+      record_tdep->size_oldold_utsname = 45;
+      record_tdep->size_ustat = 20;
+      record_tdep->size_old_sigaction = 16;
+      record_tdep->size_old_sigset_t = 4;
+      record_tdep->size_rlimit = 8;
+      record_tdep->size_rusage = 72;
+      record_tdep->size_timeval = 8;
+      record_tdep->size_timezone = 8;
+      record_tdep->size_old_gid_t = 4;
+      record_tdep->size_old_uid_t = 4;
+      record_tdep->size_fd_set = 128;
+      record_tdep->size_old_dirent = 268;
+      record_tdep->size_statfs = 64;
+      record_tdep->size_statfs64 = 88;
+      record_tdep->size_sockaddr = 16;
+      record_tdep->size_int = 4;
+      record_tdep->size_long = 4;
+      record_tdep->size_ulong = 4;
+      record_tdep->size_msghdr = 28;
+      record_tdep->size_itimerval = 16;
+      record_tdep->size_stat = 88;
+      record_tdep->size_old_utsname = 325;
+      record_tdep->size_sysinfo = 64;
+      record_tdep->size_msqid_ds = 68;
+      record_tdep->size_shmid_ds = 60;
+      record_tdep->size_new_utsname = 390;
+      record_tdep->size_timex = 128;
+      record_tdep->size_mem_dqinfo = 24;
+      record_tdep->size_if_dqblk = 72;
+      record_tdep->size_fs_quota_stat = 80;
+      record_tdep->size_timespec = 8;
+      record_tdep->size_pollfd = 8;
+      record_tdep->size_NFS_FHSIZE = 32;
+      record_tdep->size_knfsd_fh = 132;
+      record_tdep->size_TASK_COMM_LEN = 16;
+      record_tdep->size_sigaction = 20;
+      record_tdep->size_sigset_t = 8;
+      record_tdep->size_siginfo_t = 128;
+      record_tdep->size_cap_user_data_t = 4;
+      record_tdep->size_stack_t = 12;
+      record_tdep->size_off_t = 4;
+      record_tdep->size_stat64 = 104;
+      record_tdep->size_gid_t = 4;
+      record_tdep->size_uid_t = 4;
+      record_tdep->size_PAGE_SIZE = 0x10000;   /* 64KB */
+      record_tdep->size_flock64 = 32;
+      record_tdep->size_io_event = 32;
+      record_tdep->size_iocb = 64;
+      record_tdep->size_epoll_event = 16;
+      record_tdep->size_itimerspec = 16;
+      record_tdep->size_mq_attr = 32;
+      record_tdep->size_termios = 44;
+      record_tdep->size_pid_t = 4;
+      record_tdep->size_winsize = 8;
+      record_tdep->size_serial_struct = 60;
+      record_tdep->size_serial_icounter_struct = 80;
+      record_tdep->size_size_t = 4;
+      record_tdep->size_iovec = 8;
+      record_tdep->size_time_t = 4;
+    }
+  else
+    internal_error (__FILE__, __LINE__, _("unexpected wordsize"));
+
+  /* These values are the second argument of system call "sys_fcntl"
+     and "sys_fcntl64".  They are obtained from Linux Kernel source.  */
+  record_tdep->fcntl_F_GETLK = 5;
+  record_tdep->fcntl_F_GETLK64 = 12;
+  record_tdep->fcntl_F_SETLK64 = 13;
+  record_tdep->fcntl_F_SETLKW64 = 14;
+
+  record_tdep->arg1 = PPC_R0_REGNUM + 3;
+  record_tdep->arg2 = PPC_R0_REGNUM + 4;
+  record_tdep->arg3 = PPC_R0_REGNUM + 5;
+  record_tdep->arg4 = PPC_R0_REGNUM + 6;
+  record_tdep->arg5 = PPC_R0_REGNUM + 7;
+  record_tdep->arg6 = PPC_R0_REGNUM + 8;
+
+  /* These values are the second argument of system call "sys_ioctl".
+     They are obtained from Linux Kernel source.
+     See arch/powerpc/include/uapi/asm/ioctls.h.  */
+  record_tdep->ioctl_TCGETS = 0x403c7413;
+  record_tdep->ioctl_TCSETS = 0x803c7414;
+  record_tdep->ioctl_TCSETSW = 0x803c7415;
+  record_tdep->ioctl_TCSETSF = 0x803c7416;
+  record_tdep->ioctl_TCGETA = 0x40147417;
+  record_tdep->ioctl_TCSETA = 0x80147418;
+  record_tdep->ioctl_TCSETAW = 0x80147419;
+  record_tdep->ioctl_TCSETAF = 0x8014741c;
+  record_tdep->ioctl_TCSBRK = 0x2000741d;
+  record_tdep->ioctl_TCXONC = 0x2000741e;
+  record_tdep->ioctl_TCFLSH = 0x2000741f;
+  record_tdep->ioctl_TIOCEXCL = 0x540c;
+  record_tdep->ioctl_TIOCNXCL = 0x540d;
+  record_tdep->ioctl_TIOCSCTTY = 0x540e;
+  record_tdep->ioctl_TIOCGPGRP = 0x40047477;
+  record_tdep->ioctl_TIOCSPGRP = 0x80047476;
+  record_tdep->ioctl_TIOCOUTQ = 0x40047473;
+  record_tdep->ioctl_TIOCSTI = 0x5412;
+  record_tdep->ioctl_TIOCGWINSZ = 0x40087468;
+  record_tdep->ioctl_TIOCSWINSZ = 0x80087467;
+  record_tdep->ioctl_TIOCMGET = 0x5415;
+  record_tdep->ioctl_TIOCMBIS = 0x5416;
+  record_tdep->ioctl_TIOCMBIC = 0x5417;
+  record_tdep->ioctl_TIOCMSET = 0x5418;
+  record_tdep->ioctl_TIOCGSOFTCAR = 0x5419;
+  record_tdep->ioctl_TIOCSSOFTCAR = 0x541a;
+  record_tdep->ioctl_FIONREAD = 0x4004667f;
+  record_tdep->ioctl_TIOCINQ = 0x4004667f;
+  record_tdep->ioctl_TIOCLINUX = 0x541c;
+  record_tdep->ioctl_TIOCCONS = 0x541d;
+  record_tdep->ioctl_TIOCGSERIAL = 0x541e;
+  record_tdep->ioctl_TIOCSSERIAL = 0x541f;
+  record_tdep->ioctl_TIOCPKT = 0x5420;
+  record_tdep->ioctl_FIONBIO = 0x8004667e;
+  record_tdep->ioctl_TIOCNOTTY = 0x5422;
+  record_tdep->ioctl_TIOCSETD = 0x5423;
+  record_tdep->ioctl_TIOCGETD = 0x5424;
+  record_tdep->ioctl_TCSBRKP = 0x5425;
+  record_tdep->ioctl_TIOCSBRK = 0x5427;
+  record_tdep->ioctl_TIOCCBRK = 0x5428;
+  record_tdep->ioctl_TIOCGSID = 0x5429;
+  record_tdep->ioctl_TIOCGPTN = 0x40045430;
+  record_tdep->ioctl_TIOCSPTLCK = 0x80045431;
+  record_tdep->ioctl_FIONCLEX = 0x20006602;
+  record_tdep->ioctl_FIOCLEX = 0x20006601;
+  record_tdep->ioctl_FIOASYNC = 0x8004667d;
+  record_tdep->ioctl_TIOCSERCONFIG = 0x5453;
+  record_tdep->ioctl_TIOCSERGWILD = 0x5454;
+  record_tdep->ioctl_TIOCSERSWILD = 0x5455;
+  record_tdep->ioctl_TIOCGLCKTRMIOS = 0x5456;
+  record_tdep->ioctl_TIOCSLCKTRMIOS = 0x5457;
+  record_tdep->ioctl_TIOCSERGSTRUCT = 0x5458;
+  record_tdep->ioctl_TIOCSERGETLSR = 0x5459;
+  record_tdep->ioctl_TIOCSERGETMULTI = 0x545a;
+  record_tdep->ioctl_TIOCSERSETMULTI = 0x545b;
+  record_tdep->ioctl_TIOCMIWAIT = 0x545c;
+  record_tdep->ioctl_TIOCGICOUNT = 0x545d;
+  record_tdep->ioctl_FIOQSIZE = 0x40086680;
+}
+
+/* Return a floating-point format for a floating-point variable of
+   length LEN in bits.  If non-NULL, NAME is the name of its type.
+   If no suitable type is found, return NULL.  */
+
+const struct floatformat **
+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, "__ibm128") == 0)
+       return floatformats_ibm_long_double;
+    }
+
+  return default_floatformat_for_type (gdbarch, name, len);
+}
 
 static void
 ppc_linux_init_abi (struct gdbarch_info info,
                     struct gdbarch *gdbarch)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-  struct tdesc_arch_data *tdesc_data = (void *) info.tdep_info;
+  struct tdesc_arch_data *tdesc_data = info.tdesc_data;
   static const char *const stap_integer_prefixes[] = { "i", NULL };
   static const char *const stap_register_indirection_prefixes[] = { "(",
                                                                    NULL };
@@ -1250,12 +1670,18 @@ 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);
 
   /* Handle inferior calls during interrupted system calls.  */
   set_gdbarch_write_pc (gdbarch, ppc_linux_write_pc);
@@ -1361,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);
@@ -1407,17 +1827,22 @@ ppc_linux_init_abi (struct gdbarch_info info,
       /* Cell/B.E. cross-architecture unwinder support.  */
       frame_unwind_prepend_unwinder (gdbarch, &ppu2spu_unwind);
 
-      /* The default displaced_step_at_entry_point doesn't work for
-        SPU stand-alone executables.  */
-      set_gdbarch_displaced_step_location (gdbarch,
-                                          ppc_linux_displaced_step_location);
+      /* 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_get_siginfo_type (gdbarch, linux_get_siginfo_type);
-}
+  set_gdbarch_displaced_step_location (gdbarch,
+                                      linux_displaced_step_location);
 
-/* Provide a prototype to silence -Wmissing-prototypes.  */
-extern initialize_file_ftype _initialize_ppc_linux_tdep;
+  /* Support reverse debugging.  */
+  set_gdbarch_process_record (gdbarch, ppc_process_record);
+  set_gdbarch_process_record_signal (gdbarch, ppc_linux_record_signal);
+  tdep->ppc_syscall_record = ppc_linux_syscall_record;
+
+  ppc_init_linux_record_tdep (&ppc_linux_record_tdep, 4);
+  ppc_init_linux_record_tdep (&ppc64_linux_record_tdep, 8);
+}
 
 void
 _initialize_ppc_linux_tdep (void)
@@ -1431,13 +1856,10 @@ _initialize_ppc_linux_tdep (void)
   gdbarch_register_osabi (bfd_arch_rs6000, bfd_mach_rs6k, GDB_OSABI_LINUX,
                          ppc_linux_init_abi);
 
-  /* Attach to inferior_created observer.  */
-  observer_attach_inferior_created (ppc_linux_inferior_created);
-
   /* 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 ();