public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] Process record support for PowerPC
@ 2014-11-18 16:27 Wei-cheng, Wang
  2014-11-28 12:15 ` Ulrich Weigand
  0 siblings, 1 reply; 4+ messages in thread
From: Wei-cheng, Wang @ 2014-11-18 16:27 UTC (permalink / raw)
  To: uweigand, gdb-patches; +Cc: dje.gcc, green

Hi,

This patch is process record support for PowerPC
* Tested with Advance Toolchain 8.0 ppc64 - 2326 pass, no fail
* 26 fails if tested with ppc64le, due to local entry optimization.
   Breakpoints set on the very beginning of functions may
   not be hit when reverse-continue.
* Support reverse-step over subroutine without debug info
* Record/reverse syscall/signal
* Support reverse-step through solib trampoline

And these instructions are handled
* All main opcode
* opcode 31
-- Privileged instructions are listed, but not handled.
    Shoule I just remote them?
* opcode 59 and 63 (Decimal Floating-Point and Floating-point)
* opcode 4 (Only [vector] instructions are handled.)
* opcode 19 (Only conditional and branch instruction.)

SPE, Embedded, LMA, VSX and privileged instructions are not handled.

Wei-cheng

---
  gdb/configure.tgt                       |    3 +-
  gdb/ppc-linux-tdep.c                    |  353 +++++++
  gdb/ppc-tdep.h                          |    5 +
  gdb/rs6000-tdep.c                       | 1516 ++++++++++++++++++++++++++++++-
  gdb/testsuite/lib/gdb.exp               |    6 +-
  6 files changed, 1881 insertions(+), 7 deletions(-)

diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 1d7f54b..ae77efe 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -434,7 +434,8 @@ powerpc*-*-linux*)
  			ppc64-tdep.o solib-svr4.o solib-spu.o \
  			spu-multiarch.o \
  			glibc-tdep.o symfile-mem.o linux-tdep.o \
-			ravenscar-thread.o ppc-ravenscar-thread.o"
+			ravenscar-thread.o ppc-ravenscar-thread.o \
+			linux-record.o "
  	gdb_sim=../sim/ppc/libsim.a
  	build_gdbserver=yes
  	;;
diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c
index a997869..608081c 100644
--- a/gdb/ppc-linux-tdep.c
+++ b/gdb/ppc-linux-tdep.c
@@ -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"
@@ -298,6 +301,23 @@ powerpc_linux_in_dynsym_resolve_code (CORE_ADDR pc)
  	  || strcmp (MSYMBOL_LINKAGE_NAME (sym.minsym),
  		     "__glink_PLTresolve") == 0))
      return 1;
+  else if (sym.minsym != NULL && execution_direction == EXEC_REVERSE)
+    {
+      /* When reverse stepping, gdb needs to know whether PC lies in
+	 the dynamic symbol resolve code, so it can keep going until
+	 reaching some user code.
+	 Using insns-match-pattern is not suitable, because we had to
+	 look both ahead and behind to check where we are in the middle
+	 of one of trampline sequences.  */
+#define SUBSTRCMP(sym, stub)  (memcmp (sym + 8, stub, sizeof (stub) - 1) == 0)
+      if (SUBSTRCMP (MSYMBOL_LINKAGE_NAME (sym.minsym), ".plt_call."))
+	return 1;
+      if (SUBSTRCMP (MSYMBOL_LINKAGE_NAME (sym.minsym), ".plt_branch."))
+	return 1;
+      if (SUBSTRCMP (MSYMBOL_LINKAGE_NAME (sym.minsym), ".plt_branch_r2off."))
+	return 1;
+#undef SUBSTRCMP
+    }

    return 0;
  }
@@ -764,6 +784,165 @@ ppc_linux_get_syscall_number (struct gdbarch *gdbarch,
    return ret;
  }

+/* PPC process record-replay */
+
+struct linux_record_tdep ppc_linux_record_tdep;
+
+static enum gdb_syscall
+ppc_canonicalize_syscall (int syscall)
+{
+  /* See arch/powerpc/include/uapi/asm/unistd.h */
+
+  if (syscall <= 165)
+    return syscall;
+  else if (syscall >= 167 && syscall <= 190)	/* Skip query_module 166 */
+    return syscall + 1;
+  else if (syscall >= 192 && syscall <= 197)	/* mmap2 */
+    return syscall;
+  else if (syscall == 208)			/* tkill */
+    return gdb_sys_tkill;
+  else if (syscall >= 207 && syscall <= 220)	/* gettid */
+    return syscall + 224 - 207;
+  else if (syscall >= 234 && syscall <= 239)	/* exit_group */
+    return syscall + 252 - 234;
+  else if (syscall >= 240 && syscall <=248)	/* timer_create */
+    return syscall += 259 - 240;
+  else if (syscall >= 250 && syscall <=251)	/* tgkill */
+    return syscall + 270 - 250;
+  else if (syscall == 336)
+    return gdb_sys_recv;
+  else if (syscall == 337)
+    return gdb_sys_recvfrom;
+  else if (syscall == 342)
+    return gdb_sys_recvmsg;
+  return -1;
+}
+
+/* Record all registers but PC register for process-record.  */
+
+static int
+ppc_all_but_pc_registers_record (struct regcache *regcache)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int i;
+
+  for (i = 0; i < 32; 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_cr_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_ctr_regnum))
+    return -1;
+
+  return 0;
+}
+
+static int
+ppc_linux_syscall_record (struct regcache *regcache)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  ULONGEST scnum;
+  enum gdb_syscall syscall_gdb;
+  int ret;
+
+  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)
+   {
+     if (ppc_all_but_pc_registers_record (regcache))
+       return -1;
+     return 0;
+   }
+
+  ret = record_linux_system_call (syscall_gdb, regcache,
+                                  &ppc_linux_record_tdep);
+  if (ret != 0)
+    return ret;
+
+  /* Record registers clobbered during syscall.  */
+  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_gp0_regnum + 3))
+    return -1;
+  if (record_full_arch_list_add_reg (regcache, tdep->ppc_gp0_regnum + 4))
+    return -1;
+  if (record_full_arch_list_add_reg (regcache, tdep->ppc_gp0_regnum + 5))
+    return -1;
+  if (record_full_arch_list_add_reg (regcache, tdep->ppc_gp0_regnum + 6))
+    return -1;
+  if (record_full_arch_list_add_reg (regcache, tdep->ppc_gp0_regnum + 7))
+    return -1;
+  if (record_full_arch_list_add_reg (regcache, tdep->ppc_gp0_regnum + 8))
+    return -1;
+  if (record_full_arch_list_add_reg (regcache, tdep->ppc_gp0_regnum + 9))
+    return -1;
+  if (record_full_arch_list_add_reg (regcache, tdep->ppc_gp0_regnum + 10))
+    return -1;
+  if (record_full_arch_list_add_reg (regcache, tdep->ppc_gp0_regnum + 11))
+    return -1;
+  if (record_full_arch_list_add_reg (regcache, tdep->ppc_gp0_regnum + 12))
+    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;
+}
+
+static int
+ppc64_linux_record_signal (struct gdbarch *gdbarch,
+                           struct regcache *regcache,
+                           enum gdb_signal signal)
+{
+  /* See arch/powerpc/kernel/signal_64.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);
+
+  if (ppc_all_but_pc_registers_record (regcache))
+    return -1;
+
+  if (record_full_arch_list_add_reg (regcache, gdbarch_pc_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)
  {
@@ -1345,6 +1524,15 @@ ppc_linux_init_abi (struct gdbarch_info info,
        set_solib_svr4_fetch_link_map_offsets
          (gdbarch, svr4_lp64_fetch_link_map_offsets);

+      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);
+
        /* Setting the correct XML syscall filename.  */
        set_xml_syscall_file_name (XML_SYSCALL_FILENAME_PPC64);

@@ -1414,6 +1602,171 @@ ppc_linux_init_abi (struct gdbarch_info info,
      }

    set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
+
+  /* Support reverse debugging.  */
+  set_gdbarch_process_record (gdbarch, ppc64_process_record);
+  set_gdbarch_process_record_signal (gdbarch, ppc64_linux_record_signal);
+  tdep->syscall_record = ppc_linux_syscall_record;
+
+  /* Initialize the ppc_linux_record_tdep.  */
+  /* These values are the size of the type that will be used in a system
+     call.  They are obtained from Linux Kernel source.
+
+     See arch/powerpc/include/uapi/asm/ioctls.h.  */
+  ppc_linux_record_tdep.size_pointer
+    = gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT;
+  ppc_linux_record_tdep.size__old_kernel_stat = 32;
+  ppc_linux_record_tdep.size_tms = 32;
+  ppc_linux_record_tdep.size_loff_t = 8;
+  ppc_linux_record_tdep.size_flock = 32;
+  ppc_linux_record_tdep.size_oldold_utsname = 45;
+  ppc_linux_record_tdep.size_ustat = 32;
+  ppc_linux_record_tdep.size_old_sigaction = 152;
+  ppc_linux_record_tdep.size_old_sigset_t = 128;
+  ppc_linux_record_tdep.size_rlimit = 16;
+  ppc_linux_record_tdep.size_rusage = 144;
+  ppc_linux_record_tdep.size_timeval = 16;
+  ppc_linux_record_tdep.size_timezone = 8;
+  ppc_linux_record_tdep.size_old_gid_t = 2;
+  ppc_linux_record_tdep.size_old_uid_t = 2;
+  ppc_linux_record_tdep.size_fd_set = 128;
+  ppc_linux_record_tdep.size_dirent = 280;
+  ppc_linux_record_tdep.size_dirent64 = 280;
+  ppc_linux_record_tdep.size_statfs = 120;
+  ppc_linux_record_tdep.size_statfs64 = 120;
+  ppc_linux_record_tdep.size_sockaddr = 16;
+  ppc_linux_record_tdep.size_int
+    = gdbarch_int_bit (gdbarch) / TARGET_CHAR_BIT;
+  ppc_linux_record_tdep.size_long
+    = gdbarch_long_bit (gdbarch) / TARGET_CHAR_BIT;
+  ppc_linux_record_tdep.size_ulong
+    = gdbarch_long_bit (gdbarch) / TARGET_CHAR_BIT;
+  ppc_linux_record_tdep.size_msghdr = 56;
+  ppc_linux_record_tdep.size_itimerval = 32;
+  ppc_linux_record_tdep.size_stat = 144;
+  ppc_linux_record_tdep.size_old_utsname = 325;
+  ppc_linux_record_tdep.size_sysinfo = 112;
+  ppc_linux_record_tdep.size_msqid_ds = 120;
+  ppc_linux_record_tdep.size_shmid_ds = 112;
+  ppc_linux_record_tdep.size_new_utsname = 390;
+  ppc_linux_record_tdep.size_timex = 208;
+  ppc_linux_record_tdep.size_mem_dqinfo = 24;
+  ppc_linux_record_tdep.size_if_dqblk = 72;
+  ppc_linux_record_tdep.size_fs_quota_stat = 80;
+  ppc_linux_record_tdep.size_timespec = 16;
+  ppc_linux_record_tdep.size_pollfd = 8;
+  ppc_linux_record_tdep.size_NFS_FHSIZE = 32;
+  ppc_linux_record_tdep.size_knfsd_fh = 132;
+  ppc_linux_record_tdep.size_TASK_COMM_LEN = 32;
+  ppc_linux_record_tdep.size_sigaction = 152;
+  ppc_linux_record_tdep.size_sigset_t = 128;
+  ppc_linux_record_tdep.size_siginfo_t = 128;
+  ppc_linux_record_tdep.size_cap_user_data_t = 8;
+  ppc_linux_record_tdep.size_stack_t = 24;
+  ppc_linux_record_tdep.size_off_t = 8;
+  ppc_linux_record_tdep.size_stat64 = 144;
+  ppc_linux_record_tdep.size_gid_t = 4;
+  ppc_linux_record_tdep.size_uid_t = 4;
+  ppc_linux_record_tdep.size_PAGE_SIZE = 4096;
+  ppc_linux_record_tdep.size_flock64 = 32;
+  ppc_linux_record_tdep.size_user_desc = 16;
+  ppc_linux_record_tdep.size_io_event = 32;
+  ppc_linux_record_tdep.size_iocb = 64;
+  ppc_linux_record_tdep.size_epoll_event = 12;
+  ppc_linux_record_tdep.size_itimerspec = 32;
+  ppc_linux_record_tdep.size_mq_attr = 64;
+  ppc_linux_record_tdep.size_siginfo = 128;
+  ppc_linux_record_tdep.size_termios = 60;
+  ppc_linux_record_tdep.size_termios2 = 44;
+  ppc_linux_record_tdep.size_pid_t = 4;
+  ppc_linux_record_tdep.size_winsize = 8;
+  ppc_linux_record_tdep.size_serial_struct = 72;
+  ppc_linux_record_tdep.size_serial_icounter_struct = 80;
+  ppc_linux_record_tdep.size_hayes_esp_config = 12;
+  ppc_linux_record_tdep.size_size_t = 8;
+  ppc_linux_record_tdep.size_iovec = 16;
+
+  /* These values are the second argument of system call "sys_fcntl"
+     and "sys_fcntl64".  They are obtained from Linux Kernel source.  */
+  ppc_linux_record_tdep.fcntl_F_GETLK = 5;
+  ppc_linux_record_tdep.fcntl_F_GETLK64 = 12;
+  ppc_linux_record_tdep.fcntl_F_SETLK64 = 13;
+  ppc_linux_record_tdep.fcntl_F_SETLKW64 = 14;
+
+  ppc_linux_record_tdep.arg1 = PPC_R0_REGNUM + 3;
+  ppc_linux_record_tdep.arg2 = PPC_R0_REGNUM + 4;
+  ppc_linux_record_tdep.arg3 = PPC_R0_REGNUM + 5;
+  ppc_linux_record_tdep.arg4 = PPC_R0_REGNUM + 6;
+  ppc_linux_record_tdep.arg5 = PPC_R0_REGNUM + 7;
+  ppc_linux_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.  */
+  ppc_linux_record_tdep.ioctl_TCGETS = 0x5401;
+  ppc_linux_record_tdep.ioctl_TCSETS = 0x5402;
+  ppc_linux_record_tdep.ioctl_TCSETSW = 0x5403;
+  ppc_linux_record_tdep.ioctl_TCSETSF = 0x5404;
+  ppc_linux_record_tdep.ioctl_TCGETA = 0x5405;
+  ppc_linux_record_tdep.ioctl_TCSETA = 0x5406;
+  ppc_linux_record_tdep.ioctl_TCSETAW = 0x5407;
+  ppc_linux_record_tdep.ioctl_TCSETAF = 0x5408;
+  ppc_linux_record_tdep.ioctl_TCSBRK = 0x5409;
+  ppc_linux_record_tdep.ioctl_TCXONC = 0x540A;
+  ppc_linux_record_tdep.ioctl_TCFLSH = 0x540B;
+  ppc_linux_record_tdep.ioctl_TIOCEXCL = 0x540C;
+  ppc_linux_record_tdep.ioctl_TIOCNXCL = 0x540D;
+  ppc_linux_record_tdep.ioctl_TIOCSCTTY = 0x540E;
+  ppc_linux_record_tdep.ioctl_TIOCGPGRP = 0x540F;
+  ppc_linux_record_tdep.ioctl_TIOCSPGRP = 0x5410;
+  ppc_linux_record_tdep.ioctl_TIOCOUTQ = 0x5411;
+  ppc_linux_record_tdep.ioctl_TIOCSTI = 0x5412;
+  ppc_linux_record_tdep.ioctl_TIOCGWINSZ = 0x5413;
+  ppc_linux_record_tdep.ioctl_TIOCSWINSZ = 0x5414;
+  ppc_linux_record_tdep.ioctl_TIOCMGET = 0x5415;
+  ppc_linux_record_tdep.ioctl_TIOCMBIS = 0x5416;
+  ppc_linux_record_tdep.ioctl_TIOCMBIC = 0x5417;
+  ppc_linux_record_tdep.ioctl_TIOCMSET = 0x5418;
+  ppc_linux_record_tdep.ioctl_TIOCGSOFTCAR = 0x5419;
+  ppc_linux_record_tdep.ioctl_TIOCSSOFTCAR = 0x541A;
+  ppc_linux_record_tdep.ioctl_FIONREAD = 0x541B;
+  ppc_linux_record_tdep.ioctl_TIOCINQ = ppc_linux_record_tdep.ioctl_FIONREAD;
+  ppc_linux_record_tdep.ioctl_TIOCLINUX = 0x541C;
+  ppc_linux_record_tdep.ioctl_TIOCCONS = 0x541D;
+  ppc_linux_record_tdep.ioctl_TIOCGSERIAL = 0x541E;
+  ppc_linux_record_tdep.ioctl_TIOCSSERIAL = 0x541F;
+  ppc_linux_record_tdep.ioctl_TIOCPKT = 0x5420;
+  ppc_linux_record_tdep.ioctl_FIONBIO = 0x5421;
+  ppc_linux_record_tdep.ioctl_TIOCNOTTY = 0x5422;
+  ppc_linux_record_tdep.ioctl_TIOCSETD = 0x5423;
+  ppc_linux_record_tdep.ioctl_TIOCGETD = 0x5424;
+  ppc_linux_record_tdep.ioctl_TCSBRKP = 0x5425;
+  ppc_linux_record_tdep.ioctl_TIOCTTYGSTRUCT = 0x5426;
+  ppc_linux_record_tdep.ioctl_TIOCSBRK = 0x5427;
+  ppc_linux_record_tdep.ioctl_TIOCCBRK = 0x5428;
+  ppc_linux_record_tdep.ioctl_TIOCGSID = 0x5429;
+  ppc_linux_record_tdep.ioctl_TCGETS2 = 0x802c542a;
+  ppc_linux_record_tdep.ioctl_TCSETS2 = 0x402c542b;
+  ppc_linux_record_tdep.ioctl_TCSETSW2 = 0x402c542c;
+  ppc_linux_record_tdep.ioctl_TCSETSF2 = 0x402c542d;
+  ppc_linux_record_tdep.ioctl_TIOCGPTN = 0x80045430;
+  ppc_linux_record_tdep.ioctl_TIOCSPTLCK = 0x40045431;
+  ppc_linux_record_tdep.ioctl_FIONCLEX = 0x5450;
+  ppc_linux_record_tdep.ioctl_FIOCLEX = 0x5451;
+  ppc_linux_record_tdep.ioctl_FIOASYNC = 0x5452;
+  ppc_linux_record_tdep.ioctl_TIOCSERCONFIG = 0x5453;
+  ppc_linux_record_tdep.ioctl_TIOCSERGWILD = 0x5454;
+  ppc_linux_record_tdep.ioctl_TIOCSERSWILD = 0x5455;
+  ppc_linux_record_tdep.ioctl_TIOCGLCKTRMIOS = 0x5456;
+  ppc_linux_record_tdep.ioctl_TIOCSLCKTRMIOS = 0x5457;
+  ppc_linux_record_tdep.ioctl_TIOCSERGSTRUCT = 0x5458;
+  ppc_linux_record_tdep.ioctl_TIOCSERGETLSR = 0x5459;
+  ppc_linux_record_tdep.ioctl_TIOCSERGETMULTI = 0x545A;
+  ppc_linux_record_tdep.ioctl_TIOCSERSETMULTI = 0x545B;
+  ppc_linux_record_tdep.ioctl_TIOCMIWAIT = 0x545C;
+  ppc_linux_record_tdep.ioctl_TIOCGICOUNT = 0x545D;
+  ppc_linux_record_tdep.ioctl_TIOCGHAYESESP = 0x545E;
+  ppc_linux_record_tdep.ioctl_TIOCSHAYESESP = 0x545F;
+  ppc_linux_record_tdep.ioctl_FIOQSIZE = 0x5460;
  }

  /* Provide a prototype to silence -Wmissing-prototypes.  */
diff --git a/gdb/ppc-tdep.h b/gdb/ppc-tdep.h
index 08554ff..437ca8c 100644
--- a/gdb/ppc-tdep.h
+++ b/gdb/ppc-tdep.h
@@ -259,6 +259,8 @@ struct gdbarch_tdep
      /* ISA-specific types.  */
      struct type *ppc_builtin_type_vec64;
      struct type *ppc_builtin_type_vec128;
+
+    int (* syscall_record) (struct regcache *regcache);
  };


@@ -318,6 +320,9 @@ extern CORE_ADDR ppc_insn_d_field (unsigned int insn);

  extern CORE_ADDR ppc_insn_ds_field (unsigned int insn);

+extern int ppc64_process_record (struct gdbarch *gdbarch,
+				 struct regcache *regcache, CORE_ADDR addr);
+
  /* Instruction size.  */
  #define PPC_INSN_SIZE 4

diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
index dabf448..4153454 100644
--- a/gdb/rs6000-tdep.c
+++ b/gdb/rs6000-tdep.c
@@ -40,6 +40,8 @@
  #include "dwarf2-frame.h"
  #include "target-descriptions.h"
  #include "user-regs.h"
+#include "record-full.h"
+#include "auxv.h"

  #include "libbfd.h"		/* for bfd_default_set_arch_mach */
  #include "coff/internal.h"	/* for libcoff.h */
@@ -872,14 +874,14 @@ insn_changes_sp_or_jumps (unsigned long insn)
             limit for the size of an epilogue.  */

  static int
-rs6000_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+rs6000_in_function_epilogue_frame_p (struct frame_info *curfrm,
+				     struct gdbarch *gdbarch, CORE_ADDR pc)
  {
    struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
    enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
    bfd_byte insn_buf[PPC_INSN_SIZE];
    CORE_ADDR scan_pc, func_start, func_end, epilogue_start, epilogue_end;
    unsigned long insn;
-  struct frame_info *curfrm;

    /* Find the search limits based on function boundaries and hard limit.  */

@@ -892,8 +894,6 @@ rs6000_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
    epilogue_end = pc + PPC_MAX_EPILOGUE_INSTRUCTIONS * PPC_INSN_SIZE;
    if (epilogue_end > func_end) epilogue_end = func_end;

-  curfrm = get_current_frame ();
-
    /* Scan forward until next 'blr'.  */

    for (scan_pc = pc; scan_pc < epilogue_end; scan_pc += PPC_INSN_SIZE)
@@ -934,6 +934,15 @@ rs6000_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
    return 0;
  }

+/* Implementation of gdbarch_in_function_epilogue_p.  */
+
+static int
+rs6000_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  return rs6000_in_function_epilogue_frame_p (get_current_frame (),
+					      gdbarch, pc);
+}
+
  /* Get the ith function argument for the current function.  */
  static CORE_ADDR
  rs6000_fetch_pointer_argument (struct frame_info *frame, int argi,
@@ -3339,6 +3348,89 @@ static const struct frame_unwind rs6000_frame_unwind =
    NULL,
    default_frame_sniffer
  };
+
+static struct rs6000_frame_cache *
+rs6000_epilogue_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+  volatile struct gdb_exception ex;
+  struct rs6000_frame_cache *cache;
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  CORE_ADDR sp;
+
+  if (*this_cache)
+    return *this_cache;
+
+  cache = FRAME_OBSTACK_ZALLOC (struct rs6000_frame_cache);
+  (*this_cache) = cache;
+  cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+
+  TRY_CATCH (ex, RETURN_MASK_ERROR)
+    {
+      /* At this point the stack looks as if we just entered the
+	 function, and the return address is stored in LR.  */
+      CORE_ADDR sp, lr;
+
+      sp = get_frame_register_unsigned (this_frame, gdbarch_sp_regnum (gdbarch));
+      lr = get_frame_register_unsigned (this_frame, tdep->ppc_lr_regnum);
+
+      cache->base = sp;
+      cache->initial_sp = sp;
+
+      trad_frame_set_value (cache->saved_regs,
+			    gdbarch_pc_regnum (gdbarch), lr);
+    }
+  if (ex.reason < 0 && ex.error != NOT_AVAILABLE_ERROR)
+    throw_exception (ex);
+
+  return cache;
+}
+
+static void
+rs6000_epilogue_frame_this_id (struct frame_info *this_frame,
+			       void **this_cache, struct frame_id *this_id)
+{
+  CORE_ADDR pc;
+  struct rs6000_frame_cache *info =
+    rs6000_epilogue_frame_cache (this_frame, this_cache);
+
+  pc = get_frame_func (this_frame);
+  if (info->base == 0)
+    (*this_id) = frame_id_build_unavailable_stack (pc);
+  else
+    (*this_id) = frame_id_build (info->base, pc);
+}
+
+static struct value *
+rs6000_epilogue_frame_prev_register (struct frame_info *this_frame,
+				     void **this_cache, int regnum)
+{
+  struct rs6000_frame_cache *info =
+    rs6000_epilogue_frame_cache (this_frame, this_cache);
+  return trad_frame_get_prev_register (this_frame, info->saved_regs, regnum);
+}
+
+static int
+rs6000_epilogue_frame_sniffer (const struct frame_unwind *self,
+			       struct frame_info *this_frame,
+			       void **this_prologue_cache)
+{
+  if (frame_relative_level (this_frame) == 0)
+    return rs6000_in_function_epilogue_frame_p (this_frame,
+						get_frame_arch (this_frame),
+						get_frame_pc (this_frame));
+  else
+    return 0;
+}
+
+static const struct frame_unwind rs6000_epilogue_frame_unwind =
+{
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  rs6000_epilogue_frame_this_id, rs6000_epilogue_frame_prev_register,
+  NULL,
+  rs6000_epilogue_frame_sniffer
+};
  \f

  static CORE_ADDR
@@ -3543,6 +3635,1420 @@ bfd_uses_spe_extensions (bfd *abfd)
    return success;
  }

+/* These are macros for parsing instruction fields (I.1.6.28)  */
+
+#define PPC_FIELD(value, from, len) \
+	(((value) >> (32 - (from) - (len))) & ((1 << (len)) - 1))
+#define PPC_SEXT(v, bs) \
+	((((CORE_ADDR) (v) & (((CORE_ADDR) 1 << (bs)) - 1)) \
+	  ^ ((CORE_ADDR) 1 << ((bs) - 1))) \
+	 - ((CORE_ADDR) 1 << ((bs) - 1)))
+#define PPC_OP6(insn)	PPC_FIELD (insn, 0, 6)
+#define PPC_EXTOP(insn)	PPC_FIELD (insn, 21, 10)
+#define PPC_RT(insn)	PPC_FIELD (insn, 6, 5)
+#define PPC_RS(insn)	PPC_FIELD (insn, 6, 5)
+#define PPC_RA(insn)	PPC_FIELD (insn, 11, 5)
+#define PPC_RB(insn)	PPC_FIELD (insn, 16, 5)
+#define PPC_NB(insn)	PPC_FIELD (insn, 16, 5)
+#define PPC_VRT(insn)	PPC_FIELD (insn, 6, 5)
+#define PPC_FRT(insn)	PPC_FIELD (insn, 6, 5)
+#define PPC_SPR(insn)	(PPC_FIELD (insn, 11, 5) \
+			| (PPC_FIELD (insn, 16, 5) << 5))
+#define PPC_BF(insn)	PPC_FIELD (insn, 6, 3)
+#define PPC_BO(insn)	PPC_FIELD (insn, 6, 5)
+#define PPC_T(insn)	PPC_FIELD (insn, 6, 5)
+#define PPC_D(insn)	PPC_SEXT (PPC_FIELD (insn, 16, 16), 16)
+#define PPC_DS(insn)	PPC_SEXT (PPC_FIELD (insn, 16, 14), 14)
+#define PPC_BIT(insn,n)	((insn & (1 << (31 - (n)))) ? 1 : 0)
+#define PPC_OE(insn)	PPC_BIT (insn, 21)
+#define PPC_RC(insn)	PPC_BIT (insn, 31)
+#define PPC_Rc(insn)	PPC_BIT (insn, 21)
+#define PPC_LK(insn)	PPC_BIT (insn, 31)
+#define PPC_TX(insn)	PPC_BIT (insn, 31)
+
+#define PPC_XT(insn)	((PPC_TX (insn) << 5) | PPC_T (insn))
+#define PPC_XER_NB(xer)	(xer & 0x7f)
+
+/* Record Vector-Scalar Registers.  */
+
+static int
+ppc_record_vsr (struct regcache *regcache, struct gdbarch_tdep *tdep, int vsr,
+		int size)
+{
+  if (vsr < 0 || vsr >= 64)
+    return -1;
+
+  if (vsr >= 32)
+    {
+      if (tdep->ppc_vr0_regnum >= 0)
+	record_full_arch_list_add_reg (regcache, tdep->ppc_vr0_regnum + vsr);
+    }
+  else
+    {
+      if (tdep->ppc_fp0_regnum >= 0)
+	record_full_arch_list_add_reg (regcache, tdep->ppc_fp0_regnum + vsr);
+      if (size > 8 && tdep->ppc_vsr0_upper_regnum >= 0)
+	record_full_arch_list_add_reg (regcache,
+				       tdep->ppc_vsr0_upper_regnum + vsr);
+    }
+
+  return 0;
+}
+
+/* Parse instructions of primary opcode-4.  */
+
+static int
+ppc64_process_record_op4 (struct gdbarch *gdbarch, struct regcache *regcache,
+			   CORE_ADDR addr, uint32_t insn)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int ext = PPC_FIELD (insn, 21, 11);
+
+  if ((ext & 0x3f) == 45)
+    {
+      /* Vector Permute and Exclusive-OR */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_vr0_regnum + PPC_VRT (insn));
+      return 0;
+    }
+
+  switch ((ext & 0x1ff))
+    {
+			/* 5.16 Decimal Integer Arithmetic Instructions */
+    case 1:		/* Decimal Add Modulo */
+    case 65:		/* Decimal Subtract Modulo */
+
+      /* Bit-21 should be set.  */
+      if (!PPC_BIT (insn, 21))
+	break;
+
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_vr0_regnum + PPC_VRT (insn));
+      record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum);
+      return 0;
+    }
+
+  /* Bit-21 is used for RC */
+  switch (ext & 0x3ff)
+    {
+    case 6:		/* Vector Compare Equal To Unsigned Byte */
+    case 70:		/* Vector Compare Equal To Unsigned Halfword */
+    case 134:		/* Vector Compare Equal To Unsigned Word */
+    case 199:		/* Vector Compare Equal To Unsigned Doubleword */
+    case 774:		/* Vector Compare Greater Than Signed Byte */
+    case 838:		/* Vector Compare Greater Than Signed Halfword */
+    case 902:		/* Vector Compare Greater Than Signed Word */
+    case 967:		/* Vector Compare Greater Than Signed Doubleword */
+    case 518:		/* Vector Compare Greater Than Unsigned Byte */
+    case 646:		/* Vector Compare Greater Than Unsigned Word */
+    case 582:		/* Vector Compare Greater Than Unsigned Halfword */
+    case 711:		/* Vector Compare Greater Than Unsigned Doubleword */
+    case 966:		/* Vector Compare Bounds Single-Precision */
+    case 198:		/* Vector Compare Equal To Single-Precision */
+    case 454:		/* Vector Compare Greater Than or Equal To Single-Precision */
+    case 710:		/* Vector Compare Greater Than Single-Precision */
+      if (PPC_Rc (insn))
+	record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum);
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_vr0_regnum + PPC_VRT (insn));
+      return 0;
+    }
+
+  switch (ext)
+    {
+    /* 5.8 Vector Permute and Formatting Instructions */
+    case 142:		/* Vector Pack Unsigned Halfword Unsigned Saturate */
+    case 206:		/* Vector Pack Unsigned Word Unsigned Saturate */
+    case 270:		/* Vector Pack Signed Halfword Unsigned Saturate */
+    case 334:		/* Vector Pack Signed Word Unsigned Saturate */
+    case 398:		/* Vector Pack Signed Halfword Signed Saturate */
+    case 462:		/* Vector Pack Signed Word Signed Saturate */
+    case 1230:		/* Vector Pack Unsigned Doubleword Unsigned Saturate */
+    case 1358:		/* Vector Pack Signed Doubleword Unsigned Saturate */
+    case 1486:		/* Vector Pack Signed Doubleword Signed Saturate */
+			/* 5.9 Vector Integer Instructions */
+    case 512:		/* Vector Add Unsigned Byte Saturate */
+    case 576:		/* Vector Add Unsigned Halfword Saturate */
+    case 640:		/* Vector Add Unsigned Word Saturate */
+    case 786:		/* Vector Add Signed Byte Saturate */
+    case 832:		/* Vector Add Signed Halfword Saturate */
+    case 896:		/* Vector Add Signed Word Saturate */
+    case 1536:		/* Vector Subtract Unsigned Byte Saturate */
+    case 1600:		/* Vector Subtract Unsigned Halfword Saturate */
+    case 1664:		/* Vector Subtract Unsigned Word Saturate */
+    case 1792:		/* Vector Subtract Signed Byte Saturate */
+    case 1856:		/* Vector Subtract Signed Halfword Saturate */
+    case 1920:		/* Vector Subtract Signed Word Saturate */
+    case 32:		/* Vector Multiply-High-Add Signed Halfword Saturate */
+    case 33:		/* Vector Multiply-High-Round-Add Signed Halfword Saturate */
+    case 39:		/* Vector Multiply-Sum Unsigned Halfword Saturate */
+    case 41:		/* Vector Multiply-Sum Signed Halfword Saturate */
+    case 1544:		/* Vector Sum across Quarter Unsigned Byte Saturate */
+    case 1800:		/* Vector Sum across Quarter Signed Byte Saturate */
+    case 1608:		/* Vector Sum across Quarter Signed Halfword Saturate */
+    case 1672:		/* Vector Sum across Half Signed Word Saturate */
+    case 1928:		/* Vector Sum across Signed Word Saturate */
+			/* 5.10 Vector Floating-Point Instruction Set */
+    case 970:		/* Vector Convert To Signed Fixed-Point Word Saturate */
+    case 906:		/* Vector Convert To Unsigned Fixed-Point Word Saturate */
+      record_full_arch_list_add_reg (regcache, PPC_VSCR_REGNUM);
+      /* FALL-THROUGH */
+			/* 5.8 Vector Permute and Formatting Instructions */
+    case 12:		/* Vector Merge High Byte */
+    case 14:		/* Vector Pack Unsigned Halfword Unsigned Modulo */
+    case 42:		/* Vector Select */
+    case 43:		/* Vector Permute */
+    case 76:		/* Vector Merge High Halfword */
+    case 78:		/* Vector Pack Unsigned Word Unsigned Modulo */
+    case 140:		/* Vector Merge High Word */
+    case 268:		/* Vector Merge Low Byte */
+    case 332:		/* Vector Merge Low Halfword */
+    case 396:		/* Vector Merge Low Word */
+    case 526:		/* Vector Unpack High Signed Byte */
+    case 590:		/* Vector Unpack High Signed Halfword */
+    case 654:		/* Vector Unpack Low Signed Byte */
+    case 718:		/* Vector Unpack Low Signed Halfword */
+    case 782:		/* Vector Pack Pixel */
+    case 846:		/* Vector Unpack High Pixel */
+    case 974:		/* Vector Unpack Low Pixel */
+    case 1102:		/* Vector Pack Unsigned Doubleword Unsigned Modulo */
+    case 1614:		/* Vector Unpack High Signed Word */
+    case 1676:		/* Vector Merge Odd Word */
+    case 1742:		/* Vector Unpack Low Signed Word */
+    case 1932:		/* Vector Merge Even Word */
+    case 524:		/* Vector Splat Byte */
+    case 588:		/* Vector Splat Halfword */
+    case 652:		/* Vector Splat Word */
+    case 780:		/* Vector Splat Immediate Signed Byte */
+    case 844:		/* Vector Splat Immediate Signed Halfword */
+    case 908:		/* Vector Splat Immediate Signed Word */
+    case 44:		/* Vector Shift Left Double by Octet Immediate */
+    case 452:		/* Vector Shift Left */
+    case 708:		/* Vector Shift Right */
+    case 1036:		/* Vector Shift Left by Octet */
+    case 1100:		/* Vector Shift Right by Octet */
+			/* 5.9 Vector Integer Instructions */
+    case 60:		/* Vector Add Extended Unsigned Quadword Modulo */
+    case 61:		/* Vector Add Extended & write Carry Unsigned Quadword */
+    case 62:		/* Vector Subtract Extended Unsigned Quadword Modulo */
+    case 63:		/* Vector Subtract Extended & write Carry Unsigned Quadword */
+    case 0:		/* Vector Add Unsigned Byte Modulo */
+    case 64:		/* Vector Add Unsigned Halfword Modulo */
+    case 128:		/* Vector Add Unsigned Word Modulo */
+    case 192:		/* Vector Add Unsigned Doubleword Modulo */
+    case 256:		/* Vector Add Unsigned Quadword Modulo */
+    case 320:		/* Vector Add & write Carry Unsigned Quadword */
+    case 384:		/* Vector Add and Write Carry-Out Unsigned Word */
+    case 8:		/* Vector Multiply Odd Unsigned Byte */
+    case 72:		/* Vector Multiply Odd Unsigned Halfword */
+    case 136:		/* Vector Multiply Odd Unsigned Word */
+    case 264:		/* Vector Multiply Odd Signed Byte */
+    case 328:		/* Vector Multiply Odd Signed Halfword */
+    case 392:		/* Vector Multiply Odd Signed Word */
+    case 520:		/* Vector Multiply Even Unsigned Byte */
+    case 584:		/* Vector Multiply Even Unsigned Halfword */
+    case 648:		/* Vector Multiply Even Unsigned Word */
+    case 776:		/* Vector Multiply Even Signed Byte */
+    case 840:		/* Vector Multiply Even Signed Halfword */
+    case 940:		/* Vector Multiply Even Signed Word */
+    case 137:		/* Vector Multiply Unsigned Word Modulo */
+    case 1024:		/* Vector Subtract Unsigned Byte Modulo */
+    case 1088:		/* Vector Subtract Unsigned Halfword Modulo */
+    case 1152:		/* Vector Subtract Unsigned Word Modulo */
+    case 1216:		/* Vector Subtract Unsigned Doubleword Modulo */
+    case 1280:		/* Vector Subtract Unsigned Quadword Modulo */
+    case 1344:		/* Vector Subtract & write Carry Unsigned Quadword */
+    case 1408:		/* Vector Subtract and Write Carry-Out Unsigned Word */
+    case 34:		/* Vector Multiply-Low-Add Unsigned Halfword Modulo */
+    case 36:		/* Vector Multiply-Sum Unsigned Byte Modulo */
+    case 37:		/* Vector Multiply-Sum Mixed Byte Modulo */
+    case 38:		/* Vector Multiply-Sum Unsigned Halfword Modulo */
+    case 40:		/* Vector Multiply-Sum Signed Halfword Modulo */
+    case 1282:		/* Vector Average Signed Byte */
+    case 1346:		/* Vector Average Signed Halfword */
+    case 1410:		/* Vector Average Signed Word */
+    case 1026:		/* Vector Average Unsigned Byte */
+    case 1090:		/* Vector Average Unsigned Halfword */
+    case 1154:		/* Vector Average Unsigned Word */
+    case 258:		/* Vector Maximum Signed Byte */
+    case 322:		/* Vector Maximum Signed Halfword */
+    case 386:		/* Vector Maximum Signed Word */
+    case 450:		/* Vector Maximum Signed Doubleword */
+    case 2:		/* Vector Maximum Unsigned Byte */
+    case 66:		/* Vector Maximum Unsigned Halfword */
+    case 130:		/* Vector Maximum Unsigned Word */
+    case 194:		/* Vector Maximum Unsigned Doubleword */
+    case 770:		/* Vector Minimum Signed Byte */
+    case 834:		/* Vector Minimum Signed Halfword */
+    case 898:		/* Vector Minimum Signed Word */
+    case 962:		/* Vector Minimum Signed Doubleword */
+    case 514:		/* Vector Minimum Unsigned Byte */
+    case 578:		/* Vector Minimum Unsigned Halfword */
+    case 642:		/* Vector Minimum Unsigned Word */
+    case 706:		/* Vector Minimum Unsigned Doubleword */
+    case 1028:		/* Vector Logical AND */
+    case 1668:		/* Vector Logical Equivalent */
+    case 1092:		/* Vector Logical AND with Complement */
+    case 1412:		/* Vector Logical NAND */
+    case 1348:		/* Vector Logical OR with Complement */
+    case 1156:		/* Vector Logical OR */
+    case 1284:		/* Vector Logical NOR */
+    case 1220:		/* Vector Logical XOR */
+    case 4:		/* Vector Rotate Left Byte */
+    case 132:		/* Vector Rotate Left Word VX-form */
+    case 68:		/* Vector Rotate Left Halfword */
+    case 196:		/* Vector Rotate Left Doubleword */
+    case 260:		/* Vector Shift Left Byte */
+    case 388:		/* Vector Shift Left Word */
+    case 324:		/* Vector Shift Left Halfword */
+    case 1476:		/* Vector Shift Left Doubleword */
+    case 516:		/* Vector Shift Right Byte */
+    case 644:		/* Vector Shift Right Word */
+    case 580:		/* Vector Shift Right Halfword */
+    case 1732:		/* Vector Shift Right Doubleword */
+    case 772:		/* Vector Shift Right Algebraic Byte */
+    case 900:		/* Vector Shift Right Algebraic Word */
+    case 836:		/* Vector Shift Right Algebraic Halfword */
+    case 864:		/* Vector Shift Right Algebraic Doubleword */
+			/* 5.10 Vector Floating-Point Instruction Set */
+    case 10:		/* Vector Add Single-Precision */
+    case 74:		/* Vector Subtract Single-Precision */
+    case 46:		/* Vector Multiply-Add Single-Precision */
+    case 47:		/* Vector Negative Multiply-Subtract Single-Precision */
+    case 1034:		/* Vector Maximum Single-Precision */
+    case 1098:		/* Vector Minimum Single-Precision */
+    case 842:		/* Vector Convert From Signed Fixed-Point Word */
+    case 778:		/* Vector Convert From Unsigned Fixed-Point Word */
+    case 714:		/* Vector Round to Single-Precision Integer toward -Infinity */
+    case 522:		/* Vector Round to Single-Precision Integer Nearest */
+    case 650:		/* Vector Round to Single-Precision Integer toward +Infinity */
+    case 586:		/* Vector Round to Single-Precision Integer toward Zero */
+    case 394:		/* Vector 2 Raised to the Exponent Estimate Floating-Point */
+    case 458:		/* Vector Log Base 2 Estimate Floating-Point */
+    case 266:		/* Vector Reciprocal Estimate Single-Precision */
+    case 330:		/* Vector Reciprocal Square Root Estimate Single-Precision */
+			/* 5.11 Vector Exclusive-OR-based Instructions */
+    case 1288:		/* Vector AES Cipher */
+    case 1289:		/* Vector AES Cipher Last */
+    case 1352:		/* Vector AES Inverse Cipher */
+    case 1353:		/* Vector AES Inverse Cipher Last */
+    case 1480:		/* Vector AES SubBytes */
+    case 1730:		/* Vector SHA-512 Sigma Doubleword */
+    case 1666:		/* Vector SHA-256 Sigma Word */
+    case 1032:		/* Vector Polynomial Multiply-Sum Byte */
+    case 1160:		/* Vector Polynomial Multiply-Sum Word */
+    case 1096:		/* Vector Polynomial Multiply-Sum Halfword */
+    case 1224:		/* Vector Polynomial Multiply-Sum Doubleword */
+			/* 5.12 Vector Gather Instruction */
+    case 1292:		/* Vector Gather Bits by Bytes by Doubleword */
+			/* 5.13 Vector Count Leading Zeros Instructions */
+    case 1794:		/* Vector Count Leading Zeros Byte */
+    case 1858:		/* Vector Count Leading Zeros Halfword */
+    case 1922:		/* Vector Count Leading Zeros Word */
+    case 1986:		/* Vector Count Leading Zeros Doubleword */
+			/* 5.14 Vector Population Count Instructions */
+    case 1795:		/* Vector Population Count Byte */
+    case 1859:		/* Vector Population Count Halfword */
+    case 1923:		/* Vector Population Count Word */
+    case 1987:		/* Vector Population Count Doubleword */
+			/* 5.15 Vector Bit Permute Instruction */
+    case 1356:		/* Vector Bit Permute Quadword */
+			/* 5.16 Decimal Integer Arithmetic Instructions */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_vr0_regnum + PPC_VRT (insn));
+      return 0;
+
+			/* 5.17 Vector Status and Control Register Instructions */
+    case 1604:		/* Move To Vector Status and Control Register */
+      record_full_arch_list_add_reg (regcache, PPC_VSCR_REGNUM);
+      return 0;
+    case 1540:		/* Move From Vector Status and Control Register */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_vr0_regnum + PPC_VRT (insn));
+      return 0;
+    }
+
+  fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record "
+		      "%08x at %08lx, 4-%d.\n", insn, addr, ext);
+  return -1;
+}
+
+/* Parse instructions of primary opcode-19.  */
+
+static int
+ppc64_process_record_op19 (struct gdbarch *gdbarch, struct regcache *regcache,
+			   CORE_ADDR addr, uint32_t insn)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int ext = PPC_EXTOP (insn);
+
+  switch (ext)
+    {
+    case 0:		/* Move Condition Register Field */
+    case 33:		/* Condition Register NOR */
+    case 129:		/* Condition Register AND with Complement */
+    case 193:		/* Condition Register XOR */
+    case 225:		/* Condition Register NAND */
+    case 257:		/* Condition Register AND */
+    case 289:		/* Condition Register Equivalent */
+    case 417:		/* Condition Register OR with Complement */
+    case 449:		/* Condition Register OR */
+      record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum);
+      return 0;
+
+    case 16:		/* Branch Conditional */
+    case 560:		/* Branch Conditional to Branch Target Address Register */
+      if (PPC_BO (insn) & 0x2)
+	record_full_arch_list_add_reg (regcache, tdep->ppc_ctr_regnum);
+      /* FALL-THROUGH */
+    case 528:		/* Branch Conditional to Count Register */
+      if (PPC_LK (insn))
+	record_full_arch_list_add_reg (regcache, tdep->ppc_lr_regnum);
+      return 0;
+
+    case 150:		/* Instruction Synchronize */
+      /* Do nothing.  */
+      return 0;
+    }
+
+  fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record "
+		      "%08x at %08lx, 19-%d.\n", insn, addr, ext);
+  return -1;
+}
+
+/* Parse instructions of primary opcode-31.  */
+
+static int
+ppc64_process_record_op31 (struct gdbarch *gdbarch, struct regcache *regcache,
+			   CORE_ADDR addr, uint32_t insn)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int ext = PPC_EXTOP (insn);
+  int tmp, nr, nb, i;
+  CORE_ADDR at_dcsz, at_icsz, ea = 0;
+  ULONGEST rb, ra, xer;
+  int size = 0;
+
+  /* These instructions have OE bit.  */
+  switch (ext & 0x1ff)
+    {
+    /* These write RT and XER.  Update CR if RC is set.  */
+    case 8:		/* Subtract from carrying */
+    case 10:		/* Add carrying */
+    case 136:		/* Subtract from extended */
+    case 138:		/* Add extended */
+    case 200:		/* Subtract from zero extended */
+    case 202:		/* Add to zero extended */
+    case 232:		/* Subtract from minus one extended */
+    case 234:		/* Add to minus one extended */
+      /* CA is always altered, but SO/OV are only altered when OE=1.
+	 In any case, XER is always altered.  */
+      record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum);
+      if (PPC_RC (insn))
+	record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum);
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_gp0_regnum + PPC_RT (insn));
+      return 0;
+
+    /* These write RT.  Update CR if RC is set and update XER if OE is set.  */
+    case 40:		/* Subtract from */
+    case 104:		/* Negate */
+    case 233:		/* Multiply low doubleword */
+    case 235:		/* Multiply low word */
+    case 266:		/* Add */
+    case 393:		/* Divide Doubleword Extended Unsigned */
+    case 395:		/* Divide Word Extended Unsigned */
+    case 425:		/* Divide Doubleword Extended */
+    case 427:		/* Divide Word Extended */
+    case 457:		/* Divide Doubleword Unsigned */
+    case 459:		/* Divide Word Unsigned */
+    case 489:		/* Divide Doubleword */
+    case 491:		/* Divide Word */
+      if (PPC_OE (insn))
+	record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum);
+      /* FALL-THROUGH */
+    case 9:		/* Multiply High Doubleword Unsigned */
+    case 11:		/* Multiply High Word Unsigned */
+    case 73:		/* Multiply High Doubleword */
+    case 75:		/* Multiply High Word */
+      if (PPC_RC (insn))
+	record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum);
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_gp0_regnum + PPC_RT (insn));
+      return 0;
+    }
+
+  if ((ext & 0x1f) == 15)
+    {
+      /* Integer Select. bit[16:20] is used for BC.  */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_gp0_regnum + PPC_RT (insn));
+      return 0;
+    }
+
+  switch (ext)
+    {
+    case 78:		/* Determine Leftmost Zero Byte */
+      /* CA is always altered, but SO/OV are only altered when OE=1.
+	 In any case, XER is always altered.  */
+      record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum);
+      if (PPC_RC (insn))
+	record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum);
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_gp0_regnum + PPC_RT (insn));
+      return 0;
+
+    /* These only write RT.  */
+    case 19:		/* Move from condition register */
+			/* Move From One Condition Register Field */
+    case 74:		/* Add and Generate Sixes */
+    case 74 | 0x200:	/* Add and Generate Sixes (bit-21 dont-care) */
+    case 302:		/* Move From Branch History Rolling Buffer */
+    case 334:		/* Move From Performance Monitor Register */
+    case 339:		/* Move From Special Purpose Register */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_gp0_regnum + PPC_RT (insn));
+      return 0;
+
+    /* These only write to RA.  */
+    case 51:		/* Move From VSR Doubleword */
+    case 115:		/* Move From VSR Word and Zero */
+    case 122:		/* Population count bytes */
+    case 378:		/* Population count words */
+    case 506:		/* Population count doublewords */
+    case 154:		/* Parity Word */
+    case 186:		/* Parity Doubleword */
+    case 252:		/* Bit Permute Doubleword */
+    case 282:		/* Convert Declets To Binary Coded Decimal */
+    case 314:		/* Convert Binary Coded Decimal To Declets */
+    case 508:		/* Compare bytes */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_gp0_regnum + PPC_RA (insn));
+      return 0;
+
+    /* These write CR and optional RA.  */
+    case 792:		/* Shift Right Algebraic Word */
+    case 794:		/* Shift Right Algebraic Doubleword */
+    case 824:		/* Shift Right Algebraic Word Immediate */
+    case 826:		/* Shift Right Algebraic Doubleword Immediate (413) */
+    case 826 | 1:	/* Shift Right Algebraic Doubleword Immediate (413) */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_gp0_regnum + PPC_RA (insn));
+      /* FALL-THROUGH */
+    case 0:		/* Compare */
+    case 32:		/* Compare logical */
+    case 144:		/* Move To Condition Register Fields */
+			/* Move To One Condition Register Field */
+      record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum);
+      return 0;
+
+    /* These write to RT.  Update RA if 'update indexed.'  */
+    case 53:		/* Load Doubleword with Update Indexed */
+    case 119:		/* Load Byte and Zero with Update Indexed */
+    case 311:		/* Load Halfword and Zero with Update Indexed */
+    case 55:		/* Load Word and Zero with Update Indexed */
+    case 375:		/* Load Halfword Algebraic with Update Indexed */
+    case 373:		/* Load Word Algebraic with Update Indexed */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_gp0_regnum + PPC_RA (insn));
+      /* FALL-THROUGH */
+    case 21:		/* Load Doubleword Indexed */
+    case 52:		/* Load Byte And Reserve Indexed */
+    case 116:		/* Load Halfword And Reserve Indexed */
+    case 20:		/* Load Word And Reserve Indexed */
+    case 84:		/* Load Doubleword And Reserve Indexed */
+    case 87:		/* Load Byte and Zero Indexed */
+    case 279:		/* Load Halfword and Zero Indexed */
+    case 23:		/* Load Word and Zero Indexed */
+    case 343:		/* Load Halfword Algebraic Indexed */
+    case 341:		/* Load Word Algebraic Indexed */
+    case 790:		/* Load Halfword Byte-Reverse Indexed */
+    case 534:		/* Load Word Byte-Reverse Indexed */
+    case 532:		/* Load Doubleword Byte-Reverse Indexed */
+    case 853:		/* Load Byte and Zero Caching Inhibited Indexed */
+    case 821:		/* Load Halfword and Zero Caching Inhibited Indexed */
+    case 789:		/* Load Word and Zero Caching Inhibited Indexed */
+    case 885:		/* Load Doubleword Caching Inhibited Indexed */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_gp0_regnum + PPC_RT (insn));
+      return 0;
+
+    case 597:		/* Load String Word Immediate */
+    case 533:		/* Load String Word Indexed */
+      if (ext == 597)
+	nr = PPC_NB (insn);
+      else
+	{
+	  regcache_raw_read_unsigned (regcache, tdep->ppc_xer_regnum, &xer);
+	  nr = PPC_XER_NB (xer);
+	}
+
+      nr = (nr + 3) >> 2;
+
+      for (i = 0; i < nr; i++)
+	record_full_arch_list_add_reg (regcache,
+				       tdep->ppc_gp0_regnum
+				       + ((PPC_RT (insn) + i) & 0x1f));
+      return 0;
+
+    case 276:		/* Load Quadword And Reserve Indexed */
+      tmp = (tdep->ppc_gp0_regnum + PPC_RT (insn)) & ~1;
+      record_full_arch_list_add_reg (regcache, tmp);
+      record_full_arch_list_add_reg (regcache, tmp | 1);
+      return 0;
+
+    /* These write VRT.  */
+    case 6:		/* Load Vector for Shift Left Indexed */
+    case 38:		/* Load Vector for Shift Right Indexed */
+    case 7:		/* Load Vector Element Byte Indexed */
+    case 39:		/* Load Vector Element Halfword Indexed */
+    case 71:		/* Load Vector Element Word Indexed */
+    case 103:		/* Load Vector Indexed */
+    case 359:		/* Load Vector Indexed LRU */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_vr0_regnum + PPC_VRT (insn));
+      return 0;
+
+    /* These write FRT.  Update RA if 'update indexed.'  */
+    case 567:		/* Load Floating-Point Single with Update Indexed */
+    case 631:		/* Load Floating-Point Double with Update Indexed */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_gp0_regnum + PPC_RA (insn));
+      /* FALL-THROUGH */
+    case 535:		/* Load Floating-Point Single Indexed */
+    case 599:		/* Load Floating-Point Double Indexed */
+    case 855:		/* Load Floating-Point as Integer Word Algebraic Indexed */
+    case 887:		/* Load Floating-Point as Integer Word and Zero Indexed */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_fp0_regnum + PPC_FRT (insn));
+      return 0;
+
+    case 791:		/* Load Floating-Point Double Pair Indexed */
+      tmp = (tdep->ppc_fp0_regnum + PPC_FRT (insn)) & ~1;
+      record_full_arch_list_add_reg (regcache, tmp);
+      record_full_arch_list_add_reg (regcache, tmp | 1);
+      return 0;
+
+    /* These write VSR of size 8.  */
+    case 588:		/* Load VSX Scalar Doubleword Indexed */
+      ppc_record_vsr (regcache, tdep, PPC_XT (insn), 8);
+      return 0;
+
+    /* These write VSR of size 16.  */
+    case 179:		/* Move To VSR Doubleword */
+    case 211:		/* Move To VSR Word Algebraic */
+    case 243:		/* Move To VSR Word and Zero */
+    case 524:		/* Load VSX Scalar Single-Precision Indexed */
+    case 76:		/* Load VSX Scalar as Integer Word Algebraic Indexed */
+    case 12:		/* Load VSX Scalar as Integer Word and Zero Indexed */
+    case 844:		/* Load VSX Vector Doubleword*2 Indexed */
+    case 332:		/* Load VSX Vector Doubleword & Splat Indexed */
+    case 780:		/* Load VSX Vector Word*4 Indexed */
+      ppc_record_vsr (regcache, tdep, PPC_XT (insn), 16);
+      return 0;
+
+    /* These write RA.  Update CR if RC is set.  */
+    case 24:		/* Shift Left Word */
+    case 26:		/* Count Leading Zeros Word */
+    case 27:		/* Shift Left Doubleword */
+    case 28:		/* AND */
+    case 58:		/* Count Leading Zeros Doubleword */
+    case 60:		/* AND with Complement */
+    case 124:		/* NOR */
+    case 284:		/* Equivalent */
+    case 316:		/* XOR */
+    case 476:		/* NAND */
+    case 412:		/* OR with Complement */
+    case 444:		/* OR */
+    case 536:		/* Shift Right Word */
+    case 539:		/* Shift Right Doubleword */
+    case 922:		/* Extend Sign Halfword */
+    case 954:		/* Extend Sign Byte */
+    case 986:		/* Extend Sign Word */
+      if (PPC_RC (insn))
+	record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum);
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_gp0_regnum + PPC_RA (insn));
+      return 0;
+
+    /* Store memory.  */
+    case 181:		/* Store Doubleword with Update Indexed */
+    case 183:		/* Store Word with Update Indexed */
+    case 247:		/* Store Byte with Update Indexed */
+    case 439:		/* Store Half Word with Update Indexed */
+    case 695:		/* Store Floating-Point Single with Update Indexed */
+    case 759:		/* Store Floating-Point Double with Update Indexed */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_gp0_regnum + PPC_RA (insn));
+      /* FALL-THROUGH */
+    case 135:		/* Store Vector Element Byte Indexed */
+    case 167:		/* Store Vector Element Halfword Indexed */
+    case 199:		/* Store Vector Element Word Indexed */
+    case 231:		/* Store Vector Indexed */
+    case 487:		/* Store Vector Indexed LRU */
+    case 716:		/* Store VSX Scalar Doubleword Indexed */
+    case 140:		/* Store VSX Scalar as Integer Word Indexed */
+    case 652:		/* Store VSX Scalar Single-Precision Indexed */
+    case 972:		/* Store VSX Vector Doubleword*2 Indexed */
+    case 908:		/* Store VSX Vector Word*4 Indexed */
+    case 149:		/* Store Doubleword Indexed */
+    case 151:		/* Store Word Indexed */
+    case 215:		/* Store Byte Indexed */
+    case 407:		/* Store Half Word Indexed */
+    case 694:		/* Store Byte Conditional Indexed */
+    case 726:		/* Store Halfword Conditional Indexed */
+    case 150:		/* Store Word Conditional Indexed */
+    case 214:		/* Store Doubleword Conditional Indexed */
+    case 182:		/* Store Quadword Conditional Indexed */
+    case 662:		/* Store Word Byte-Reverse Indexed */
+    case 918:		/* Store Halfword Byte-Reverse Indexed */
+    case 660:		/* Store Doubleword Byte-Reverse Indexed */
+    case 663:		/* Store Floating-Point Single Indexed */
+    case 727:		/* Store Floating-Point Double Indexed */
+    case 981:		/* Store Byte Caching Inhibited Indexed */
+    case 949:		/* Store Halfword Caching Inhibited Indexed */
+    case 917:		/* Store Word Caching Inhibited Indexed */
+    case 1013:		/* Store Doubleword Caching Inhibited Indexed */
+    case 919:		/* Store Floating-Point Double Pair Indexed */
+    case 983:		/* Store Floating-Point as Integer Word Indexed */
+      if (ext == 694 || ext == 726 || ext == 150 || ext == 214 || ext == 182)
+	record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum);
+
+      ra = 0;
+      if (PPC_RA (insn) != 0)
+	regcache_raw_read_unsigned (regcache,
+				    tdep->ppc_gp0_regnum + PPC_RA (insn), &ra);
+      regcache_raw_read_unsigned (regcache,
+				  tdep->ppc_gp0_regnum + PPC_RB (insn), &rb);
+      ea = ra + rb;
+
+      switch (ext)
+	{
+	case 183:	/* Store Word with Update Indexed */
+	case 199:	/* Store Vector Element Word Indexed */
+	case 140:	/* Store VSX Scalar as Integer Word Indexed */
+	case 652:	/* Store VSX Scalar Single-Precision Indexed */
+	case 151:	/* Store Word Indexed */
+	case 150:	/* Store Word Conditional Indexed */
+	case 917:	/* Store Word Caching Inhibited Indexed */
+	case 663:	/* Store Floating-Point Single Indexed */
+	case 695:	/* Store Floating-Point Single with Update Indexed */
+	case 983:	/* Store Floating-Point as Integer Word Indexed */
+	  size = 4;
+	  break;
+	case 247:	/* Store Byte with Update Indexed */
+	case 135:	/* Store Vector Element Byte Indexed */
+	case 215:	/* Store Byte Indexed */
+	case 694:	/* Store Byte Conditional Indexed */
+	case 662:	/* Store Word Byte-Reverse Indexed */
+	case 981:	/* Store Byte Caching Inhibited Indexed */
+	  size = 1;
+	  break;
+	case 439:	/* Store Half Word with Update Indexed */
+	case 167:	/* Store Vector Element Halfword Indexed */
+	case 407:	/* Store Half Word Indexed */
+	case 726:	/* Store Halfword Conditional Indexed */
+	case 918:	/* Store Halfword Byte-Reverse Indexed */
+	case 949:	/* Store Halfword Caching Inhibited Indexed */
+	  size = 2;
+	  break;
+	case 181:	/* Store Doubleword with Update Indexed */
+	case 716:	/* Store VSX Scalar Doubleword Indexed */
+	case 149:	/* Store Doubleword Indexed */
+	case 214:	/* Store Doubleword Conditional Indexed */
+	case 660:	/* Store Doubleword Byte-Reverse Indexed */
+	case 1013:	/* Store Doubleword Caching Inhibited Indexed */
+	  size = 8;
+	  break;
+	case 972:	/* Store VSX Vector Doubleword*2 Indexed */
+	case 908:	/* Store VSX Vector Word*4 Indexed */
+	case 182:	/* Store Quadword Conditional Indexed */
+	case 231:	/* Store Vector Indexed */
+	case 487:	/* Store Vector Indexed LRU */
+	case 919:	/* Store Floating-Point Double Pair Indexed */
+	  size = 16;
+	  break;
+	}
+
+      /* Align address for Store Vector instructions.  */
+      if ((ext & 0x1f) == 0x7)
+	{
+	  if ((ext & 0x3) < 3)
+	    addr = (addr >> (ext & 0x3)) << (ext & 0x3);
+	  else
+	    addr = addr & ~0x7ULL;
+	}
+
+      record_full_arch_list_add_mem (addr, size);
+      return 0;
+
+    case 725:		/* Store String Word Immediate */
+    case 661:		/* Store String Word Indexed */
+      ra = 0;
+      if (PPC_RA (insn) != 0)
+	regcache_raw_read_unsigned (regcache, tdep->ppc_xer_regnum, &ra);
+      ea += ra;
+
+      if (ext == 725)
+	nb = PPC_NB (insn);
+      else
+	{
+	  regcache_raw_read_unsigned (regcache, tdep->ppc_xer_regnum, &xer);
+	  nb = PPC_XER_NB (xer);
+
+	  regcache_raw_read_unsigned (regcache, tdep->ppc_xer_regnum, &rb);
+	  ea += rb;
+	}
+
+      record_full_arch_list_add_mem (ea, nb);
+      return 0;
+
+    case 467:		/* Move To Special Purpose Register */
+      switch (PPC_SPR (insn))
+	{
+	case 1:			/* XER */
+	  record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum);
+	  return 0;
+	case 8:			/* LR */
+	  record_full_arch_list_add_reg (regcache, tdep->ppc_lr_regnum);
+	  return 0;
+	case 9:			/* CTR */
+	  record_full_arch_list_add_reg (regcache, tdep->ppc_ctr_regnum);
+	  return 0;
+	}
+
+      goto UNKNOWN_OP;
+
+    case 147:		/* Move To Split Little Endian */
+      record_full_arch_list_add_reg (regcache, tdep->ppc_ps_regnum);
+      return 0;
+
+    case 512:		/* Move to Condition Register from XER */
+      record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum);
+      record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum);
+      return 0;
+
+    case 4:		/* Trap Word */
+    case 68:		/* Trap Doubleword */
+    case 430:		/* Clear BHRB */
+    case 598:		/* Synchronize */
+    case 62:		/* Wait for Interrupt */
+    case 22:		/* Instruction Cache Block Touch */
+    case 854:		/* Enforce In-order Execution of I/O */
+    case 246:		/* Data Cache Block Touch for Store */
+    case 54:		/* Data Cache Block Store */
+    case 86:		/* Data Cache Block Flush */
+    case 278:		/* Data Cache Block Touch */
+    case 758:		/* Data Cache Block Allocate */
+      return 0;
+
+    case 18:		/* TLB Invalidate Local Indexed */
+    case 326:		/* Data Cache Read */
+    case 63:		/* Data Cache Block Store by External PID */
+    case 127:		/* Data Cache Block Flush by External PID */
+    case 134:		/* Data Cache Block Touch for Store and Lock Set */
+    case 166:		/* Data Cache Block Touch and Lock Set */
+    case 255:		/* Data Cache Block Touch for Store by External PID */
+    case 319:		/* Data Cache Block Touch by External PID */
+    case 390:		/* Data Cache Block Lock Clear */
+    case 422:		/* Data Cache Block Lock Query */
+    case 454:		/* Data Cache Invalidate */
+    case 998:		/* Instruction Cache Read */
+    case 966:		/* Instruction Cache Invalidate */
+    case 982:		/* Instruction Cache Block Invalidate */
+    case 198:		/* Instruction Cache Block Lock Query */
+    case 230:		/* Instruction Cache Block Lock Clear */
+    case 486:		/* Instruction Cache Block Touch and Lock Set */
+    case 206:		/* Message Send */
+    case 238:		/* Message Clear */
+    case 142:		/* Message Send Privileged */
+    case 174:		/* Message Clear Privileged */
+    case 131:		/* Write MSR External Enable */
+    case 163:		/* Write MSR External Enable Immediate */
+    case 270:		/* Embedded Hypervisor Privilege */
+    case 462:		/* Move To Performance Monitor Register */
+    case 494:		/* Move To Thread Management Register */
+    case 807:		/* Store Vector by External Process ID Indexed */
+    case 775:		/* Store Vector by External Process ID Indexed LRU */
+    case 95:		/* Load Byte by External Process ID Indexed */
+    case 287:		/* Load Halfword by External Process ID Indexed */
+    case 31:		/* Load Word by External Process ID Indexed */
+    case 29:		/* Load Doubleword by External Process ID Indexed */
+    case 295:		/* Load Vector by External Process ID Indexed */
+    case 263:		/* Load Vector by External Process ID Indexed LRU */
+    case 259:		/* Move From Device Control Register Indexed */
+    case 323:		/* Move From Device Control Register */
+    case 146:		/* Move To Machine State Register */
+    case 178:		/* Move To Machine State Register Doubleword */
+    case 387:		/* Move To Device Control Register Indexed */
+    case 419:		/* Move To Device Control Register User-mode Indexed */
+    case 291:		/* Move From Device Control Register User-mode Indexed */
+    case 451:		/* Move To Device Control Register */
+      /* Privileged instructions.  */
+      fprintf_unfiltered (gdb_stdlog, "Cannot record privileged instructions. "
+			  "%08x at %08lx, 31-%d.\n", insn, addr, ext);
+      return -1;
+
+    case 654:		/* Transaction Begin */
+    case 686:		/* Transaction End */
+    case 718:		/* Transaction Check */
+    case 750:		/* Transaction Suspend or Resume */
+    case 782:		/* Transaction Abort Word Conditional */
+    case 814:		/* Transaction Abort Doubleword Conditional */
+    case 846:		/* Transaction Abort Word Conditional Immediate */
+    case 878:		/* Transaction Abort Doubleword Conditional Immediate */
+    case 910:		/* Transaction Abort */
+    case 942:		/* Transaction Reclaim */
+    case 1006:		/* Transaction Recheckpoint */
+      fprintf_unfiltered (gdb_stdlog, "Cannot record Transaction instructions. "
+			  "%08x at %08lx, 31-%d.\n", insn, addr, ext);
+      return -1;
+
+    case 1014:		/* Data Cache Block set to Zero */
+      if (target_auxv_search (&current_target, AT_DCACHEBSIZE, &at_dcsz) <= 0
+	  || at_dcsz == 0)
+	at_dcsz = 128; /* Assume 128-byte cache line size (POWER8)  */
+
+      if (PPC_RA (insn) != 0)
+	regcache_raw_read_unsigned (regcache,
+				    tdep->ppc_gp0_regnum + PPC_RA (insn), &ra);
+      regcache_raw_read_unsigned (regcache,
+				  tdep->ppc_gp0_regnum + PPC_RB (insn), &rb);
+      ea = (ra + rb) & ~((ULONGEST) (at_dcsz - 1));
+      record_full_arch_list_add_mem (ea, at_dcsz);
+      return 0;
+    }
+
+UNKNOWN_OP:
+  fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record "
+		      "%08x at %08lx, 31-%d.\n", insn, addr, ext);
+  return -1;
+}
+
+/* Parse instructions of primary opcode-59.  */
+
+static int
+ppc64_process_record_op59 (struct gdbarch *gdbarch, struct regcache *regcache,
+			   CORE_ADDR addr, uint32_t insn)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int ext = PPC_EXTOP (insn);
+
+  switch (ext & 0x1f)
+    {
+    case 18:		/* Floating Divide */
+    case 20:		/* Floating Subtract */
+    case 21:		/* Floating Add */
+    case 22:		/* Floating Square Root */
+    case 24:		/* Floating Reciprocal Estimate */
+    case 25:		/* Floating Multiply */
+    case 26:		/* Floating Reciprocal Square Root Estimate */
+    case 28:		/* Floating Multiply-Subtract */
+    case 29:		/* Floating Multiply-Add */
+    case 30:		/* Floating Negative Multiply-Subtract */
+    case 31:		/* Floating Negative Multiply-Add */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_fp0_regnum + PPC_FRT (insn));
+      if (PPC_RC (insn))
+	record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum);
+      record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum);
+
+      return 0;
+    }
+
+  switch (ext)
+    {
+    case 2:		/* DFP Add */
+    case 3:		/* DFP Quantize */
+    case 34:		/* DFP Multiply */
+    case 35:		/* DFP Reround */
+    case 67:		/* DFP Quantize Immediate */
+    case 99:		/* DFP Round To FP Integer With Inexact */
+    case 227:		/* DFP Round To FP Integer Without Inexact */
+    case 258:		/* DFP Convert To DFP Long! */
+    case 290:		/* DFP Convert To Fixed */
+    case 514:		/* DFP Subtract */
+    case 546:		/* DFP Divide */
+    case 770:		/* DFP Round To DFP Short! */
+    case 802:		/* DFP Convert From Fixed */
+    case 834:		/* DFP Encode BCD To DPD */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_fp0_regnum + PPC_FRT (insn));
+      /* FALL-THROUGH */
+    case 130:		/* DFP Compare Ordered */
+    case 162:		/* DFP Test Exponent */
+    case 194:		/* DFP Test Data Class */
+    case 226:		/* DFP Test Data Group */
+    case 642:		/* DFP Compare Unordered */
+    case 674:		/* DFP Test Significance */
+      if (PPC_RC (insn))
+	record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum);
+      record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum);
+      return 0;
+
+    case 66:		/* DFP Shift Significand Left Immediate */
+    case 98:		/* DFP Shift Significand Right Immediate */
+    case 322:		/* DFP Decode DPD To BCD */
+    case 354:		/* DFP Extract Biased Exponent */
+    case 866:		/* DFP Insert Biased Exponent */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_fp0_regnum + PPC_FRT (insn));
+      if (PPC_RC (insn))
+	record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum);
+      return 0;
+
+    case 846:		/* Floating Convert From Integer Doubleword Single */
+    case 974:		/* Floating Convert From Integer Doubleword Unsigned
+			   Single */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_fp0_regnum + PPC_FRT (insn));
+      if (PPC_RC (insn))
+	record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum);
+      record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum);
+
+      return 0;
+    }
+
+  fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record "
+		      "%08x at %08lx, 59-%d.\n", insn, addr, ext);
+  return -1;
+}
+
+/* Parse instructions of primary opcode-60.  */
+
+static int
+ppc64_process_record_op60 (struct gdbarch *gdbarch, struct regcache *regcache,
+			   CORE_ADDR addr, uint32_t insn)
+{
+  int ext = PPC_EXTOP (insn);
+
+  fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record "
+		      "%08x at %08lx, 60-%d.\n", insn, addr, ext);
+  return -1;
+}
+
+/* Parse instructions of primary opcode-63.  */
+
+static int
+ppc64_process_record_op63 (struct gdbarch *gdbarch, struct regcache *regcache,
+			   CORE_ADDR addr, uint32_t insn)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int ext = PPC_EXTOP (insn);
+  int tmp;
+
+  switch (ext & 0x1f)
+    {
+    case 18:		/* Floating Divide */
+    case 20:		/* Floating Subtract */
+    case 21:		/* Floating Add */
+    case 22:		/* Floating Square Root */
+    case 24:		/* Floating Reciprocal Estimate */
+    case 25:		/* Floating Multiply */
+    case 26:		/* Floating Reciprocal Square Root Estimate */
+    case 28:		/* Floating Multiply-Subtract */
+    case 29:		/* Floating Multiply-Add */
+    case 30:		/* Floating Negative Multiply-Subtract */
+    case 31:		/* Floating Negative Multiply-Add */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_fp0_regnum + PPC_FRT (insn));
+      if (PPC_RC (insn))
+	record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum);
+      record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum);
+      return 0;
+    }
+
+  switch (ext)
+    {
+    case 2:		/* DFP Add */
+    case 3:		/* DFP Quantize */
+    case 34:		/* DFP Multiply */
+    case 35:		/* DFP Reround */
+    case 67:		/* DFP Quantize Immediate */
+    case 99:		/* DFP Round To FP Integer With Inexact */
+    case 227:		/* DFP Round To FP Integer Without Inexact */
+    case 258:		/* DFP Convert To DFP Extended */
+    case 290:		/* DFP Convert To Fixed */
+    case 514:		/* DFP Subtract */
+    case 546:		/* DFP Divide */
+    case 770:		/* DFP Round To DFP Long */
+    case 802:		/* DFP Convert From Fixed */
+    case 834:		/* DFP Encode BCD To DPD */
+      tmp = (tdep->ppc_fp0_regnum + PPC_FRT (insn)) & ~1;
+      record_full_arch_list_add_reg (regcache, tmp);
+      record_full_arch_list_add_reg (regcache, tmp | 1);
+      /* FALL-THROUGH */
+    case 130:		/* DFP Compare Ordered */
+    case 162:		/* DFP Test Exponent */
+    case 194:		/* DFP Test Data Class */
+    case 226:		/* DFP Test Data Group */
+    case 642:		/* DFP Compare Unordered */
+    case 674:		/* DFP Test Significance */
+      if (PPC_RC (insn))
+	record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum);
+      record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum);
+      return 0;
+
+    case 66:		/* DFP Shift Significand Left Immediate */
+    case 98:		/* DFP Shift Significand Right Immediate */
+    case 322:		/* DFP Decode DPD To BCD */
+    case 354:		/* DFP Extract Biased Exponent */
+    case 866:		/* DFP Insert Biased Exponent */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_fp0_regnum + PPC_FRT (insn));
+      if (PPC_RC (insn))
+	record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum);
+      return 0;
+
+    case 12:		/* Floating Round to Single-Precision */
+    case 14:		/* Floating Convert To Integer Word */
+    case 15:		/* Floating Convert To Integer Word
+			   with round toward Zero */
+    case 142:		/* Floating Convert To Integer Word Unsigned */
+    case 143:		/* Floating Convert To Integer Word Unsigned
+			   with round toward Zero */
+    case 392:		/* Floating Round to Integer Nearest */
+    case 424:		/* Floating Round to Integer Toward Zero */
+    case 456:		/* Floating Round to Integer Plus */
+    case 488:		/* Floating Round to Integer Minus */
+    case 814:		/* Floating Convert To Integer Doubleword */
+    case 815:		/* Floating Convert To Integer Doubleword
+			   with round toward Zero */
+    case 846:		/* Floating Convert From Integer Doubleword */
+    case 942:		/* Floating Convert To Integer Doubleword Unsigned */
+    case 943:		/* Floating Convert To Integer Doubleword Unsigned
+			   with round toward Zero */
+    case 974:		/* Floating Convert From Integer Doubleword Unsigned */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_fp0_regnum + PPC_FRT (insn));
+      if (PPC_RC (insn))
+	record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum);
+      record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum);
+      return 0;
+
+    case 8:		/* Floating Copy Sign */
+    case 40:		/* Floating Negate */
+    case 72:		/* Floating Move Register */
+    case 136:		/* Floating Negative Absolute Value */
+    case 264:		/* Floating Absolute Value */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_fp0_regnum + PPC_FRT (insn));
+      if (PPC_RC (insn))
+	record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum);
+      return 0;
+
+    case 838:		/* Floating Merge Odd Word */
+    case 966:		/* Floating Merge Even Word */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_fp0_regnum + PPC_FRT (insn));
+      return 0;
+
+    case 0:		/* Floating Compare Unordered */
+    case 32:		/* Floating Compare Ordered */
+    case 38:		/* Move To FPSCR Bit 1 */
+    case 64:		/* Move to Condition Register from FPSCR */
+    case 70:		/* Move To FPSCR Bit 0 */
+    case 134:		/* Move To FPSCR Field Immediate */
+    case 711:		/* Move To FPSCR Fields */
+      record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum);
+      /* FALL-THROUGH */
+    case 23:		/* Floating Select */
+    case 128:		/* Floating Test for software Divide */
+    case 160:		/* Floating Test for software Square Root */
+    case 583:		/* Move From FPSCR */
+      record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum);
+      return 0;
+
+    }
+
+  fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record "
+		      "%08x at %08lx, 59-%d.\n", insn, addr, ext);
+  return -1;
+}
+
+/* Parse the current instruction and record the values of the registers and
+   memory that will be changed in current instruction to "record_arch_list".
+   Return -1 if something wrong.  */
+
+int
+ppc64_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
+		      CORE_ADDR addr)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  uint32_t insn;
+  int op6, tmp, i;
+
+  insn = read_memory_unsigned_integer (addr, 4, byte_order);
+  op6 = PPC_OP6 (insn);
+
+  switch (op6)
+    {
+    case 2:		/* Trap Doubleword Immediate */
+    case 3:		/* Trap Word Immediate */
+      /* Do nothing.  */
+      break;
+
+    case 4:
+      if (ppc64_process_record_op4 (gdbarch, regcache, addr, insn) != 0)
+	return -1;
+      break;
+
+    case 17:		/* System call */
+      if (tdep->syscall_record != NULL)
+	{
+	  if (tdep->syscall_record (regcache) != 0)
+	    return -1;
+	}
+      else
+	{
+	  printf_unfiltered (_("no syscall record support\n"));
+	  return -1;
+	}
+      break;
+
+    case 7:		/* Multiply Low Immediate */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_gp0_regnum + PPC_RT (insn));
+      break;
+
+    case 8:		/* Subtract From Immediate Carrying */
+      record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum);
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_gp0_regnum + PPC_RT (insn));
+      break;
+
+    case 10:		/* Compare Logical Immediate  */
+    case 11:		/* Compare Immediate */
+      record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum);
+      break;
+
+    case 13:		/* Add Immediate Carrying and Record */
+      record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum);
+      /* FALL-THROUGH */
+    case 12:		/* Add Immediate Carrying */
+      record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum);
+      /* FALL-THROUGH */
+    case 14:		/* Add Immediate */
+    case 15:		/* Add Immediate Shifted */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_gp0_regnum + PPC_RT (insn));
+      break;
+
+    case 16:		/* Branch Conditional */
+      if (PPC_BO (insn) & 0x2)
+	record_full_arch_list_add_reg (regcache, tdep->ppc_ctr_regnum);
+      /* FALL-THROUGH */
+    case 18:		/* Branch */
+      if (PPC_LK (insn))
+	record_full_arch_list_add_reg (regcache, tdep->ppc_lr_regnum);
+      break;
+
+    case 19:
+      if (ppc64_process_record_op19 (gdbarch, regcache, addr, insn) != 0)
+	return -1;
+      break;
+
+    case 20:		/* Rotate Left Word Immediate then Mask Insert */
+    case 21:		/* Rotate Left Word Immediate then AND with Mask */
+    case 23:		/* Rotate Left Word then AND with Mask */
+    case 30:		/* Rotate Left Doubleword Immediate then Clear Left */
+			/* Rotate Left Doubleword Immediate then Clear Right */
+			/* Rotate Left Doubleword Immediate then Clear */
+			/* Rotate Left Doubleword then Clear Left */
+			/* Rotate Left Doubleword then Clear Right */
+			/* Rotate Left Doubleword Immediate then Mask Insert */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_gp0_regnum + PPC_RA (insn));
+      record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum);
+      break;
+
+    case 24:		/* OR Immediate */
+    case 25:		/* OR Immediate Shifted */
+    case 26:		/* XOR Immediate */
+    case 27:		/* XOR Immediate Shifted */
+    case 28:		/* AND Immediate */
+    case 29:		/* AND Immediate Shifted */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_gp0_regnum + PPC_RA (insn));
+      break;
+
+    case 31:
+      if (ppc64_process_record_op31 (gdbarch, regcache, addr, insn) != 0)
+	return -1;
+      break;
+
+    case 33:		/* Load Word and Zero with Update */
+    case 35:		/* Load Byte and Zero with Update */
+    case 41:		/* Load Halfword and Zero with Update */
+    case 43:		/* Load Halfword Algebraic with Update */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_gp0_regnum + PPC_RA (insn));
+      /* FALL-THROUGH */
+    case 32:		/* Load Word and Zero */
+    case 34:		/* Load Byte and Zero */
+    case 40:		/* Load Halfword and Zero */
+    case 42:		/* Load Halfword Algebraic */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_gp0_regnum + PPC_RT (insn));
+      break;
+
+    case 46:		/* Load Multiple Word */
+      for (i = PPC_RT (insn); i < 32; i++)
+	record_full_arch_list_add_reg (regcache,
+				       tdep->ppc_gp0_regnum + PPC_RT (insn));
+      break;
+
+    case 56:		/* Load Quadword */
+      tmp = (tdep->ppc_gp0_regnum + PPC_RT (insn)) & ~1;
+      record_full_arch_list_add_reg (regcache, tmp);
+      record_full_arch_list_add_reg (regcache, tmp | 1);
+      break;
+
+    case 49:		/* Load Floating-Point Single with Update */
+    case 51:		/* Load Floating-Point Double with Update */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_gp0_regnum + PPC_RA (insn));
+      /* FALL-THROUGH */
+    case 48:		/* Load Floating-Point Single */
+    case 50:		/* Load Floating-Point Double */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_fp0_regnum + PPC_FRT (insn));
+      break;
+
+    case 47:		/* Store Multiple Word */
+	{
+	  ULONGEST addr = 0;
+	  int size;
+
+	  if (PPC_RA (insn) != 0)
+	    regcache_raw_read_unsigned (regcache,
+					tdep->ppc_gp0_regnum + PPC_RA (insn),
+					&addr);
+
+	  addr += PPC_D (insn);
+
+	  for (i = PPC_RS (insn); i < 32; i++)
+	    record_full_arch_list_add_mem (addr + i * 4, 4);
+	}
+      break;
+
+    case 37:		/* Store Word with Update */
+    case 39:		/* Store Byte with Update */
+    case 45:		/* Store Halfword with Update */
+    case 53:		/* Store Floating-Point Single with Update */
+    case 55:		/* Store Floating-Point Double with Update */
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_gp0_regnum + PPC_RA (insn));
+      /* FALL-THROUGH */
+    case 36:		/* Store Word */
+    case 38:		/* Store Byte */
+    case 44:		/* Store Halfword */
+    case 52:		/* Store Floating-Point Single */
+    case 54:		/* Store Floating-Point Double */
+	{
+	  ULONGEST addr = 0;
+	  int size = -1;
+
+	  if (PPC_RA (insn) != 0)
+	    regcache_raw_read_unsigned (regcache,
+					tdep->ppc_gp0_regnum + PPC_RA (insn),
+					&addr);
+	  addr += PPC_D (insn);
+
+	  if (op6 == 36 || op6 == 37 || op6 == 52 || op6 == 53)
+	    size = 4;
+	  else if (op6 == 54 || op6 == 55)
+	    size = 8;
+	  else if (op6 == 44 || op6 == 45)
+	    size = 2;
+	  else if (op6 == 38 || op6 == 39)
+	    size = 1;
+	  else
+	    gdb_assert (0);
+
+	  record_full_arch_list_add_mem (addr, size);
+	}
+      break;
+
+    case 57:		/* Load Floating-Point Double Pair */
+      tmp = (tdep->ppc_fp0_regnum + PPC_RT (insn)) & ~1;
+      record_full_arch_list_add_reg (regcache, tmp);
+      record_full_arch_list_add_reg (regcache, tmp | 1);
+      break;
+
+    case 58:		/* Load Doubleword */
+			/* Load Doubleword with Update */
+			/* Load Doubleword Algebraic */
+      if (PPC_FIELD (insn, 30, 2) > 2)
+	    goto UNKNOWN_OP;
+
+      record_full_arch_list_add_reg (regcache,
+				     tdep->ppc_gp0_regnum + PPC_RT (insn));
+      if (PPC_BIT (insn, 31))
+	record_full_arch_list_add_reg (regcache,
+				       tdep->ppc_gp0_regnum + PPC_RA (insn));
+      break;
+
+    case 59:
+      if (ppc64_process_record_op59 (gdbarch, regcache, addr, insn) != 0)
+	return -1;
+      break;
+
+    case 60:
+      if (ppc64_process_record_op60 (gdbarch, regcache, addr, insn) != 0)
+	return -1;
+      break;
+
+    case 61:		/* Store Floating-Point Double Pair */
+    case 62:		/* Store Doubleword */
+			/* Store Doubleword with Update */
+			/* Store Quadword with Update */
+	{
+	  ULONGEST addr = 0;
+	  int size;
+	  int sub2 = PPC_FIELD (insn, 30, 2);
+
+	  if ((op6 == 61 && sub2 != 0) || (op6 == 62 && sub2 > 2))
+	    goto UNKNOWN_OP;
+
+	  if (PPC_RA (insn) != 0)
+	    regcache_raw_read_unsigned (regcache,
+					tdep->ppc_gp0_regnum + PPC_RA (insn),
+					&addr);
+
+	  size = ((op6 == 61) || sub2 == 2) ? 16 : 8;
+
+	  addr += PPC_DS (insn) << 2;
+	  record_full_arch_list_add_mem (addr, size);
+
+	  if (op6 == 62 && sub2 == 1)
+	    record_full_arch_list_add_reg (regcache,
+					   tdep->ppc_gp0_regnum +
+					   PPC_RA (insn));
+
+	  break;
+	}
+
+    case 63:
+      if (ppc64_process_record_op63 (gdbarch, regcache, addr, insn) != 0)
+	return -1;
+      break;
+
+    default:
+UNKNOWN_OP:
+      fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record "
+			  "%08x at %08lx, %d.\n", insn, addr, op6);
+      return -1;
+    }
+
+  if (record_full_arch_list_add_reg (regcache, PPC_PC_REGNUM))
+    return -1;
+  if (record_full_arch_list_add_end ())
+    return -1;
+  return 0;
+}
+
  /* Initialize the current architecture based on INFO.  If possible, re-use an
     architecture from ARCHES, which is a list of architectures already created
     during this debugging session.
@@ -4154,6 +5660,7 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
      case GDB_OSABI_NETBSD_ELF:
      case GDB_OSABI_UNKNOWN:
        set_gdbarch_unwind_pc (gdbarch, rs6000_unwind_pc);
+      frame_unwind_append_unwinder (gdbarch, &rs6000_epilogue_frame_unwind);
        frame_unwind_append_unwinder (gdbarch, &rs6000_frame_unwind);
        set_gdbarch_dummy_id (gdbarch, rs6000_dummy_id);
        frame_base_append_sniffer (gdbarch, rs6000_frame_base_sniffer);
@@ -4162,6 +5669,7 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
        set_gdbarch_believe_pcc_promotion (gdbarch, 1);

        set_gdbarch_unwind_pc (gdbarch, rs6000_unwind_pc);
+      frame_unwind_append_unwinder (gdbarch, &rs6000_epilogue_frame_unwind);
        frame_unwind_append_unwinder (gdbarch, &rs6000_frame_unwind);
        set_gdbarch_dummy_id (gdbarch, rs6000_dummy_id);
        frame_base_append_sniffer (gdbarch, rs6000_frame_base_sniffer);
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 2c79bc1..77bd462 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -1881,7 +1881,8 @@ proc supports_process_record {} {
      }

      if { [istarget "arm*-*-linux*"] || [istarget "x86_64-*-linux*"]
-         || [istarget "i\[34567\]86-*-linux*"] } {
+         || [istarget "i\[34567\]86-*-linux*"]
+         || [istarget "powerpc*-linux*"] } {
  	return 1
      }

@@ -1897,7 +1898,8 @@ proc supports_reverse {} {
      }

      if { [istarget "arm*-*-linux*"] || [istarget "x86_64-*-linux*"]
-         || [istarget "i\[34567\]86-*-linux*"] } {
+         || [istarget "i\[34567\]86-*-linux*"]
+         || [istarget "powerpc*-linux*"] } {
  	return 1
      }

-- 

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] Process record support for PowerPC
  2014-11-18 16:27 [PATCH] Process record support for PowerPC Wei-cheng, Wang
@ 2014-11-28 12:15 ` Ulrich Weigand
  2014-12-06 17:57   ` [PATCH 0/3 v2] " Wei-cheng Wang
  0 siblings, 1 reply; 4+ messages in thread
From: Ulrich Weigand @ 2014-11-28 12:15 UTC (permalink / raw)
  To: Wei-cheng, Wang; +Cc: gdb-patches, dje.gcc, green

Wei-cheng Wang wrote:

> This patch is process record support for PowerPC

Very good, thanks for working on this!

> * Tested with Advance Toolchain 8.0 ppc64 - 2326 pass, no fail

Excellent!   Some suggestions for additional testing:
  - 32-bit mode (test using -m32) -- it seems some of your Linux-specific
    code may not work correctly in 32-bit mode
  - Different ISA levels (test using -mcpu=power8/power7/...) to exercise
    different instructions

> * 26 fails if tested with ppc64le, due to local entry optimization.
>    Breakpoints set on the very beginning of functions may
>    not be hit when reverse-continue.

I see.  There is this block in infrun.c:process_event_stop_test

      if (execution_direction == EXEC_REVERSE)
        {
          /* If we're already at the start of the function, we've either just
             stepped backward into a single instruction function without line
             number info, or stepped back out of a signal handler to the first
             instruction of the function without line number info.  Just keep
             going, which will single-step back to the caller.  */
          if (ecs->stop_func_start != stop_pc)
            {
              /* Set a breakpoint at callee's start address.
                 From there we can step once and be back in the caller.  */
              struct symtab_and_line sr_sal;

              init_sal (&sr_sal);
              sr_sal.pc = ecs->stop_func_start;
              sr_sal.pspace = get_frame_program_space (frame);
              insert_step_resume_breakpoint_at_sal (gdbarch,
                                                    sr_sal, null_frame_id);
            }
        }

which doesn't correctly handle multiple entry points.  ecs->stop_func_start
is already the local entry point (see fill_in_stop_func), so code should
already continue backwards until then.  However, code elsewhere in infrun.c
assumes that once this breakpoint is hit, we need just a single further step
to arrive back at the caller.  If we actually go through a global entry point
prologue, we may have to step multiple times.

This can certainly be fixed as a follow-on patch.

> * Support reverse-step over subroutine without debug info
> * Record/reverse syscall/signal
> * Support reverse-step through solib trampoline
> 
> And these instructions are handled
> * All main opcode
> * opcode 31
> -- Privileged instructions are listed, but not handled.
>     Shoule I just remote them?

Yes, it doesn't make much sense to list (some of) them.  See also below.

> * opcode 59 and 63 (Decimal Floating-Point and Floating-point)
> * opcode 4 (Only [vector] instructions are handled.)
> * opcode 19 (Only conditional and branch instruction.)
> 
> SPE, Embedded, LMA, VSX and privileged instructions are not handled.

The only one of those that would be of interest (on current server
platforms) would be VSX.  I see that you're actually already supporting
many VSX instructions, in particular loads and stores.  The one missing
piece is opcode 60.  It would be great if you could add that to complete
VSX support ... but this is not a requirement to get this patch approved,
we can always add it later.

Note that the patch seems to be missing ChangeLog entries.

Some detailed review comments follow.


> diff --git a/gdb/ppc-tdep.h b/gdb/ppc-tdep.h
> index 08554ff..437ca8c 100644
> --- a/gdb/ppc-tdep.h
> +++ b/gdb/ppc-tdep.h
> @@ -259,6 +259,8 @@ struct gdbarch_tdep
>       /* ISA-specific types.  */
>       struct type *ppc_builtin_type_vec64;
>       struct type *ppc_builtin_type_vec128;
> +
> +    int (* syscall_record) (struct regcache *regcache);
No space after the '*'.  Also, for better searchability,
the field should probably be named ppc_syscall_record.

>+extern int ppc64_process_record (struct gdbarch *gdbarch,
>+                                struct regcache *regcache, CORE_ADDR addr);
A note on naming: there doesn't really seem to be anything 64-bit specific 
in ppc64_process_record or its subroutines.  The usual naming convention
would then be to use ppc_process_record.


> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index 2c79bc1..77bd462 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -1881,7 +1881,8 @@ proc supports_process_record {} {
>       }
> 
>       if { [istarget "arm*-*-linux*"] || [istarget "x86_64-*-linux*"]
> -         || [istarget "i\[34567\]86-*-linux*"] } {
> +         || [istarget "i\[34567\]86-*-linux*"]
> +         || [istarget "powerpc*-linux*"] } {
Should be powerpc*-*-linux*

> @@ -1897,7 +1898,8 @@ proc supports_reverse {} {
>       }
> 
>       if { [istarget "arm*-*-linux*"] || [istarget "x86_64-*-linux*"]
> -         || [istarget "i\[34567\]86-*-linux*"] } {
> +         || [istarget "i\[34567\]86-*-linux*"]
> +         || [istarget "powerpc*-linux*"] } {
Likewise.


> diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c
> index a997869..608081c 100644
> --- a/gdb/ppc-linux-tdep.c
> +++ b/gdb/ppc-linux-tdep.c
> @@ -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"
What is this (infrun.h) needed for?


> @@ -298,6 +301,23 @@ powerpc_linux_in_dynsym_resolve_code (CORE_ADDR pc)
>   	  || strcmp (MSYMBOL_LINKAGE_NAME (sym.minsym),
>   		     "__glink_PLTresolve") == 0))
>       return 1;
> +  else if (sym.minsym != NULL && execution_direction == EXEC_REVERSE)
> +    {
> +      /* When reverse stepping, gdb needs to know whether PC lies in
> +	 the dynamic symbol resolve code, so it can keep going until
> +	 reaching some user code.
> +	 Using insns-match-pattern is not suitable, because we had to
> +	 look both ahead and behind to check where we are in the middle
> +	 of one of trampline sequences.  */
> +#define SUBSTRCMP(sym, stub)  (memcmp (sym + 8, stub, sizeof (stub) - 1) == 0)
> +      if (SUBSTRCMP (MSYMBOL_LINKAGE_NAME (sym.minsym), ".plt_call."))
> +	return 1;
> +      if (SUBSTRCMP (MSYMBOL_LINKAGE_NAME (sym.minsym), ".plt_branch."))
> +	return 1;
> +      if (SUBSTRCMP (MSYMBOL_LINKAGE_NAME (sym.minsym), ".plt_branch_r2off."))
> +	return 1;
> +#undef SUBSTRCMP

Huh.  The "sym + 8" seems odd.  What if symbol name is shorter than 8 bytes?

Also, those stub symbols are not guaranteed to be present.

Can't we generalize the skip_trampoline_code so that it also accepts
a PC in the middle of the sequence?  That would seem a more general
solution.

> @@ -1345,6 +1524,15 @@ ppc_linux_init_abi (struct gdbarch_info info,
>         set_solib_svr4_fetch_link_map_offsets
>           (gdbarch, svr4_lp64_fetch_link_map_offsets);
> 
> +      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);
> +

If we actually need this, we shouldn't copy this part in both the
wordsize == 4 and wordsize == 8 paths, but just have it once.

Also, this part should probably be broken out into a separate patch.


> +/* PPC process record-replay */
> +
> +struct linux_record_tdep ppc_linux_record_tdep;
> +
> +static enum gdb_syscall
> +ppc_canonicalize_syscall (int syscall)
> +{
> +  /* See arch/powerpc/include/uapi/asm/unistd.h */
> +
> +  if (syscall <= 165)
> +    return syscall;
> +  else if (syscall >= 167 && syscall <= 190)	/* Skip query_module 166 */
> +    return syscall + 1;
> +  else if (syscall >= 192 && syscall <= 197)	/* mmap2 */
> +    return syscall;
> +  else if (syscall == 208)			/* tkill */
> +    return gdb_sys_tkill;
> +  else if (syscall >= 207 && syscall <= 220)	/* gettid */
> +    return syscall + 224 - 207;
> +  else if (syscall >= 234 && syscall <= 239)	/* exit_group */
> +    return syscall + 252 - 234;
> +  else if (syscall >= 240 && syscall <=248)	/* timer_create */
> +    return syscall += 259 - 240;
> +  else if (syscall >= 250 && syscall <=251)	/* tgkill */
> +    return syscall + 270 - 250;
> +  else if (syscall == 336)
> +    return gdb_sys_recv;
> +  else if (syscall == 337)
> +    return gdb_sys_recvfrom;
> +  else if (syscall == 342)
> +    return gdb_sys_recvmsg;

This seems a somewhat partial mapping; I guess that's good enough for now.
Longer term, we may want to look into automatically generating the mapping;
we also have another list of platform syscalls in the syscalls/ directory ...


> +/* Record all registers but PC register for process-record.  */
> +
> +static int
> +ppc_all_but_pc_registers_record (struct regcache *regcache)
> +{
> +  struct gdbarch *gdbarch = get_regcache_arch (regcache);
> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> +  int i;
> +
> +  for (i = 0; i < 32; 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_cr_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_ctr_regnum))
> +    return -1;

This of course doen't actually record *all* registers, just the general
purpose ones.  Depending on the usage, this may or may not be appropriate.


> +static int
> +ppc_linux_syscall_record (struct regcache *regcache)
> +{
> +  struct gdbarch *gdbarch = get_regcache_arch (regcache);
> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> +  ULONGEST scnum;
> +  enum gdb_syscall syscall_gdb;
> +  int ret;
> +
> +  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)
> +   {
> +     if (ppc_all_but_pc_registers_record (regcache))
> +       return -1;

For example, here, we might actually have to record *all* registers, since
a sigreturn syscall will in fact reload not just the GPRs, but also float
and vector registers.


> +static int
> +ppc64_linux_record_signal (struct gdbarch *gdbarch,
> +                           struct regcache *regcache,
> +                           enum gdb_signal signal)
> +{
> +  /* See arch/powerpc/kernel/signal_64.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;

This is too big for 32-bit, but that may not matter.  (See also below.)

> +  ULONGEST sp;
> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> +
> +  if (ppc_all_but_pc_registers_record (regcache))
> +    return -1;

I'm not sure why we need this here; signal delivery does not actually change
all registers, it only changes those affected by a function call (possibly
0, 11, 12, some argument registers, LR, CTR, SP).

> +  if (record_full_arch_list_add_reg (regcache, gdbarch_pc_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;

I see x86 does this too, but I wonder why.  All this memory is in fact
uninitialized before the signal, so what's the point of tracking its original
contents?


> +  /* Support reverse debugging.  */
> +  set_gdbarch_process_record (gdbarch, ppc64_process_record);
> +  set_gdbarch_process_record_signal (gdbarch, ppc64_linux_record_signal);
> +  tdep->syscall_record = ppc_linux_syscall_record;

At this place in ppc_linux_init_abi, we are handling *both* 32-bit and
64-bit code.  This means the callbacks installed here should handle
both bitsizes.  That seems OK for ppc64_process_record, but probably
not for ppc64_linux_record_signal and ppc_linux_syscall_record (in
their current implementation).

> +  /* Initialize the ppc_linux_record_tdep.  */
> +  /* These values are the size of the type that will be used in a system
> +     call.  They are obtained from Linux Kernel source.
> +
> +     See arch/powerpc/include/uapi/asm/ioctls.h.  */
> +  ppc_linux_record_tdep.size_pointer
> +    = gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT;

This is problematic.  There is only one single instance of
ppc_linux_record_tdep, so when this code is called for 32-bit
and then for 64-bit, that single instance gets overwritten.
I think we really need two copies of the structure, and
install the one appropriate for the current bitsize.

Note that many of the hard-coded "size" values in your
patch are only correct for 64-bit, so the 32-bit copy
of the struct would have to use different values.
(The non-"size" values should be OK for both.)

> +  ppc_linux_record_tdep.size_old_gid_t = 2;
> +  ppc_linux_record_tdep.size_old_uid_t = 2;
These should be 4 on PowerPC (never used short).

> +  ppc_linux_record_tdep.size_stat64 = 144;
This is 104 on PowerPC (different padding).

> +  ppc_linux_record_tdep.size_PAGE_SIZE = 4096;
This is a bit of a problem.  The PowerPC kernel can be compiled
with either 4k or 64k page size.  We could either try to detect
at runtime (from auxv) or always use the conservative 64k.

> +  ppc_linux_record_tdep.size_user_desc = 16;
PowerPC doesn't have this system call at all.

> +  ppc_linux_record_tdep.size_epoll_event = 12;
This is 16 on PowerPC (due to different packing).

> +  ppc_linux_record_tdep.size_termios = 60;
> +  ppc_linux_record_tdep.size_termios2 = 44;
PowerPC doesn't have termios2, and the size of termios is 44.

> +  /* These values are the second argument of system call "sys_ioctl".
> +     They are obtained from Linux Kernel source.  */
Many of these are different on PowerPC, see the private file
arch/powerpc/include/uapi/asm/ioctls.h vs. the generic one
include/uapi/asm-generic/ioctls.h.

> +  ppc_linux_record_tdep.ioctl_TCGETS = 0x5401;
> +  ppc_linux_record_tdep.ioctl_TCSETS = 0x5402;
> +  ppc_linux_record_tdep.ioctl_TCSETSW = 0x5403;
> +  ppc_linux_record_tdep.ioctl_TCSETSF = 0x5404;
> +  ppc_linux_record_tdep.ioctl_TCGETA = 0x5405;
> +  ppc_linux_record_tdep.ioctl_TCSETA = 0x5406;
> +  ppc_linux_record_tdep.ioctl_TCSETAW = 0x5407;
> +  ppc_linux_record_tdep.ioctl_TCSETAF = 0x5408;
> +  ppc_linux_record_tdep.ioctl_TCSBRK = 0x5409;
> +  ppc_linux_record_tdep.ioctl_TCXONC = 0x540A;
> +  ppc_linux_record_tdep.ioctl_TCFLSH = 0x540B;
ioctl_TCGETS = 0x402C7413
ioctl_TCSETS = 0x802C7414
ioctl_TCSETSW = 0x802C7415
ioctl_TCSETSF = 0x802C7416
ioctl_TCGETA = 0x40147417
ioctl_TCSETA = 0x80147418
ioctl_TCSETAW = 0x80147419
ioctl_TCSETAF = 0x8014741C
ioctl_TCSBRK = 0x2000741D
ioctl_TCXONC = 0x2000741E
ioctl_TCFLSH = 0x2000741F

> +  ppc_linux_record_tdep.ioctl_TIOCGPGRP = 0x540F;
> +  ppc_linux_record_tdep.ioctl_TIOCSPGRP = 0x5410;
> +  ppc_linux_record_tdep.ioctl_TIOCOUTQ = 0x5411;
ioctl_TIOCGPGRP = 0x40047477
ioctl_TIOCSPGRP = 0x80047476
ioctl_TIOCOUTQ = 0x40047473

> +  ppc_linux_record_tdep.ioctl_TIOCGWINSZ = 0x5413;
> +  ppc_linux_record_tdep.ioctl_TIOCSWINSZ = 0x5414;
ioctl_TIOCGWINSZ = 0x40087468
ioctl_TIOCSWINSZ = 0x80087467

> +  ppc_linux_record_tdep.ioctl_FIONREAD = 0x541B;
ioctl_FIONREAD = 0x4004667F

> +  ppc_linux_record_tdep.ioctl_FIONBIO = 0x5421;
ioctl_FIONBIO = 0x8004667E

> +  ppc_linux_record_tdep.ioctl_TCGETS2 = 0x802c542a;
> +  ppc_linux_record_tdep.ioctl_TCSETS2 = 0x402c542b;
> +  ppc_linux_record_tdep.ioctl_TCSETSW2 = 0x402c542c;
> +  ppc_linux_record_tdep.ioctl_TCSETSF2 = 0x402c542d;
These don't exist at all; PowerPC has no termios2.

> +  ppc_linux_record_tdep.ioctl_TIOCGPTN = 0x80045430;
> +  ppc_linux_record_tdep.ioctl_TIOCSPTLCK = 0x40045431;
> +  ppc_linux_record_tdep.ioctl_FIONCLEX = 0x5450;
> +  ppc_linux_record_tdep.ioctl_FIOCLEX = 0x5451;
> +  ppc_linux_record_tdep.ioctl_FIOASYNC = 0x5452;
ioctl_TIOCGPTN = 0x40045430
ioctl_TIOCSPTLCK = 0x80045431
ioctl_FIONCLEX = 0x20006602
ioctl_FIOCLEX = 0x20006601
ioctl_FIOASYNC = 0x8004667D

> +  ppc_linux_record_tdep.ioctl_FIOQSIZE = 0x5460;
ioctl_FIOQSIZE = 0x40086680



> +static const struct frame_unwind rs6000_epilogue_frame_unwind =
> +{
> +  NORMAL_FRAME,
> +  default_frame_unwind_stop_reason,
> +  rs6000_epilogue_frame_this_id, rs6000_epilogue_frame_prev_register,
> +  NULL,
> +  rs6000_epilogue_frame_sniffer
> +};

Is this actually still necessary with a current compiler that tracks
epilogues in DWARF?   In any case, it would be better to provide this
in a separate patch.


> +#define PPC_BF(insn)	PPC_FIELD (insn, 6, 3)
This seems unused.


> +static int
> +ppc_record_vsr (struct regcache *regcache, struct gdbarch_tdep *tdep, int vsr,
> +		int size)
> +{
> +  if (vsr < 0 || vsr >= 64)
> +    return -1;
> +
> +  if (vsr >= 32)
> +    {
> +      if (tdep->ppc_vr0_regnum >= 0)
> +	record_full_arch_list_add_reg (regcache, tdep->ppc_vr0_regnum + vsr);
Should be vsr - 32 here.

> +  else
> +    {
> +      if (tdep->ppc_fp0_regnum >= 0)
> +	record_full_arch_list_add_reg (regcache, tdep->ppc_fp0_regnum + vsr);
> +      if (size > 8 && tdep->ppc_vsr0_upper_regnum >= 0)
We don't really need the size check; see below.
> +	record_full_arch_list_add_reg (regcache,
> +				       tdep->ppc_vsr0_upper_regnum + vsr);


> +/* Parse instructions of primary opcode-4.  */
> +
> +static int
> +ppc64_process_record_op4 (struct gdbarch *gdbarch, struct regcache *regcache,
> +			   CORE_ADDR addr, uint32_t insn)
> +{

> +    case 786:		/* Vector Add Signed Byte Saturate */
Typo: should be 768
> +    case 940:		/* Vector Multiply Even Signed Word */
Typo: should be 904
> +    case 864:		/* Vector Shift Right Algebraic Doubleword */
Typo: should be 964

> +    case 32:		/* Vector Multiply-High-Add Signed Halfword Saturate */
> +    case 33:		/* Vector Multiply-High-Round-Add Signed Halfword Saturate */
> +    case 39:		/* Vector Multiply-Sum Unsigned Halfword Saturate */
> +    case 41:		/* Vector Multiply-Sum Signed Halfword Saturate */
> +    case 42:		/* Vector Select */
> +    case 43:		/* Vector Permute */
> +    case 44:		/* Vector Shift Left Double by Octet Immediate */
> +    case 60:		/* Vector Add Extended Unsigned Quadword Modulo */
> +    case 61:		/* Vector Add Extended & write Carry Unsigned Quadword */
> +    case 62:		/* Vector Subtract Extended Unsigned Quadword Modulo */
> +    case 63:		/* Vector Subtract Extended & write Carry Unsigned Quadword */
> +    case 34:		/* Vector Multiply-Low-Add Unsigned Halfword Modulo */
> +    case 36:		/* Vector Multiply-Sum Unsigned Byte Modulo */
> +    case 37:		/* Vector Multiply-Sum Mixed Byte Modulo */
> +    case 38:		/* Vector Multiply-Sum Unsigned Halfword Modulo */
> +    case 40:		/* Vector Multiply-Sum Signed Halfword Modulo */
> +    case 46:		/* Vector Multiply-Add Single-Precision */
> +    case 47:		/* Vector Negative Multiply-Subtract Single-Precision */
All of those use a VRC field, and therefore need to be treated like the case 45
at the beginning of this function!

> +			/* 5.16 Decimal Integer Arithmetic Instructions */
Headline superfluous at this point.


> +static int
> +ppc64_process_record_op19 (struct gdbarch *gdbarch, struct regcache *regcache,
> +			   CORE_ADDR addr, uint32_t insn)
> +{

> +    case 16:		/* Branch Conditional */
> +    case 560:		/* Branch Conditional to Branch Target Address Register */
> +      if (PPC_BO (insn) & 0x2)
> +	record_full_arch_list_add_reg (regcache, tdep->ppc_ctr_regnum);
This should be "if ((PPC_BO (insn) & 0x4) == 0)".  BO_2 is the bit with
value 4 in BO, and the instruction decrements CRT if BO_2 is *clear*.


> +static int
> +ppc64_process_record_op31 (struct gdbarch *gdbarch, struct regcache *regcache,
> +			   CORE_ADDR addr, uint32_t insn)
> +{

> +  CORE_ADDR at_dcsz, at_icsz, ea = 0;
at_icsz is unused?

> +  switch (ext)
> +    {
> +    case 78:		/* Determine Leftmost Zero Byte */
> +      /* CA is always altered, but SO/OV are only altered when OE=1.
> +	 In any case, XER is always altered.  */
The comment is wrong, there's no OE bit here.  Code is correct.

> +    case 339:          /* Move From Special Purpose Register */
Maybe add case 371 Move From Time Base here.  The instruction is
phased out, but potentially still used in some code.

> +    /* These write CR and optional RA.  */
> +    case 792:		/* Shift Right Algebraic Word */
> +    case 794:		/* Shift Right Algebraic Doubleword */
> +    case 824:		/* Shift Right Algebraic Word Immediate */
> +    case 826:		/* Shift Right Algebraic Doubleword Immediate (413) */
> +    case 826 | 1:	/* Shift Right Algebraic Doubleword Immediate (413) */
All of these also write CA (i.e. XER).

> +    case 853:		/* Load Byte and Zero Caching Inhibited Indexed */
> +    case 821:		/* Load Halfword and Zero Caching Inhibited Indexed */
> +    case 789:		/* Load Word and Zero Caching Inhibited Indexed */
> +    case 885:		/* Load Doubleword Caching Inhibited Indexed */
These are (hypervisor) privileged, so we don't really need to support them here.

> +    case 597:		/* Load String Word Immediate */
> +    case 533:		/* Load String Word Indexed */
> +      if (ext == 597)
> +	nr = PPC_NB (insn);
I guess this needs a "if (nr == 0) nr = 32" or similar here.
> +      else
> +	{
> +	  regcache_raw_read_unsigned (regcache, tdep->ppc_xer_regnum, &xer);
> +	  nr = PPC_XER_NB (xer);
If nr is zero here, the architecture says that RT is undefined, so we probably
should set nr to one in that case.
> +	}

> +    case 276:		/* Load Quadword And Reserve Indexed */
> +      tmp = (tdep->ppc_gp0_regnum + PPC_RT (insn)) & ~1;
Probably better to apply the & ~1 to PPC_RT (insn) ...
> +      record_full_arch_list_add_reg (regcache, tmp);
> +      record_full_arch_list_add_reg (regcache, tmp | 1);
... and use +1 here.  Otherwise you require that tdep->ppc_gp0_regnum
is even, which is currently true but not necessarily guaranteed.

> +    case 791:		/* Load Floating-Point Double Pair Indexed */
> +      tmp = (tdep->ppc_fp0_regnum + PPC_FRT (insn)) & ~1;
Likewise.
> +      record_full_arch_list_add_reg (regcache, tmp);
> +      record_full_arch_list_add_reg (regcache, tmp | 1);

> +    /* These write VSR of size 8.  */
> +    case 588:		/* Load VSX Scalar Doubleword Indexed */
> +      ppc_record_vsr (regcache, tdep, PPC_XT (insn), 8);
Note that the contents of the other doubleword element are undefined
after this instruction, so you need to save all of it, i.e. size == 16.
In fact, we probably don't even need the size argument then.

> +    /* Store memory.  */

> +    case 981:          /* Store Byte Caching Inhibited Indexed */
> +    case 949:          /* Store Halfword Caching Inhibited Indexed */
> +    case 917:          /* Store Word Caching Inhibited Indexed */
> +    case 1013:         /* Store Doubleword Caching Inhibited Indexed */
These are (hypervisor) privileged, so we don't really need to support them here.

> +       case 247:       /* Store Byte with Update Indexed */
> +       case 135:       /* Store Vector Element Byte Indexed */
> +       case 215:       /* Store Byte Indexed */
> +       case 694:       /* Store Byte Conditional Indexed */
> +       case 662:       /* Store Word Byte-Reverse Indexed */
> The above is wrong, it should have size 4.
> +       case 981:       /* Store Byte Caching Inhibited Indexed */
> +         size = 1;
> +         break;

> +       case 181:       /* Store Doubleword with Update Indexed */
> +       case 716:       /* Store VSX Scalar Doubleword Indexed */
> +       case 149:       /* Store Doubleword Indexed */
> +       case 214:       /* Store Doubleword Conditional Indexed */
> +       case 660:       /* Store Doubleword Byte-Reverse Indexed */
> +       case 1013:      /* Store Doubleword Caching Inhibited Indexed */
Missing cases for size 8: 727 and 759 (store floating-point double).
> +         size = 8;
> +         break;

> +      /* Align address for Store Vector instructions.  */
> +      if ((ext & 0x1f) == 0x7)
> +	{
> +	  if ((ext & 0x3) < 3)
This seems incorrect.  If (ext & 0x1f) == 0x7, then this check is never true.
There's just a few store vector instructions; maybe just making it a switch
would be more straightforward ...
> +	    addr = (addr >> (ext & 0x3)) << (ext & 0x3);
> +	  else
> +	    addr = addr & ~0x7ULL;
> +	}

> +    case 725:		/* Store String Word Immediate */
> +    case 661:		/* Store String Word Indexed */
> +      ra = 0;
> +      if (PPC_RA (insn) != 0)
> +	regcache_raw_read_unsigned (regcache, tdep->ppc_xer_regnum, &ra);
> +      ea += ra;
> +
> +      if (ext == 725)
> +	nb = PPC_NB (insn);
I guess this needs a "if (nr == 0) nr = 32" or similar here.
> +      else
> +	{
> +	  regcache_raw_read_unsigned (regcache, tdep->ppc_xer_regnum, &xer);
> +	  nb = PPC_XER_NB (xer);
Do we have to handle the nb == 0 case specially?  Doesn't write memory.
> +
> +	  regcache_raw_read_unsigned (regcache, tdep->ppc_xer_regnum, &rb);
> +	  ea += rb;
> +	}

> +    case 467:		/* Move To Special Purpose Register */
> +      switch (PPC_SPR (insn))
> +	{
> +	case 1:			/* XER */
> +	  record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum);
> +	  return 0;
> +	case 8:			/* LR */
> +	  record_full_arch_list_add_reg (regcache, tdep->ppc_lr_regnum);
> +	  return 0;
> +	case 9:			/* CTR */
> +	  record_full_arch_list_add_reg (regcache, tdep->ppc_ctr_regnum);
> +	  return 0;
We should also at least support VRSAVE (256).

> +    case 18:		/* TLB Invalidate Local Indexed */
> +    case 326:		/* Data Cache Read */
> +    case 63:		/* Data Cache Block Store by External PID */
> +    case 127:		/* Data Cache Block Flush by External PID */
> +    case 134:		/* Data Cache Block Touch for Store and Lock Set */
> +    case 166:		/* Data Cache Block Touch and Lock Set */
> +    case 255:		/* Data Cache Block Touch for Store by External PID */
> +    case 319:		/* Data Cache Block Touch by External PID */
> +    case 390:		/* Data Cache Block Lock Clear */
> +    case 422:		/* Data Cache Block Lock Query */
> +    case 454:		/* Data Cache Invalidate */
> +    case 998:		/* Instruction Cache Read */
> +    case 966:		/* Instruction Cache Invalidate */
> +    case 982:		/* Instruction Cache Block Invalidate */
This is actually not privileged; it should just be ignored.
> +    case 198:		/* Instruction Cache Block Lock Query */
> +    case 230:		/* Instruction Cache Block Lock Clear */
> +    case 486:		/* Instruction Cache Block Touch and Lock Set */
> +    case 206:		/* Message Send */
> +    case 238:		/* Message Clear */
> +    case 142:		/* Message Send Privileged */
> +    case 174:		/* Message Clear Privileged */
> +    case 131:		/* Write MSR External Enable */
> +    case 163:		/* Write MSR External Enable Immediate */
> +    case 270:		/* Embedded Hypervisor Privilege */
> +    case 462:		/* Move To Performance Monitor Register */
This is not (generally) privileged; it's embedded only, but you already support
the "From" variant above ...
> +    case 494:		/* Move To Thread Management Register */
> +    case 807:		/* Store Vector by External Process ID Indexed */
> +    case 775:		/* Store Vector by External Process ID Indexed LRU */
> +    case 95:		/* Load Byte by External Process ID Indexed */
> +    case 287:		/* Load Halfword by External Process ID Indexed */
> +    case 31:		/* Load Word by External Process ID Indexed */
> +    case 29:		/* Load Doubleword by External Process ID Indexed */
> +    case 295:		/* Load Vector by External Process ID Indexed */
> +    case 263:		/* Load Vector by External Process ID Indexed LRU */
> +    case 259:		/* Move From Device Control Register Indexed */
> +    case 323:		/* Move From Device Control Register */
> +    case 146:		/* Move To Machine State Register */
> +    case 178:		/* Move To Machine State Register Doubleword */
> +    case 387:		/* Move To Device Control Register Indexed */
> +    case 419:		/* Move To Device Control Register User-mode Indexed */
> +    case 291:		/* Move From Device Control Register User-mode Indexed */
The two instructions above are in fact unprivileged.  But they are embedded-only,
so I guess it would be OK to not support them (but the error shouldn't say "privileged").
> +    case 451:		/* Move To Device Control Register */
> +      /* Privileged instructions.  */
> +      fprintf_unfiltered (gdb_stdlog, "Cannot record privileged instructions. "
> +			  "%08x at %08lx, 31-%d.\n", insn, addr, ext);
In general, I don't think this error makes much sense -- the list above does
not even contain all op31 privileged instructions, and we don't have any handling
for non-op31 privileged instructions.  It would probably be better to drop the
specical handling here, and just use the generic error message.

> +    case 654:		/* Transaction Begin */
> +    case 686:		/* Transaction End */
> +    case 718:		/* Transaction Check */
> +    case 750:		/* Transaction Suspend or Resume */
> +    case 782:		/* Transaction Abort Word Conditional */
> +    case 814:		/* Transaction Abort Doubleword Conditional */
> +    case 846:		/* Transaction Abort Word Conditional Immediate */
> +    case 878:		/* Transaction Abort Doubleword Conditional Immediate */
> +    case 910:		/* Transaction Abort */
> +    case 942:		/* Transaction Reclaim */
> +    case 1006:		/* Transaction Recheckpoint */
> +      fprintf_unfiltered (gdb_stdlog, "Cannot record Transaction instructions. "
> +			  "%08x at %08lx, 31-%d.\n", insn, addr, ext);
This seems OK, though.  Transactional instructions can occur, and we certainly cannot
handle them, and it is good to inform the user about that.  (Maybe not the last two,
those are privileged.)

> +static int
> +ppc64_process_record_op60 (struct gdbarch *gdbarch, struct regcache *regcache,
> +                          CORE_ADDR addr, uint32_t insn)
> +{
> +  int ext = PPC_EXTOP (insn);
> +
> +  fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record "
> +                     "%08x at %08lx, 60-%d.\n", insn, addr, ext);
Since those may actually occur (frequently) in user code, we should probably
reword the message to something along the lines of "VSX instructions not
yet supported".  (Or simply implement them :-))


> +ppc64_process_record_op63 (struct gdbarch *gdbarch, struct regcache *regcache,
> +			   CORE_ADDR addr, uint32_t insn)
> +{

> +    case 290:		/* DFP Convert To Fixed */
This only writes a single register FPT, not a pair.

> +      tmp = (tdep->ppc_fp0_regnum + PPC_FRT (insn)) & ~1;
Probably better to apply the & ~1 to PPC_RT (insn) ...
> +      record_full_arch_list_add_reg (regcache, tmp);
> +      record_full_arch_list_add_reg (regcache, tmp | 1);
... and use +1 here.  Otherwise you require that tdep->ppc_fp0_regnum
is even, which is currently true but not necessarily guaranteed.

> +    case 66:		/* DFP Shift Significand Left Immediate */
> +    case 98:		/* DFP Shift Significand Right Immediate */
> +    case 322:		/* DFP Decode DPD To BCD */
> +    case 866:		/* DFP Insert Biased Exponent */
But these four write a register pair, not just a single register.

> +    case 38:		/* Move To FPSCR Bit 1 */
> +    case 70:		/* Move To FPSCR Bit 0 */
> +    case 134:		/* Move To FPSCR Field Immediate */
> +    case 711:		/* Move To FPSCR Fields */
These four only write to CR if RC is set.

> +    case 23:		/* Floating Select */
> +    case 583:		/* Move From FPSCR */
These two write to FRT.


> +int
> +ppc64_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
> +		      CORE_ADDR addr)
> +{

> +    case 17:		/* System call */
Should we verify that the LEV field is zero here?

> +    case 16:		/* Branch Conditional */
> +      if (PPC_BO (insn) & 0x2)
> +	record_full_arch_list_add_reg (regcache, tdep->ppc_ctr_regnum);
This should be "if ((PPC_BO (insn) & 0x4) == 0)".  BO_2 is the bit with
value 4 in BO, and the instruction decrements CRT if BO_2 is *clear*.

> +    case 20:		/* Rotate Left Word Immediate then Mask Insert */
> +    case 21:		/* Rotate Left Word Immediate then AND with Mask */
> +    case 23:		/* Rotate Left Word then AND with Mask */
> +    case 30:		/* Rotate Left Doubleword Immediate then Clear Left */
> +			/* Rotate Left Doubleword Immediate then Clear Right */
> +			/* Rotate Left Doubleword Immediate then Clear */
> +			/* Rotate Left Doubleword then Clear Left */
> +			/* Rotate Left Doubleword then Clear Right */
> +			/* Rotate Left Doubleword Immediate then Mask Insert */
> +      record_full_arch_list_add_reg (regcache,
> +				     tdep->ppc_gp0_regnum + PPC_RA (insn));
> +      record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum);
CR changes only if PPC_RC (insn) is set.

> +    case 24:		/* OR Immediate */
> +    case 25:		/* OR Immediate Shifted */
> +    case 26:		/* XOR Immediate */
> +    case 27:		/* XOR Immediate Shifted */
> +    case 28:		/* AND Immediate */
> +    case 29:		/* AND Immediate Shifted */
> +      record_full_arch_list_add_reg (regcache,
> +				     tdep->ppc_gp0_regnum + PPC_RA (insn));
Cases 28/29 (only) also change CR.

> +    case 46:		/* Load Multiple Word */
> +      for (i = PPC_RT (insn); i < 32; i++)
> +	record_full_arch_list_add_reg (regcache,
> +				       tdep->ppc_gp0_regnum + PPC_RT (insn));
Should be "tdep->ppc_gp0_regnum + i", I guess.

> +    case 56:		/* Load Quadword */
Should check that the last two bits are zero.

> +      tmp = (tdep->ppc_gp0_regnum + PPC_RT (insn)) & ~1;
Probably better to apply the & ~1 to PPC_RT (insn) ...
> +      record_full_arch_list_add_reg (regcache, tmp);
> +      record_full_arch_list_add_reg (regcache, tmp | 1);
... and use +1 here.  Otherwise you require that tdep->ppc_gp0_regnum
is even, which is currently true but not necessarily guaranteed.

> +    case 47:		/* Store Multiple Word */
> +	{
> +	  ULONGEST addr = 0;
> +	  int size;
Unused?
> +
> +	  if (PPC_RA (insn) != 0)
> +	    regcache_raw_read_unsigned (regcache,
> +					tdep->ppc_gp0_regnum + PPC_RA (insn),
> +					&addr);
> +
> +	  addr += PPC_D (insn);
> +
> +	  for (i = PPC_RS (insn); i < 32; i++)
> +	    record_full_arch_list_add_mem (addr + i * 4, 4);
The offset is wrong; the first register is stored at addr.
Is there a reason why this can't be just a single record call?

> +    case 57:		/* Load Floating-Point Double Pair */
> +      tmp = (tdep->ppc_fp0_regnum + PPC_RT (insn)) & ~1;
> +      record_full_arch_list_add_reg (regcache, tmp);
> +      record_full_arch_list_add_reg (regcache, tmp | 1);
See above (Load Quadword).

> +    case 58:		/* Load Doubleword */
> +			/* Load Doubleword with Update */
> +			/* Load Doubleword Algebraic */
Load Word Algebraic.


Bye,
Ulrich


-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 0/3 v2] Process record support for PowerPC
  2014-11-28 12:15 ` Ulrich Weigand
