From: Dmitry V. Levin Date: Thu, 5 Mar 2015 22:10:15 +0000 (+0000) Subject: s390, s390x: use PTRACE_GETREGSET to fetch registers X-Git-Tag: v4.10~3 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=20eca8a1c5913043fcf4a67ff6cdc6293985831f;p=strace 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 587dd7a4..589e61b4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 4ef4d485..8ff02497 100644 --- 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 index 00000000..586326ff --- /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 00000000..14fced4e --- /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 6aab54f7..69a47bb6 100644 --- 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); } diff --git a/syscall.c b/syscall.c index 2e536fc9..854a7851 100644 --- 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)) {