Add support for tracing 32-bit ARM EABI binaries on AArch64

* defs.h [AARCH64]: Copy in the definition of arm_pt_regs and the
accessor macros, so it's possible to build on AArch64 without
ARM system headers.  Set SUPPORTED_PERSONALITIES to 2.
Define PERSONALITY0_WORDSIZE and PERSONALITY1_WORDSIZE.
Set DEFAULT_PERSONALITY to 1.
* linux/aarch64/errnoent1.h: New file, includes generic errnoent.h.
* linux/aarch64/ioctlent1.h: New file, includes generic ioctlent.h.
* linux/aarch64/signalent1.h: New file, includes generic signalent.h.
* linux/aarch64/syscallent1.h: Rename from linux/aarch64/syscallent.h.
* linux/aarch64/syscallent.h: New file, includes arm/syscallent.h.
* syscall.c [AARCH64]: Define aarch64_regs.
(update_personality) [AARCH64]: Add debug output.
(get_scno) [AARCH64]: Determine if we're in ARM or AArch64 mode by
checking the size of the returned uio structure from PTRACE_GETREGSET
and interpret the structure accordingly.
(get_syscall_result): Likewise.
(get_syscall_args): Merge the AArch64 and ARM sections so that on
AArch64 we can fall back to supporting the ARM personality.
(get_error): Likewise.

Signed-off-by: Steve McIntyre <steve.mcintyre@linaro.org>
diff --git a/syscall.c b/syscall.c
index 680cbc3..69eceed 100644
--- a/syscall.c
+++ b/syscall.c
@@ -287,6 +287,12 @@
 		fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
 			tcp->pid, names[personality]);
 	}
+# elif defined(AARCH64)
+	if (!qflag) {
+		static const char *const names[] = {"32-bit ARM", "AArch64"};
+		fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
+			tcp->pid, names[personality]);
+	}
 # endif
 }
 #endif
@@ -664,7 +670,8 @@
 #elif defined(ARM)
 static struct pt_regs regs;
 #elif defined(AARCH64)
-static struct user_pt_regs regs;
+static struct user_pt_regs aarch64_regs;
+static struct arm_pt_regs regs;
 #elif defined(ALPHA)
 static long r0;
 static long a3;
@@ -916,6 +923,29 @@
 		if (upeek(tcp, PT_R15, &scno) < 0)
 			return -1;
 	}
+#elif defined(AARCH64)
+	struct iovec io;
+	char buf[sizeof(aarch64_regs)];
+	io.iov_base = &buf;
+	io.iov_len = sizeof(aarch64_regs);
+	if (ptrace(PTRACE_GETREGSET, tcp->pid, NT_PRSTATUS, (void *)&io) == -1)
+		return -1;
+	switch (io.iov_len) {
+		case sizeof(aarch64_regs):
+			/* We are in 64-bit mode */
+			memcpy(&aarch64_regs, buf, sizeof(aarch64_regs));
+			scno = aarch64_regs.regs[8];
+			update_personality(tcp, 1);
+			break;
+		case sizeof(regs):
+			/* We are in 32-bit mode */
+			memcpy(&regs, buf, sizeof(regs));
+			scno = regs.uregs[7];
+			update_personality(tcp, 0);
+			break;
+		default:
+			return -1;
+	}
 #elif defined(ARM)
 	/* Read complete register set in one go. */
 	if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
@@ -975,13 +1005,6 @@
 		fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
 		tcp->flags |= TCB_INSYSCALL;
 	}
-#elif defined(AARCH64)
-	struct iovec io;
-	io.iov_base = &regs;
-	io.iov_len = sizeof(regs);
-	if (ptrace(PTRACE_GETREGSET, tcp->pid, NT_PRSTATUS, (void *)&io) == -1)
-		return -1;
-	scno = regs.regs[8];
 #elif defined(M68K)
 	if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
 		return -1;
@@ -1415,12 +1438,15 @@
 	for (i = 0; i < nargs; ++i)
 		if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
 			return -1;
-#elif defined(ARM)
+#elif defined(ARM) || defined(AARCH64)
+# if defined(AARCH64)
+	if (tcp->currpers == 1)
+		for (i = 0; i < nargs; ++i)
+			tcp->u_arg[i] = aarch64_regs.regs[i];
+	else
+# endif /* AARCH64 */
 	for (i = 0; i < nargs; ++i)
 		tcp->u_arg[i] = regs.uregs[i];
-#elif defined(AARCH64)
-	for (i = 0; i < nargs; ++i)
-		tcp->u_arg[i] = regs.regs[i];
 #elif defined(AVR32)
 	(void)i;
 	(void)nargs;
@@ -1655,16 +1681,31 @@
 		return -1;
 	if (upeek(tcp, PT_R10, &r10) < 0)
 		return -1;
-#elif defined(ARM)
-	/* Read complete register set in one go. */
-	if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
-		return -1;
 #elif defined(AARCH64)
 	struct iovec io;
-	io.iov_base = &regs;
-	io.iov_len = sizeof(regs);
+	char buf[sizeof(aarch64_regs)];
+	io.iov_base = &buf;
+	io.iov_len = sizeof(aarch64_regs);
 	if (ptrace(PTRACE_GETREGSET, tcp->pid, NT_PRSTATUS, (void *)&io) == -1)
 		return -1;
+	switch (io.iov_len) {
+		case sizeof(aarch64_regs):
+			/* We are in 64-bit mode */
+			memcpy(&aarch64_regs, buf, sizeof(aarch64_regs));
+			update_personality(tcp, 1);
+			break;
+		case sizeof(regs):
+			/* We are in 32-bit mode */
+			memcpy(&regs, buf, sizeof(regs));
+			update_personality(tcp, 0);
+			break;
+		default:
+			return -1;
+	}
+#elif defined(ARM)
+	/* Read complete ARM register set in one go. */
+	if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
+		return -1;
 #elif defined(M68K)
 	if (upeek(tcp, 4*PT_D0, &d0) < 0)
 		return -1;
@@ -1839,21 +1880,27 @@
 	else {
 		tcp->u_rval = d0;
 	}
-#elif defined(ARM)
-	if (check_errno && is_negated_errno(regs.ARM_r0)) {
-		tcp->u_rval = -1;
-		u_error = -regs.ARM_r0;
+#elif defined(ARM) || defined(AARCH64)
+# if defined(AARCH64)
+	if (tcp->currpers == 1) {
+		if (check_errno && is_negated_errno(aarch64_regs.regs[0])) {
+			tcp->u_rval = -1;
+			u_error = -aarch64_regs.regs[0];
+		}
+		else {
+			tcp->u_rval = aarch64_regs.regs[0];
+		}
 	}
-	else {
-		tcp->u_rval = regs.ARM_r0;
-	}
-#elif defined(AARCH64)
-	if (check_errno && is_negated_errno(regs.regs[0])) {
-		tcp->u_rval = -1;
-		u_error = -regs.regs[0];
-	}
-	else {
-		tcp->u_rval = regs.regs[0];
+	else
+# endif /* AARCH64 */
+	{
+		if (check_errno && is_negated_errno(regs.ARM_r0)) {
+			tcp->u_rval = -1;
+			u_error = -regs.ARM_r0;
+		}
+		else {
+			tcp->u_rval = regs.ARM_r0;
+		}
 	}
 #elif defined(AVR32)
 	if (check_errno && regs.r12 && (unsigned) -regs.r12 < nerrnos) {