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(®s, 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 *)®s) == -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 = ®s;
- 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 *)®s) == -1)
- return -1;
#elif defined(AARCH64)
struct iovec io;
- io.iov_base = ®s;
- 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(®s, 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 *)®s) == -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) {