From c40270dd87007639ba1fb992c298a2dc6ca13097 Mon Sep 17 00:00:00 2001
From: "Dmitry V. Levin" <ldv@altlinux.org>
Date: Wed, 5 Dec 2018 18:37:34 +0000
Subject: [PATCH] i386, x32: use upoke() instead of set_regs()

This brings i386 and x32 in line with x86_64
and removes redundant HAVE_GETREGS_OLD checks.
Besides that, use of PTRACE_GET_SYSCALL_INFO would require
an extra get_regs() invocation before set_regs().

* syscall.c (ARCH_MIGHT_USE_SET_REGS): Define to 1.
[HAVE_GETREGS_OLD] (ARCH_MIGHT_USE_SET_REGS): Redefine to 0.
(ptrace_setregset_or_setregs): Check ARCH_MIGHT_USE_SET_REGS instead
of HAVE_GETREGS_OLD.
* linux/i386/arch_regs.c (ARCH_MIGHT_USE_SET_REGS): Redefine to 0.
* linux/powerpc/arch_regs.c: Likewise.
* linux/x86_64/arch_regs.c: Likewise.
* linux/i386/set_error.c (arch_set_error, arch_set_success)
[!HAVE_GETREGS_OLD]: Remove.
* linux/i386/set_scno.c (arch_set_scno) [!HAVE_GETREGS_OLD]: Remove.
* linux/powerpc/set_error.c (arch_set_error, arch_set_success)
[!HAVE_GETREGS_OLD]: Remove.
* linux/powerpc/set_scno.c (arch_set_scno) [!HAVE_GETREGS_OLD]: Remove.
* linux/x86_64/set_error.c [!HAVE_GETREGS_OLD]: Remove.
* linux/x86_64/set_scno.c: Likewise.
---
 linux/i386/arch_regs.c    |  3 +++
 linux/i386/set_error.c    |  8 --------
 linux/i386/set_scno.c     |  5 -----
 linux/powerpc/arch_regs.c |  3 +++
 linux/powerpc/set_error.c |  8 --------
 linux/powerpc/set_scno.c  |  5 -----
 linux/x86_64/arch_regs.c  |  3 +++
 linux/x86_64/set_error.c  | 30 +++---------------------------
 linux/x86_64/set_scno.c   | 14 --------------
 syscall.c                 | 14 ++++++++++----
 10 files changed, 22 insertions(+), 71 deletions(-)

diff --git a/linux/i386/arch_regs.c b/linux/i386/arch_regs.c
index a5cf9e90..aeaed9cf 100644
--- a/linux/i386/arch_regs.c
+++ b/linux/i386/arch_regs.c
@@ -3,3 +3,6 @@ static struct user_regs_struct i386_regs;
 #define ARCH_REGS_FOR_GETREGS i386_regs
 #define ARCH_PC_REG i386_regs.eip
 #define ARCH_SP_REG i386_regs.esp
+
+#undef ARCH_MIGHT_USE_SET_REGS
+#define ARCH_MIGHT_USE_SET_REGS 0
diff --git a/linux/i386/set_error.c b/linux/i386/set_error.c
index 7d47e28b..0e0d7c60 100644
--- a/linux/i386/set_error.c
+++ b/linux/i386/set_error.c
@@ -2,20 +2,12 @@ static int
 arch_set_error(struct tcb *tcp)
 {
 	i386_regs.eax = -tcp->u_error;
-#ifdef HAVE_GETREGS_OLD
 	return upoke(tcp, 4 * EAX, i386_regs.eax);
-#else
-	return set_regs(tcp->pid);
-#endif
 }
 
 static int
 arch_set_success(struct tcb *tcp)
 {
 	i386_regs.eax = tcp->u_rval;
-#ifdef HAVE_GETREGS_OLD
 	return upoke(tcp, 4 * EAX, i386_regs.eax);
-#else
-	return set_regs(tcp->pid);
-#endif
 }
diff --git a/linux/i386/set_scno.c b/linux/i386/set_scno.c
index 67736eae..9ac551f9 100644
--- a/linux/i386/set_scno.c
+++ b/linux/i386/set_scno.c
@@ -1,10 +1,5 @@
 static int
 arch_set_scno(struct tcb *tcp, kernel_ulong_t scno)
 {
-#ifdef HAVE_GETREGS_OLD
 	return upoke(tcp, 4 * ORIG_EAX, scno);
-#else
-	i386_regs.orig_eax = scno;
-	return set_regs(tcp->pid);
-#endif
 }
