summaryrefslogtreecommitdiff
path: root/syscall.c
diff options
context:
space:
mode:
authorAnton Blanchard <anton@samba.org>2013-06-26 14:42:37 +1000
committerDenys Vlasenko <dvlasenk@redhat.com>2013-06-26 15:57:29 +0200
commit14d51a6423aa47378518a71e8345a3d1944d97e7 (patch)
tree10013bf9e4ecdf4be63327de7b00ecdc657400e3 /syscall.c
parentce6e33be1dbfc16620ea7991a414e879ef84fe22 (diff)
downloadstrace-14d51a6423aa47378518a71e8345a3d1944d97e7.tar.gz
strace-14d51a6423aa47378518a71e8345a3d1944d97e7.tar.bz2
strace-14d51a6423aa47378518a71e8345a3d1944d97e7.tar.xz
powerpc: Provide a fallback for old kernels without PTRACE_GETREGS
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>
Diffstat (limited to 'syscall.c')
-rw-r--r--syscall.c51
1 files changed, 51 insertions, 0 deletions
diff --git a/syscall.c b/syscall.c
index f5263a7..7c6317f 100644
--- 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