s390, s390x: use PTRACE_GETREGSET to fetch registers
* linux/s390/arch_regs.h: New file.
* linux/s390x/arch_regs.h: New file.
* Makefile.am (EXTRA_DIST): Add them.
* signal.c (sys_sigreturn) [S390 || S390X]: Use s390_frame_ptr.
* syscall.c [S390 || S390X] (s390_regset, s390_frame_ptr): New variable.
[S390 || S390X] (ARCH_REGS_FOR_GETREGSET): New macro.
(print_pc) [S390 || S390X]: Use s390_regset.
(get_scno) [S390 || S390X]: Likewise.
(get_syscall_args) [S390 || S390X]: Likewise.
(get_error) [S390 || S390X]: Likewise.
(get_syscall_result) [S390 || S390X]: Remove.
diff --git a/Makefile.am b/Makefile.am
index 587dd7a..589e61b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -264,12 +264,14 @@
linux/powerpc64/syscallent1.h \
linux/powerpc64/userent.h \
linux/ptp_clock.h \
+ linux/s390/arch_regs.h \
linux/s390/ioctls_arch0.h \
linux/s390/ioctls_inc0.h \
linux/s390/syscallent.h \
linux/s390/userent.h \
linux/s390/userent0.h \
linux/s390/userent1.h \
+ linux/s390x/arch_regs.h \
linux/s390x/ioctls_arch0.h \
linux/s390x/ioctls_inc0.h \
linux/s390x/syscallent.h \
diff --git a/NEWS b/NEWS
index 4ef4d48..8ff0249 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,7 @@
* Implemented full 32-bit decoding of ioctl commands
(addresses Fedora bug #902788).
* Implemented PTRACE_GETREGS API support on MIPS.
+ * Implemented PTRACE_GETREGSET API support on S390/S390x.
* Implemented decoding of getrandom and seccomp syscalls.
* Implemented full decoding of 64-bit capability sets.
* Implemented decoding of all prctl commands.
diff --git a/linux/s390/arch_regs.h b/linux/s390/arch_regs.h
new file mode 100644
index 0000000..586326f
--- /dev/null
+++ b/linux/s390/arch_regs.h
@@ -0,0 +1 @@
+extern unsigned long *const s390_frame_ptr;
diff --git a/linux/s390x/arch_regs.h b/linux/s390x/arch_regs.h
new file mode 100644
index 0000000..14fced4
--- /dev/null
+++ b/linux/s390x/arch_regs.h
@@ -0,0 +1 @@
+#include "s390/arch_regs.h"
diff --git a/signal.c b/signal.c
index 6aab54f..69a47bb 100644
--- a/signal.c
+++ b/signal.c
@@ -717,19 +717,16 @@
}
#elif defined(S390) || defined(S390X)
if (entering(tcp)) {
- long usp;
long mask[NSIG / 8 / sizeof(long)];
- if (upeek(tcp->pid, PT_GPR15, &usp) < 0)
- return 0;
tprints("{mask=");
- const long addr = usp + __SIGNAL_FRAMESIZE;
+ const long addr = *s390_frame_ptr + __SIGNAL_FRAMESIZE;
if (umove(tcp, addr, &mask) < 0) {
tprintf("%#lx", addr);
} else {
# ifdef S390
- usp = mask[0];
+ long v = mask[0];
mask[0] = mask[1];
- mask[1] = usp;
+ mask[1] = v;
# endif
tprintsigmask_addr("", mask);
}
diff --git a/syscall.c b/syscall.c
index 2e536fc..854a785 100644
--- a/syscall.c
+++ b/syscall.c
@@ -764,7 +764,10 @@
/* PTRACE_GETREGS on MIPS is available since linux v2.6.15. */
# define ARCH_REGS_FOR_GETREGS mips_regs
#elif defined(S390) || defined(S390X)
-static long s390_gpr2;
+/* PTRACE_GETREGSET on S390 is available since linux v2.6.27. */
+static struct user_regs_struct s390_regset;
+unsigned long *const s390_frame_ptr = &s390_regset.gprs[15];
+# define ARCH_REGS_FOR_GETREGSET s390_regset
#elif defined(HPPA)
static long hppa_r28;
#elif defined(SH)
@@ -829,12 +832,7 @@
else
tprintf(fmt, (unsigned long) x86_64_regs.rip);
#elif defined(S390) || defined(S390X)
- long psw;
- if (upeek(tcp->pid, PT_PSWADDR, &psw) < 0) {
- PRINTBADPC;
- return;
- }
- tprintf(fmt, psw);
+ tprintf(fmt, s390_regset.psw.addr);
#elif defined(IA64)
long ip;
if (upeek(tcp->pid, PT_B0, &ip) < 0) {
@@ -1134,87 +1132,7 @@
long scno = 0;
#if defined(S390) || defined(S390X)
- if (upeek(tcp->pid, PT_GPR2, &s390_gpr2) < 0)
- return -1;
-
- if (s390_gpr2 != -ENOSYS) {
- /*
- * Since kernel version 2.5.44 the scno gets passed in gpr2.
- */
- scno = s390_gpr2;
- } else {
- /*
- * Old style of "passing" the scno via the SVC instruction.
- */
- long psw;
- long opcode, offset_reg, tmp;
- void *svc_addr;
- static const int gpr_offset[16] = {
- PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
- PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
- PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
- PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15
- };
-
- if (upeek(tcp->pid, PT_PSWADDR, &psw) < 0)
- return -1;
- errno = 0;
- opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(psw - sizeof(long)), 0);
- if (errno) {
- perror_msg("peektext(psw-oneword)");
- return -1;
- }
-
- /*
- * We have to check if the SVC got executed directly or via an
- * EXECUTE instruction. In case of EXECUTE it is necessary to do
- * instruction decoding to derive the system call number.
- * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
- * so that this doesn't work if a SVC opcode is part of an EXECUTE
- * opcode. Since there is no way to find out the opcode size this
- * is the best we can do...
- */
- if ((opcode & 0xff00) == 0x0a00) {
- /* SVC opcode */
- scno = opcode & 0xff;
- }
- else {
- /* SVC got executed by EXECUTE instruction */
-
- /*
- * Do instruction decoding of EXECUTE. If you really want to
- * understand this, read the Principles of Operations.
- */
- svc_addr = (void *) (opcode & 0xfff);
-
- tmp = 0;
- offset_reg = (opcode & 0x000f0000) >> 16;
- if (offset_reg && (upeek(tcp->pid, gpr_offset[offset_reg], &tmp) < 0))
- return -1;
- svc_addr += tmp;
-
- tmp = 0;
- offset_reg = (opcode & 0x0000f000) >> 12;
- if (offset_reg && (upeek(tcp->pid, gpr_offset[offset_reg], &tmp) < 0))
- return -1;
- svc_addr += tmp;
-
- scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
- if (errno)
- return -1;
-# if defined(S390X)
- scno >>= 48;
-# else
- scno >>= 16;
-# endif
- tmp = 0;
- offset_reg = (opcode & 0x00f00000) >> 20;
- if (offset_reg && (upeek(tcp->pid, gpr_offset[offset_reg], &tmp) < 0))
- return -1;
-
- scno = (scno | tmp) & 0xff;
- }
- }
+ scno = s390_regset.gprs[2];
#elif defined(POWERPC)
scno = ppc_regs.gpr[0];
# ifdef POWERPC64
@@ -1624,9 +1542,14 @@
nargs = tcp->s_ent->nargs;
#if defined(S390) || defined(S390X)
- for (i = 0; i < nargs; ++i)
- if (upeek(tcp->pid, i==0 ? PT_ORIGGPR2 : PT_GPR2 + i*sizeof(long), &tcp->u_arg[i]) < 0)
- return -1;
+ (void)i;
+ (void)nargs;
+ tcp->u_arg[0] = s390_regset.orig_gpr2;
+ tcp->u_arg[1] = s390_regset.gprs[3];
+ tcp->u_arg[2] = s390_regset.gprs[4];
+ tcp->u_arg[3] = s390_regset.gprs[5];
+ tcp->u_arg[4] = s390_regset.gprs[6];
+ tcp->u_arg[5] = s390_regset.gprs[7];
#elif defined(ALPHA)
for (i = 0; i < nargs; ++i)
if (upeek(tcp->pid, REG_A0+i, &tcp->u_arg[i]) < 0)
@@ -1946,9 +1869,6 @@
{
#if defined ARCH_REGS_FOR_GETREGSET || defined ARCH_REGS_FOR_GETREGS
/* already done by get_regs */
-#elif defined(S390) || defined(S390X)
- if (upeek(tcp->pid, PT_GPR2, &s390_gpr2) < 0)
- return -1;
#elif defined(BFIN)
if (upeek(tcp->pid, PT_R0, &bfin_r0) < 0)
return -1;
@@ -2009,12 +1929,12 @@
check_errno = 0;
}
#if defined(S390) || defined(S390X)
- if (check_errno && is_negated_errno(s390_gpr2)) {
+ if (check_errno && is_negated_errno(s390_regset.gprs[2])) {
tcp->u_rval = -1;
- u_error = -s390_gpr2;
+ u_error = -s390_regset.gprs[2];
}
else {
- tcp->u_rval = s390_gpr2;
+ tcp->u_rval = s390_regset.gprs[2];
}
#elif defined(I386)
if (check_errno && is_negated_errno(i386_regs.eax)) {