]> granicus.if.org Git - strace/commitdiff
s390, s390x: use PTRACE_GETREGSET to fetch registers
authorDmitry V. Levin <ldv@altlinux.org>
Thu, 5 Mar 2015 22:10:15 +0000 (22:10 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Thu, 5 Mar 2015 22:10:15 +0000 (22:10 +0000)
* 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.

Makefile.am
NEWS
linux/s390/arch_regs.h [new file with mode: 0644]
linux/s390x/arch_regs.h [new file with mode: 0644]
signal.c
syscall.c

index 587dd7a4d4428c52c67c88cb3c009f226022c5cb..589e61b4c7f68552af67e3f1c40b1f0bb74408ab 100644 (file)
@@ -264,12 +264,14 @@ EXTRA_DIST =                              \
        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 4ef4d4850cc207048c34fdbae6326b73426589e2..8ff02497099b8c9e95a9c889c08ebe3e5b71b48f 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,7 @@ Noteworthy changes in release 4.10 (????-??-??)
   * 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 (file)
index 0000000..586326f
--- /dev/null
@@ -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 (file)
index 0000000..14fced4
--- /dev/null
@@ -0,0 +1 @@
+#include "s390/arch_regs.h"
index 6aab54f700cd4a75356a15709f6ddcafc83fd2c4..69a47bb6ea316d643de06ffa910172d98886124f 100644 (file)
--- a/signal.c
+++ b/signal.c
@@ -717,19 +717,16 @@ sys_sigreturn(struct tcb *tcp)
        }
 #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);
                }
index 2e536fc995e0d3b4bf25adb59901beccb9a39350..854a785143d975ba673e352c25fa02a1008de086 100644 (file)
--- a/syscall.c
+++ b/syscall.c
@@ -764,7 +764,10 @@ struct mips_regs mips_regs; /* not static */
 /* 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 @@ print_pc(struct tcb *tcp)
        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 @@ get_scno(struct tcb *tcp)
        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 @@ get_syscall_args(struct tcb *tcp)
        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 @@ get_syscall_result(struct tcb *tcp)
 {
 #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 @@ get_error(struct tcb *tcp)
                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)) {