@ 2014-12-06 17:57   ` Wei-cheng Wang
  2014-12-08 19:09     ` Ulrich Weigand
  0 siblings, 1 reply; 4+ messages in thread
From: Wei-cheng Wang @ 2014-12-06 17:57 UTC (permalink / raw)
  To: uweigand, gdb-patches

On 2014/11/28 下午 08:15, Ulrich Weigand wrote:
> Wei-cheng Wang wrote:
> Excellent!   Some suggestions for additional testing:
>    - 32-bit mode (test using -m32) -- it seems some of your Linux-specific
>      code may not work correctly in 32-bit mode
>    - Different ISA levels (test using -mcpu=power8/power7/...) to exercise
>      different instructions

   Tested with -m32 and -mcpu=power8/power7
   * All pass for -mcpu=power8/power7
   * 12 fails due to skip-plt-stub.  Fixed in this patch.

> The only one of those that would be of interest (on current server
> platforms) would be VSX.  I see that you're actually already supporting
> many VSX instructions, in particular loads and stores.  The one missing
> piece is opcode 60.  It would be great if you could add that to complete
> VSX support ... but this is not a requirement to get this patch approved,
> we can always add it later.
   VSX instructions in opcode 60 are added now.

> What is this (infrun.h) needed for?
   For execution_direction == EXEC_REVERSE.  They are declared in infrun.h.

