]> granicus.if.org Git - strace/commitdiff
powerpc: Provide a fallback for old kernels without PTRACE_GETREGS
authorAnton Blanchard <anton@samba.org>
Wed, 26 Jun 2013 04:42:37 +0000 (14:42 +1000)
committerDenys Vlasenko <dvlasenk@redhat.com>
Wed, 26 Jun 2013 13:57:29 +0000 (15:57 +0200)
PTRACE_GETREGS was added to the ppc kernel in 2.6.23. In order to
provide backward compatibility for very old kernels, add a manual
fallback.

* syscall.c (powerpc_getreg, powerpc_getregs_old): New functions.
(get_regs): Call powerpc_getregs_old if PTRACE_GETREGS is not supported.

Signed-off-by: Anton Blanchard <anton@samba.org>
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
syscall.c

index f5263a743b7a42bfdf9c35390483c0b16275e644..7c6317fe60b08d4d94368699be6770055b51ee70 100644 (file)
--- a/syscall.c
+++ b/syscall.c
@@ -994,6 +994,55 @@ undefined_scno_name(struct tcb *tcp)
        return buf;
 }
 
+#ifdef POWERPC
+/*
+ * PTRACE_GETREGS was added to the PowerPC kernel in v2.6.23, so we
+ * provide a slow fallback for very old kernels.
+ */
+
+static long powerpc_getreg(pid_t pid, unsigned long offset, unsigned long *p)
+{
+       long val;
+
+       errno = 0;
+       val = ptrace(PTRACE_PEEKUSER, pid, (char *)offset, 0);
+       if (val == -1 && errno)
+               return -1;
+
+       *p = val;
+       return 0;
+}
+
+static long powerpc_getregs_old(pid_t pid)
+{
+       int i;
+       long r;
+
+       r = powerpc_getreg(pid, sizeof(unsigned long) * PT_MSR, &ppc_regs.msr);
+       if (r)
+               goto out;
+
+       r = powerpc_getreg(pid, sizeof(unsigned long) * PT_CCR, &ppc_regs.ccr);
+       if (r)
+               goto out;
+
+       r = powerpc_getreg(pid, sizeof(unsigned long) * PT_ORIG_R3,
+                          &ppc_regs.orig_gpr3);
+       if (r)
+               goto out;
+
+       for (i = 0; i <= 8; i++) {
+               r = powerpc_getreg(pid, sizeof(unsigned long) * (PT_R0 + i),
+                                  &ppc_regs.gpr[i]);
+               if (r)
+                       goto out;
+       }
+
+out:
+       return r;
+}
+#endif
+
 #ifndef get_regs
 long get_regs_error;
 
@@ -1042,6 +1091,8 @@ get_regs(pid_t pid)
        get_regs_error = ptrace(PTRACE_GETREGS, pid, (char *)&sparc_regs, 0);
 # elif defined(POWERPC)
        get_regs_error = ptrace(PTRACE_GETREGS, pid, NULL, (long) &ppc_regs);
+       if (get_regs_error && errno == EIO)
+               get_regs_error = powerpc_getregs_old(pid);
 
 /* try PTRACE_GETREGSET first, fallback to PTRACE_GETREGS */
 # else