]> granicus.if.org Git - strace/commitdiff
syscall.c: add ability to set personality based on GETREGSET iov size
authorEugene Syromyatnikov <evgsyr@gmail.com>
Mon, 15 Jan 2018 20:49:14 +0000 (21:49 +0100)
committerDmitry V. Levin <ldv@altlinux.org>
Tue, 16 Jan 2018 22:54:38 +0000 (22:54 +0000)
Some architectures (aarch64, s390x) use only PTRACE_GETREGSET interface
and use its size to detect current personality. Let's generalise this
approach and also avoid subtle errors when we get register but forget to
update personality, at least for those architectures.

Note that in order to employ this behaviour, architecture has to use
PTRACE_GETREGSET exclusively (no HAVE_GETREGS_OLD) and should declare
appropriate ARCH_PERSONALITY_*_IOV_SIZE macros.

* syscall.c (get_regs) [ptrace_getregset_or_getregs &&
!HAVE_GETREGS_OLD]: Call update_personality based on the value returned
in the iov_len field by PTRACE_GETREGSET.  Warn once if the returned
iov_len is unknown.

syscall.c

index 444bfa1ef25e6aa8b8a8a8553283cb5671514ebe..1a45b977cc9cb90581f665f84be46192321c7239 100644 (file)
--- a/syscall.c
+++ b/syscall.c
@@ -1154,7 +1154,37 @@ get_regs(struct tcb *const tcp)
        return get_regs_error = getregs_old(tcp);
 # else /* !HAVE_GETREGS_OLD */
        /* Assume that PTRACE_GETREGSET/PTRACE_GETREGS works. */
-       return get_regs_error = ptrace_getregset_or_getregs(tcp->pid);
+       get_regs_error = ptrace_getregset_or_getregs(tcp->pid);
+
+#  if defined ARCH_PERSONALITY_0_IOV_SIZE
+       if (get_regs_error)
+               return get_regs_error;
+
+       switch (ARCH_IOVEC_FOR_GETREGSET.iov_len) {
+       case ARCH_PERSONALITY_0_IOV_SIZE:
+               update_personality(tcp, 0);
+               break;
+       case ARCH_PERSONALITY_1_IOV_SIZE:
+               update_personality(tcp, 1);
+               break;
+       default: {
+               static bool printed = false;
+
+               if (!printed) {
+                       error_msg("Unsupported regset size returned by "
+                                 "PTRACE_GETREGSET: %zu",
+                                 ARCH_IOVEC_FOR_GETREGSET.iov_len);
+
+                       printed = true;
+               }
+
+               update_personality(tcp, 0);
+       }
+       }
+#  endif /* ARCH_PERSONALITY_0_IOV_SIZE */
+
+       return get_regs_error;
+
 # endif /* !HAVE_GETREGS_OLD */
 
 #else /* !ptrace_getregset_or_getregs */