diff --git a/linux/powerpc/arch_regs.c b/linux/powerpc/arch_regs.c
index 37cddc57..78c4c3e7 100644
--- a/linux/powerpc/arch_regs.c
+++ b/linux/powerpc/arch_regs.c
@@ -3,3 +3,6 @@ static struct pt_regs ppc_regs;
 #define ARCH_REGS_FOR_GETREGS ppc_regs
 #define ARCH_PC_REG ppc_regs.nip
 #define ARCH_SP_REG ppc_regs.gpr[1]
+
+#undef ARCH_MIGHT_USE_SET_REGS
+#define ARCH_MIGHT_USE_SET_REGS 0
diff --git a/linux/powerpc/set_error.c b/linux/powerpc/set_error.c
index 602ca15e..d22df112 100644
--- a/linux/powerpc/set_error.c
+++ b/linux/powerpc/set_error.c
@@ -3,12 +3,8 @@ arch_set_error(struct tcb *tcp)
 {
 	ppc_regs.gpr[3] = tcp->u_error;
 	ppc_regs.ccr |= 0x10000000;
-#ifdef HAVE_GETREGS_OLD
 	return upoke(tcp, sizeof(long) * PT_CCR, ppc_regs.ccr) ||
 	       upoke(tcp, sizeof(long) * (PT_R0 + 3), ppc_regs.gpr[3]);
-#else
-	return set_regs(tcp->pid);
-#endif
 }
 
 static int
@@ -16,10 +12,6 @@ arch_set_success(struct tcb *tcp)
 {
 	ppc_regs.gpr[3] = tcp->u_rval;
 	ppc_regs.ccr &= ~0x10000000;
-#ifdef HAVE_GETREGS_OLD
 	return upoke(tcp, sizeof(long) * PT_CCR, ppc_regs.ccr) ||
 	       upoke(tcp, sizeof(long) * (PT_R0 + 3), ppc_regs.gpr[3]);
-#else
-	return set_regs(tcp->pid);
-#endif
 }
diff --git a/linux/powerpc/set_scno.c b/linux/powerpc/set_scno.c
index b2f66934..f00ef238 100644
--- a/linux/powerpc/set_scno.c
+++ b/linux/powerpc/set_scno.c
@@ -1,10 +1,5 @@
 static int
 arch_set_scno(struct tcb *tcp, kernel_ulong_t scno)
 {
-#ifdef HAVE_GETREGS_OLD
 	return upoke(tcp, sizeof(long) * PT_R0, scno);
-#else
-	ppc_regs.gpr[0] = scno;
-	return set_regs(tcp->pid);
-#endif
 }
