pts/seccomp: MIPS register access

MIPS PTRACE_GETREGSET returns an array of register values. Define
ARCH_REGS to reflect this and use the offsets defined in asm/regs.h
to access it.

Incorporates some additional changes from lkml.org patch by Matt
Redfearn (https://lkml.org/lkml/2016/3/29/184):
- support the O32 syscall which passes the real syscall number in a0.
- Because SYSCALL_NUM and SYSCALL_RET are the same register, it is not
  possible to test modifying the syscall return value when skipping,
  since both would need to set the same register. Therefore modify that
  test case to just detect the skipped test.

Bug: 27484186
Change-Id: I066b01a271bc8f2eecab5e3adb5aa2117fcf5b86
diff --git a/pts/seccomp/seccomp_bpf.c b/pts/seccomp/seccomp_bpf.c
index f7c28f3..dfe30b3 100644
--- a/pts/seccomp/seccomp_bpf.c
+++ b/pts/seccomp/seccomp_bpf.c
@@ -1216,9 +1216,15 @@
 # define SYSCALL_NUM   gprs[2]
 # define SYSCALL_RET   gprs[2]
 #elif defined(__mips__)
-# define ARCH_REGS     struct pt_regs
-# define SYSCALL_NUM   regs[2]
-# define SYSCALL_RET   regs[2]
+#include <asm/reg.h>
+typedef struct {
+        unsigned long regs[EF_SIZE/sizeof(unsigned long)];
+} user_regs;
+# define ARCH_REGS user_regs
+# define SYSCALL_NUM   regs[EF_R2]
+# define SYSCALL_RET   regs[EF_R2]
+# define SYSCALL_SYSCALL_NUM regs[EF_R4]
+# define SYSCALL_NUM_RET_SHARE_REG
 #else
 # error "Do not know how to find your architecture's registers and syscalls"
 #endif
@@ -1236,6 +1242,10 @@
 		return -1;
 	}
 
+#if defined(__mips__)
+	if (regs.SYSCALL_NUM == __NR_O32_Linux)
+		return regs.SYSCALL_SYSCALL_NUM;
+#endif
 	return regs.SYSCALL_NUM;
 }
 
@@ -1257,6 +1267,13 @@
 	{
 		regs.SYSCALL_NUM = syscall;
 	}
+#elif defined(__mips__)
+	{
+		if (regs.SYSCALL_NUM == __NR_O32_Linux)
+			regs.SYSCALL_SYSCALL_NUM = syscall;
+		else
+			regs.SYSCALL_NUM = syscall;
+	}
 
 #elif defined(__arm__)
 # ifndef PTRACE_SET_SYSCALL
@@ -1287,7 +1304,11 @@
 
 	/* If syscall is skipped, change return value. */
 	if (syscall == -1)
+#ifdef SYSCALL_NUM_RET_SHARE_REG
+		TH_LOG("Can't modify syscall return on this architecture");
+#else
 		regs.SYSCALL_RET = 1;
+#endif
 
 	iov.iov_base = &regs;
 	iov.iov_len = sizeof(regs);
@@ -1421,8 +1442,13 @@
 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog, 0, 0);
 	ASSERT_EQ(0, ret);
 
+#ifdef SYSCALL_NUM_RET_SHARE_REG
+	/* gettid has been skipped */
+	EXPECT_EQ(-1, syscall(__NR_gettid));
+#else
 	/* gettid has been skipped and an altered return value stored. */
 	EXPECT_EQ(1, syscall(__NR_gettid));
+#endif
 	EXPECT_NE(self->mytid, syscall(__NR_gettid));
 }