>> +#define SUBSTRCMP(sym, stub)  (memcmp (sym + 8, stub, sizeof (stub) - 1) == 0)
>> +      if (SUBSTRCMP (MSYMBOL_LINKAGE_NAME (sym.minsym), ".plt_call."))
>> +	return 1;
>> +      if (SUBSTRCMP (MSYMBOL_LINKAGE_NAME (sym.minsym), ".plt_branch."))
>> +	return 1;
>> +      if (SUBSTRCMP (MSYMBOL_LINKAGE_NAME (sym.minsym), ".plt_branch_r2off."))
>> +	return 1;
>> +#undef SUBSTRCMP
> Huh.  The "sym + 8" seems odd.  What if symbol name is shorter than 8 bytes?
   I was trying to match such symbols,
     00000017.plt_call.foo
     ^^^^^^^^
     8 is used to skip the hex prefix.
> Also, those stub symbols are not guaranteed to be present.
> Can't we generalize the skip_trampoline_code so that it also accepts
> a PC in the middle of the sequence?  That would seem a more general
> solution.
   Ok, I changed the implementation above in in_dynsym_resolve_code to use
   skip_trampoline_code to match the sequence backward.  Is this ok?

>> @@ -1345,6 +1524,15 @@ ppc_linux_init_abi (struct gdbarch_info info,
>> +      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);
>> +
> If we actually need this, we shouldn't copy this part in both the
> wordsize == 4 and wordsize == 8 paths, but just have it once.
> Also, this part should probably be broken out into a separate patch.
>> +  if (syscall_gdb == gdb_sys_sigreturn
>> +      || syscall_gdb == gdb_sys_rt_sigreturn)
>> +   {
>> +     if (ppc_all_but_pc_registers_record (regcache))
>> +       return -1;
>
> For example, here, we might actually have to record *all* registers, since
> a sigreturn syscall will in fact reload not just the GPRs, but also float
> and vector registers.
   Changed to record GPRs, FPRs and Vector registers as you suggested.

>> +static int
>> +ppc64_linux_record_signal (struct gdbarch *gdbarch,
>> +                           struct regcache *regcache,
>> +                           enum gdb_signal signal)
>> +{
>> +  /* See arch/powerpc/kernel/signal_64.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;
> This is too big for 32-bit, but that may not matter.  (See also below.)
>> +  ULONGEST sp;
>> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
>> +
>> +  if (ppc_all_but_pc_registers_record (regcache))
>> +    return -1;
> I'm not sure why we need this here; signal delivery does not actually change
> all registers, it only changes those affected by a function call (possibly
> 0, 11, 12, some argument registers, LR, CTR, SP).
   I checked signal_64.c/signal_32.c in kernel code.
   If I didn't get it wrong, 3, 4 ,5 ,and 6, (and 12 for 64-bit only),
   LR, CTR and SP should be saved, and I record these registers in the new patch.
   However, I didn't find any document describes about this.

>> +  if (record_full_arch_list_add_mem (sp, SIGNAL_FRAMESIZE + sizeof_rt_sigframe))
>> +    return -1;
> I see x86 does this too, but I wonder why.  All this memory is in fact
> uninitialized before the signal, so what's the point of tracking its original
> contents?
   I thought users may want to record exactly what happened?
   It shouldn't matter if recording too much memory for 32-bit.
   Or should I just removed this?  As you said, the are uninitialized before the signal.

>> +  /* Support reverse debugging.  */
>> +  set_gdbarch_process_record (gdbarch, ppc64_process_record);
>> +  set_gdbarch_process_record_signal (gdbarch, ppc64_linux_record_signal);
>> +  tdep->syscall_record = ppc_linux_syscall_record;
>
> At this place in ppc_linux_init_abi, we are handling *both* 32-bit and
> 64-bit code.  This means the callbacks installed here should handle
> both bitsizes.  That seems OK for ppc64_process_record, but probably
> not for ppc64_linux_record_signal and ppc_linux_syscall_record (in
> their current implementation).
   32/64 use the same syscall numbers, and they clobbered the same registers,
   so ppc_linux_syscall_record can be shared for both 32- and 64-bit, right?
   ppc_linux_record_signal is revised by checking tdep->wordsize to save extra r12
   for 64-bit.

>> +  /* Initialize the ppc_linux_record_tdep.  */
>> +  /* These values are the size of the type that will be used in a system
>> +     call.  They are obtained from Linux Kernel source.
>> +
>> +     See arch/powerpc/include/uapi/asm/ioctls.h.  */
>> +  ppc_linux_record_tdep.size_pointer
>> +    = gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT;
>
> This is problematic.  There is only one single instance of
> ppc_linux_record_tdep, so when this code is called for 32-bit
> and then for 64-bit, that single instance gets overwritten.
> I think we really need two copies of the structure, and
> install the one appropriate for the current bitsize.
>
> Note that many of the hard-coded "size" values in your
> patch are only correct for 64-bit, so the 32-bit copy
> of the struct would have to use different values.
> (The non-"size" values should be OK for both.)

   ppc_linux_record_tdep and ppc64_linux_record_tdep are declared,
   and tdep->pcc_linux_record_tdep will point to the right one.

 >> +  ppc_linux_record_tdep.size_PAGE_SIZE = 4096;
 > This is a bit of a problem.  The PowerPC kernel can be compiled
 > with either 4k or 64k page size.  We could either try to detect
 > at runtime (from auxv) or always use the conservative 64k.
   Always 64K in this patch.
   If we want to handle both 4k/64k,
   * 4 ppc_linux_records are need for (32 + 64) * (4K + 64K).
   * Add field of pagesize in ppc_tdep.
   * Revise "Find a candidate among extant architectures." in
     rs6000_gdbarch_init to check pagesize.

>> +static const struct frame_unwind rs6000_epilogue_frame_unwind =
>> +{
>> +  NORMAL_FRAME,
>> +  default_frame_unwind_stop_reason,
>> +  rs6000_epilogue_frame_this_id, rs6000_epilogue_frame_prev_register,
>> +  NULL,
>> +  rs6000_epilogue_frame_sniffer
>> +};
>
> Is this actually still necessary with a current compiler that tracks
> epilogues in DWARF?   In any case, it would be better to provide this
> in a separate patch.
   This is necessary.
   Some cases test "reverse-next over undebuggable solib functions."

>> +    case 32:		/* Vector Multiply-High-Add Signed Halfword Saturate */
>> +    case 33:		/* Vector Multiply-High-Round-Add Signed Halfword Saturate */
>> +    case 39:		/* Vector Multiply-Sum Unsigned Halfword Saturate */
>> +    case 41:		/* Vector Multiply-Sum Signed Halfword Saturate */
>> +    case 42:		/* Vector Select */
>> +    case 43:		/* Vector Permute */
>> +    case 44:		/* Vector Shift Left Double by Octet Immediate */
>> +    case 60:		/* Vector Add Extended Unsigned Quadword Modulo */
>> +    case 61:		/* Vector Add Extended & write Carry Unsigned Quadword */
>> +    case 62:		/* Vector Subtract Extended Unsigned Quadword Modulo */
>> +    case 63:		/* Vector Subtract Extended & write Carry Unsigned Quadword */
>> +    case 34:		/* Vector Multiply-Low-Add Unsigned Halfword Modulo */
>> +    case 36:		/* Vector Multiply-Sum Unsigned Byte Modulo */
>> +    case 37:		/* Vector Multiply-Sum Mixed Byte Modulo */
>> +    case 38:		/* Vector Multiply-Sum Unsigned Halfword Modulo */
>> +    case 40:		/* Vector Multiply-Sum Signed Halfword Modulo */
>> +    case 46:		/* Vector Multiply-Add Single-Precision */
>> +    case 47:		/* Vector Negative Multiply-Subtract Single-Precision */
> All of those use a VRC field, and therefore need to be treated like the case 45
> at the beginning of this function!
    I am confused.  I checked PowerISA_V2.07_PUBLIC.pdf again,
    and these only _use_ VRC, but not write VRC, so does case 45.

>> +			/* 5.16 Decimal Integer Arithmetic Instructions */
> Headline superfluous at this point.
   Section headlines are all removed.

>> +    case 339:          /* Move From Special Purpose Register */
> Maybe add case 371 Move From Time Base here.  The instruction is
> phased out, but potentially still used in some code.
   Ok, added.

>> +    /* These write VSR of size 8.  */
>> +    case 588:		/* Load VSX Scalar Doubleword Indexed */
>> +      ppc_record_vsr (regcache, tdep, PPC_XT (insn), 8);
> Note that the contents of the other doubleword element are undefined
> after this instruction, so you need to save all of it, i.e. size == 16.
> In fact, we probably don't even need the size argument then.
   "SIZE" argument is removed as you suggest.

>> +static int
>> +ppc64_process_record_op60 (struct gdbarch *gdbarch, struct regcache *regcache,
>> +                          CORE_ADDR addr, uint32_t insn)
>> +{
>> +  int ext = PPC_EXTOP (insn);
>> +
>> +  fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record "
>> +                     "%08x at %08lx, 60-%d.\n", insn, addr, ext);
> Since those may actually occur (frequently) in user code, we should probably
> reword the message to something along the lines of "VSX instructions not
> yet supported".  (Or simply implement them :-))
   Opcode 60 are all handled in the new patch :)

>> +    case 56:		/* Load Quadword */
> Should check that the last two bits are zero.
   I checked ISA, it doesn't specify the last two bits.  Bit-28x-31 is "///".
   However, I add the check as you suggest in the new patch.

>> +    case 47:		/* Store Multiple Word */
>> +	{
>> +	  ULONGEST addr = 0;
>> +	  int size;
> Unused?
>> +
>> +	  if (PPC_RA (insn) != 0)
>> +	    regcache_raw_read_unsigned (regcache,
>> +					tdep->ppc_gp0_regnum + PPC_RA (insn),
>> +					&addr);
>> +
>> +	  addr += PPC_D (insn);
>> +
>> +	  for (i = PPC_RS (insn); i < 32; i++)
>> +	    record_full_arch_list_add_mem (addr + i * 4, 4);
> The offset is wrong; the first register is stored at addr.
> Is there a reason why this can't be just a single record call?
   Changed to just a single record as you suggested.

> Bye,
> Ulrich

Thanks for the review,
Wei-cheng

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 0/3 v2] Process record support for PowerPC
  2014-12-06 17:57   ` [PATCH 0/3 v2] " Wei-cheng Wang
@ 2014-12-08 19:09     ` Ulrich Weigand
  0 siblings, 0 replies; 4+ messages in thread
From: Ulrich Weigand @ 2014-12-08 19:09 UTC (permalink / raw)
  To: Wei-cheng Wang; +Cc: gdb-patches

Wei-cheng Wang wrote:
> On 2014/11/28 下午 08:15, Ulrich Weigand wrote:
> > Excellent!   Some suggestions for additional testing:
> >    - 32-bit mode (test using -m32) -- it seems some of your Linux-specific
> >      code may not work correctly in 32-bit mode
> >    - Different ISA levels (test using -mcpu=power8/power7/...) to exercise
> >      different instructions
> 
>    Tested with -m32 and -mcpu=power8/power7
>    * All pass for -mcpu=power8/power7
>    * 12 fails due to skip-plt-stub.  Fixed in this patch.

Very good!  Thanks for the additional testing.

> > The only one of those that would be of interest (on current server
> > platforms) would be VSX.  I see that you're actually already supporting
> > many VSX instructions, in particular loads and stores.  The one missing
> > piece is opcode 60.  It would be great if you could add that to complete
> > VSX support ... but this is not a requirement to get this patch approved,
> > we can always add it later.
>    VSX instructions in opcode 60 are added now.

Many thanks for completing VSX support!


> > What is this (infrun.h) needed for?
>   For execution_direction == EXEC_REVERSE.  They are declared in infrun.h.

I see, thanks.

> > Also, those stub symbols are not guaranteed to be present.
> > Can't we generalize the skip_trampoline_code so that it also accepts
> > a PC in the middle of the sequence?  That would seem a more general
> > solution.
>    Ok, I changed the implementation above in in_dynsym_resolve_code to use
>    skip_trampoline_code to match the sequence backward.  Is this ok?

It seems odd to have in_dynsym_resolve_code call into
skip_trampoline_code.  Is there a reason why the skip_trampoline_code
implementation cannot accept a PC in the middle of the sequence?


> >> +  ULONGEST sp;
> >> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> >> +
> >> +  if (ppc_all_but_pc_registers_record (regcache))
> >> +    return -1;
> > I'm not sure why we need this here; signal delivery does not actually change
> > all registers, it only changes those affected by a function call (possibly
> > 0, 11, 12, some argument registers, LR, CTR, SP).
>    I checked signal_64.c/signal_32.c in kernel code.
>    If I didn't get it wrong, 3, 4 ,5 ,and 6, (and 12 for 64-bit only),
>    LR, CTR and SP should be saved, and I record these registers in the new patch.
>    However, I didn't find any document describes about this.

Well, which argument registers are clobbered really depends on which
arguments the kernel passes to a signal handler routine.  The kernel
really doesn't change any registers except those needed to effect an
orderly function call to the signal handler, according to the ABI.

However, I think it would be safest to assume all argument registers
can be clobbered, just in case of future kernel changes.


> >> +  if (record_full_arch_list_add_mem (sp, SIGNAL_FRAMESIZE + sizeof_rt_sigframe))
> >> +    return -1;
> > I see x86 does this too, but I wonder why.  All this memory is in fact
> > uninitialized before the signal, so what's the point of tracking its original
> > contents?
>    I thought users may want to record exactly what happened?
>    It shouldn't matter if recording too much memory for 32-bit.
>    Or should I just removed this?  As you said, the are uninitialized before the signal.

Well, given that x86 does it, I guess I'm fine with leaving it in.

> > At this place in ppc_linux_init_abi, we are handling *both* 32-bit and
> > 64-bit code.  This means the callbacks installed here should handle
> > both bitsizes.  That seems OK for ppc64_process_record, but probably
> > not for ppc64_linux_record_signal and ppc_linux_syscall_record (in
> > their current implementation).
>    32/64 use the same syscall numbers, and they clobbered the same registers,
>    so ppc_linux_syscall_record can be shared for both 32- and 64-bit, right?

Yes, that looks right to me.


> > Note that many of the hard-coded "size" values in your
> > patch are only correct for 64-bit, so the 32-bit copy
> > of the struct would have to use different values.
> > (The non-"size" values should be OK for both.)
> 
>    ppc_linux_record_tdep and ppc64_linux_record_tdep are declared,
>    and tdep->pcc_linux_record_tdep will point to the right one.

OK, sounds good.

> >> +  ppc_linux_record_tdep.size_PAGE_SIZE = 4096;
> > This is a bit of a problem.  The PowerPC kernel can be compiled
> > with either 4k or 64k page size.  We could either try to detect
> > at runtime (from auxv) or always use the conservative 64k.
>   Always 64K in this patch.
>   If we want to handle both 4k/64k,
>   * 4 ppc_linux_records are need for (32 + 64) * (4K + 64K).
>   * Add field of pagesize in ppc_tdep.
>   * Revise "Find a candidate among extant architectures." in
>     rs6000_gdbarch_init to check pagesize.

Agreed that always 64k is good for now.


> > Is this actually still necessary with a current compiler that tracks
> > epilogues in DWARF?   In any case, it would be better to provide this
> > in a separate patch.
>    This is necessary.
>    Some cases test "reverse-next over undebuggable solib functions."

Huh, OK.  Patch 1/3 looks OK to me then.


> >> +    case 32:		/* Vector Multiply-High-Add Signed Halfword Saturate */
> >> +    case 33:		/* Vector Multiply-High-Round-Add Signed Halfword Saturate */
> >> +    case 39:		/* Vector Multiply-Sum Unsigned Halfword Saturate */
> >> +    case 41:		/* Vector Multiply-Sum Signed Halfword Saturate */
> >> +    case 42:		/* Vector Select */
> >> +    case 43:		/* Vector Permute */
> >> +    case 44:		/* Vector Shift Left Double by Octet Immediate */
> >> +    case 60:		/* Vector Add Extended Unsigned Quadword Modulo */
> >> +    case 61:		/* Vector Add Extended & write Carry Unsigned Quadword */
> >> +    case 62:		/* Vector Subtract Extended Unsigned Quadword Modulo */
> >> +    case 63:		/* Vector Subtract Extended & write Carry Unsigned Quadword */
> >> +    case 34:		/* Vector Multiply-Low-Add Unsigned Halfword Modulo */
> >> +    case 36:		/* Vector Multiply-Sum Unsigned Byte Modulo */
> >> +    case 37:		/* Vector Multiply-Sum Mixed Byte Modulo */
> >> +    case 38:		/* Vector Multiply-Sum Unsigned Halfword Modulo */
> >> +    case 40:		/* Vector Multiply-Sum Signed Halfword Modulo */
> >> +    case 46:		/* Vector Multiply-Add Single-Precision */
> >> +    case 47:		/* Vector Negative Multiply-Subtract Single-Precision */
> > All of those use a VRC field, and therefore need to be treated like the case 45
> at the beginning of this function!
>    I am confused.  I checked PowerISA_V2.07_PUBLIC.pdf again,
>    and these only _use_ VRC, but not write VRC, so does case 45.

The problem is not that they write to VRC, but that the insn wouldn't
match the case statement any more for any VRC != 0.   You have:

+  int ext = PPC_FIELD (insn, 21, 11);
[snip]
+  switch (ext)
+    {
[snip]
+    case 32:           /* Vector Multiply-High-Add Signed Halfword Saturate */

But the last 11 bits of this instruction also hold the VRC field, so if
VRC != 0, then ext would be != 32 for this instruction.

That's why I said the check needs to be handled like Vector Permute:

+  if ((ext & 0x3f) == 45)
+    {

That is, you should have a separate

  switch (ext & 0x3f)
    {
    case 45:
       ...
    case 32:
       ...
    ...
    }

at the beginning to handle all instructions with VRC field.


> >> +    case 56:		/* Load Quadword */
> > Should check that the last two bits are zero.
>    I checked ISA, it doesn't specify the last two bits.  Bit-28x-31 is "///".
>    However, I add the check as you suggest in the new patch.

Oops, you are right: for opcode 56, that check should not be there.
(In fact, adding the check is wrong.)   Sorry for the confusion.

I was confusing this with opcode 57, where the check is actually
necessary.

I'll also reply to the patches separately.

Thanks again,
Ulrich


-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2014-12-08 19:09 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-11-18 16:27 [PATCH] Process record support for PowerPC Wei-cheng, Wang
2014-11-28 12:15 ` Ulrich Weigand
2014-12-06 17:57   ` [PATCH 0/3 v2] " Wei-cheng Wang
2014-12-08 19:09     ` Ulrich Weigand

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).