diff --git a/linux/x86_64/arch_regs.c b/linux/x86_64/arch_regs.c
index ac719b6b..5775bcfa 100644
--- a/linux/x86_64/arch_regs.c
+++ b/linux/x86_64/arch_regs.c
@@ -40,3 +40,6 @@ static struct iovec x86_io = {
 	(x86_io.iov_len == sizeof(i386_regs) ? i386_regs.eip : x86_64_regs.rip)
 #define ARCH_SP_REG \
 	(x86_io.iov_len == sizeof(i386_regs) ? i386_regs.esp : x86_64_regs.rsp)
+
+#undef ARCH_MIGHT_USE_SET_REGS
+#define ARCH_MIGHT_USE_SET_REGS 0
diff --git a/linux/x86_64/set_error.c b/linux/x86_64/set_error.c
index 0c7e188c..edcf1855 100644
--- a/linux/x86_64/set_error.c
+++ b/linux/x86_64/set_error.c
@@ -1,49 +1,25 @@
-#ifndef HAVE_GETREGS_OLD
-# define arch_set_error i386_set_error
-# define arch_set_success i386_set_success
-# include "i386/set_error.c"
-# undef arch_set_success
-# undef arch_set_error
-#endif /* !HAVE_GETREGS_OLD */
-
 static int
 arch_set_error(struct tcb *tcp)
 {
-#ifdef HAVE_GETREGS_OLD
-	kernel_ulong_t	rval = -(kernel_long_t) tcp->u_error;
+	kernel_ulong_t	rval = -(long) tcp->u_error;
 
-	if (x86_io.iov_len == sizeof(i386_regs))
+	if (tcp->currpers == 1)
 		i386_regs.eax = rval;
 	else
 		x86_64_regs.rax = rval;
 
 	return upoke(tcp, 8 * RAX, rval);
-#else
-	if (x86_io.iov_len == sizeof(i386_regs))
-		return i386_set_error(tcp);
-
-	x86_64_regs.rax = -(kernel_long_t) tcp->u_error;
-	return set_regs(tcp->pid);
-#endif
 }
 
 static int
 arch_set_success(struct tcb *tcp)
 {
-#ifdef HAVE_GETREGS_OLD
 	kernel_ulong_t  rval = (kernel_ulong_t) tcp->u_rval;
 
-	if (x86_io.iov_len == sizeof(i386_regs))
+	if (tcp->currpers == 1)
 		i386_regs.eax = rval;
 	else
 		x86_64_regs.rax = rval;
 
 	return upoke(tcp, 8 * RAX, rval);
-#else
-	if (x86_io.iov_len == sizeof(i386_regs))
-		return i386_set_success(tcp);
-
-	x86_64_regs.rax = (kernel_ulong_t) tcp->u_rval;
-	return set_regs(tcp->pid);
-#endif
 }
diff --git a/linux/x86_64/set_scno.c b/linux/x86_64/set_scno.c
index 3ca402eb..0e620af8 100644
--- a/linux/x86_64/set_scno.c
+++ b/linux/x86_64/set_scno.c
@@ -1,19 +1,5 @@
-#ifndef HAVE_GETREGS_OLD
-# define arch_set_scno i386_set_scno
-# include "i386/set_scno.c"
-# undef arch_set_scno
-#endif /* !HAVE_GETREGS_OLD */
-
 static int
 arch_set_scno(struct tcb *tcp, kernel_ulong_t scno)
 {
-#ifdef HAVE_GETREGS_OLD
 	return upoke(tcp, 8 * ORIG_RAX, scno);
-#else
-	if (x86_io.iov_len == sizeof(i386_regs))
-		return i386_set_scno(tcp, scno);
-
-	x86_64_regs.orig_rax = scno;
-	return set_regs(tcp->pid);
-#endif
 }
diff --git a/syscall.c b/syscall.c
index a0902eca..6b118b61 100644
--- a/syscall.c
+++ b/syscall.c
@@ -967,6 +967,7 @@ restore_cleared_syserror(struct tcb *tcp)
 # include "xlat/nt_descriptor_types.h"
 #undef XLAT_MACROS_ONLY
 
+#define ARCH_MIGHT_USE_SET_REGS 1
 #include "arch_regs.c"
 
 #if HAVE_ARCH_GETRVAL2
@@ -974,6 +975,11 @@ restore_cleared_syserror(struct tcb *tcp)
 #endif
 
 #include "getregs_old.h"
+#ifdef HAVE_GETREGS_OLD
+/* Either getregs_old() or set_regs() */
+# undef ARCH_MIGHT_USE_SET_REGS
+# define ARCH_MIGHT_USE_SET_REGS 0
+#endif
 
 #undef ptrace_getregset_or_getregs
 #undef ptrace_setregset_or_setregs
@@ -999,7 +1005,7 @@ ptrace_getregset(pid_t pid)
 # endif
 }
 
-# ifndef HAVE_GETREGS_OLD
+# if ARCH_MIGHT_USE_SET_REGS
 #  define ptrace_setregset_or_setregs ptrace_setregset
 static int
 ptrace_setregset(pid_t pid)
@@ -1017,7 +1023,7 @@ ptrace_setregset(pid_t pid)
 	return ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &io);
 #  endif
 }
-# endif /* !HAVE_GETREGS_OLD */
+# endif /* ARCH_MIGHT_USE_SET_REGS */
 
 #elif defined ARCH_REGS_FOR_GETREGS
 
@@ -1033,7 +1039,7 @@ ptrace_getregs(pid_t pid)
 # endif
 }
 
-# ifndef HAVE_GETREGS_OLD
+# if ARCH_MIGHT_USE_SET_REGS
 #  define ptrace_setregset_or_setregs ptrace_setregs
 static int
 ptrace_setregs(pid_t pid)
@@ -1045,7 +1051,7 @@ ptrace_setregs(pid_t pid)
 	return ptrace(PTRACE_SETREGS, pid, NULL, &ARCH_REGS_FOR_GETREGS);
 #  endif
 }
-# endif /* !HAVE_GETREGS_OLD */
+# endif /* ARCH_MIGHT_USE_SET_REGS */
 
 #endif /* ARCH_REGS_FOR_GETREGSET || ARCH_REGS_FOR_GETREGS */
 
-- 
2.40.0