diff mbox

Update AArch64 strace to also support tracing 32-bit ARM binaries

Message ID 20121110112441.GB9328@einval.com
State New
Headers show

Commit Message

Steve McIntyre Nov. 10, 2012, 11:24 a.m. UTC
On Sat, Nov 10, 2012 at 12:20:34AM -0500, Mike Frysinger wrote:
>On Thursday 08 November 2012 12:36:05 Steve McIntyre wrote:
>> The patch looks big due to renaming/moving
>> linux/aarch64/syscallent.h to linux/aarch64/syscallent2.h.
>
>you can use the -C -M flags so that the git patch shows the rename.  `git am` 
>will apply it correctly (as will patch-2.6.1+).

Ah, yes. Thanks. :-) It's reduced the size slightly now by picking up
the copy, but obviously is still showing the change in syscallent.h to
move to including the ARM header.

>> To reduce build-time complexity, I've copied in the arm_pt_regs def
>> from the ARM system headers; I don't know if people are happy with
>> that. Otherwise, building on AArch64 is likely to get harder. :-/
>
>the defs.h logic looks pretty well self-contained.  usually bi-arch systems 
>have a structure that magically works, but considering aarch64 is basically a 
>new isa, i can see why that isn't happening here.  plus, as i'm sure you've 
>already seen in defs.h, other arches have done similar (if not worse) things.

Cool. I thought it was worth flagging.

>> --- a/syscall.c
>> +++ b/syscall.c
>>
>> +	switch(io.iov_len)
>> +	{
>
>cuddle that brace up and add a space before the paren:
>	switch (io.iov_len) {

ACK.

>> +		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, 2);
>> +			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;
>
>i see personality 2 and 0 here, but unless i missed some merged code, i don't 
>see any setup of personality 1 ...

True. I've dropped out personality#1 and shifted things down.

>> +	switch(io.iov_len)
>> +	{
>
>same style issue here

Yup.

>> +	if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)&regs) == -1)
>> +	{
>> +		return -1;
>> +	}
>
>drop the braces

Done.

Here's the updated patch. Thanks for the quick review.

Comments

Dmitry V. Levin Nov. 12, 2012, 3:54 p.m. UTC | #1
On Sat, Nov 10, 2012 at 11:24:48AM +0000, Steve McIntyre wrote:
> On Sat, Nov 10, 2012 at 12:20:34AM -0500, Mike Frysinger wrote:
> >On Thursday 08 November 2012 12:36:05 Steve McIntyre wrote:
[...]
> Here's the updated patch. Thanks for the quick review.

Applied (with trailing whitespaces removed), thanks.
Denys Vlasenko Feb. 5, 2013, 2:40 p.m. UTC | #2
On 11/10/2012 12:24 PM, Steve McIntyre wrote:
>  #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;
> +	}

You can eliminate buf[] and one memcpy if you'll set io.iov_base = aarch64_regs.
Denys Vlasenko Feb. 5, 2013, 4:02 p.m. UTC | #3
On 11/10/2012 12:24 PM, Steve McIntyre wrote:
> @@ -916,6 +923,29 @@ get_scno(struct tcb *tcp)
>  		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)

You check and set personality in get_scno(). Ok.


> @@ -1655,16 +1681,31 @@ get_syscall_result(struct tcb *tcp)
>  		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;
> +	}

No other architecture calls update_personality() on syscall exit
(get_syscall_result() is called, naturally, only on exit).

I think these update_personality() calls can be safely removed.
Steve McIntyre Feb. 12, 2013, 1:45 p.m. UTC | #4
On Tue, Feb 05, 2013 at 03:40:33PM +0100, Denys Vlasenko wrote:
>On 11/10/2012 12:24 PM, Steve McIntyre wrote:
>>  #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;
>> +	}
>
>You can eliminate buf[] and one memcpy if you'll set io.iov_base = aarch64_regs.

True, yes.

Cheers,
Steve McIntyre Feb. 12, 2013, 1:47 p.m. UTC | #5
On Tue, Feb 05, 2013 at 05:02:34PM +0100, Denys Vlasenko wrote:
>> @@ -1655,16 +1681,31 @@ get_syscall_result(struct tcb *tcp)
>>  		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;
>> +	}
>
>No other architecture calls update_personality() on syscall exit
>(get_syscall_result() is called, naturally, only on exit).
>
>I think these update_personality() calls can be safely removed.

Hmmm, maybe. I've possibly got a belt-and-braces solution there. It
made sense to me at the time, but that was quite a while ago now. :-)

Cheers,
diff mbox

Patch

====================================================================

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

* linux/aarch64/*.h: Include the existing ARM EABI personality, move
the AArch64 personality to #1 and make it the default.

* defs.h: Copy in the definition of arm_pt_regs and the accessor
macros, so it's possible to build on AArch64 without needing ARM
system headers. Include the existing ARM personality.

* syscall.c: (update_personality) Add debug output for AArch64.
(get_scno): On 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>
---
 defs.h                                        |   34 +++
 linux/{powerpc => aarch64}/errnoent1.h        |    1 +
 linux/aarch64/ioctlent1.h                     |    1 +
 linux/{powerpc => aarch64}/signalent1.h       |    0
 linux/aarch64/syscallent.h                    |  331 +------------------------
 linux/aarch64/{syscallent.h => syscallent1.h} |    0
 syscall.c                                     |  111 ++++++---
 7 files changed, 116 insertions(+), 362 deletions(-)
 copy linux/{powerpc => aarch64}/errnoent1.h (54%)
 create mode 100644 linux/aarch64/ioctlent1.h
 copy linux/{powerpc => aarch64}/signalent1.h (100%)
 copy linux/aarch64/{syscallent.h => syscallent1.h} (100%)

diff --git a/defs.h b/defs.h
index 11e26bb..0e05c6e 100644
--- a/defs.h
+++ b/defs.h
@@ -196,6 +196,30 @@  extern long ptrace(int, int, char *, long);
 # define REG_PC             (0*8)
 # define REG_SYSCALL        (2*8)
 #endif /* SH64 */
+#ifdef AARCH64
+#define NUM_ARM_REGS 18
+struct arm_pt_regs {
+        int uregs[NUM_ARM_REGS];
+};
+#define ARM_cpsr        uregs[16]
+#define ARM_pc          uregs[15]
+#define ARM_lr          uregs[14]
+#define ARM_sp          uregs[13]
+#define ARM_ip          uregs[12]
+#define ARM_fp          uregs[11]
+#define ARM_r10         uregs[10]
+#define ARM_r9          uregs[9]
+#define ARM_r8          uregs[8]
+#define ARM_r7          uregs[7]
+#define ARM_r6          uregs[6]
+#define ARM_r5          uregs[5]
+#define ARM_r4          uregs[4]
+#define ARM_r3          uregs[3]
+#define ARM_r2          uregs[2]
+#define ARM_r1          uregs[1]
+#define ARM_r0          uregs[0]
+#define ARM_ORIG_r0     uregs[17]
+#endif /* AARCH64 */
 
 #define SUPPORTED_PERSONALITIES 1
 #define DEFAULT_PERSONALITY 0
@@ -241,6 +265,16 @@  extern long ptrace(int, int, char *, long);
 # define PERSONALITY1_WORDSIZE 4
 #endif
 
+#ifdef AARCH64
+# undef SUPPORTED_PERSONALITIES
+/* The existing ARM personality, then AArch64 */
+# define SUPPORTED_PERSONALITIES 2
+# define PERSONALITY0_WORDSIZE 4
+# define PERSONALITY1_WORDSIZE 8
+# undef DEFAULT_PERSONALITY
+# define DEFAULT_PERSONALITY 1
+#endif
+
 #ifdef POWERPC64
 # undef SUPPORTED_PERSONALITIES
 # define SUPPORTED_PERSONALITIES 2
diff --git a/linux/powerpc/errnoent1.h b/linux/aarch64/errnoent1.h
similarity index 54%
copy from linux/powerpc/errnoent1.h
copy to linux/aarch64/errnoent1.h
index 441c66b..e1cbe33 100644
--- a/linux/powerpc/errnoent1.h
+++ b/linux/aarch64/errnoent1.h
@@ -1 +1,2 @@ 
+/* Native AArch64 */
 #include "../errnoent.h"
diff --git a/linux/aarch64/ioctlent1.h b/linux/aarch64/ioctlent1.h
new file mode 100644
index 0000000..df485d3
--- /dev/null
+++ b/linux/aarch64/ioctlent1.h
@@ -0,0 +1 @@ 
+#include "../ioctlent.h"
diff --git a/linux/powerpc/signalent1.h b/linux/aarch64/signalent1.h
similarity index 100%
copy from linux/powerpc/signalent1.h
copy to linux/aarch64/signalent1.h
diff --git a/linux/aarch64/syscallent.h b/linux/aarch64/syscallent.h
index b712c9f..1b892be 100644
--- a/linux/aarch64/syscallent.h
+++ b/linux/aarch64/syscallent.h
@@ -1,330 +1 @@ 
-	{ 2,	0,	sys_io_setup,			"io_setup"			}, /*    0 */
-	{ 1,	0,	sys_io_destroy,			"io_destroy"			}, /*    1 */
-	{ 3,	0,	sys_io_submit,			"io_submit"			}, /*    2 */
-	{ 3,	0,	sys_io_cancel,			"io_cancel"			}, /*    3 */
-	{ 5,	0,	sys_io_getevents,		"io_getevents"			}, /*    4 */
-	{ 5,	TF,	sys_setxattr,			"setxattr"			}, /*    5 */
-	{ 5,	TF,	sys_setxattr,			"lsetxattr"			}, /*    6 */
-	{ 5,	TD,	sys_fsetxattr,			"fsetxattr"			}, /*    7 */
-	{ 4,	TF,	sys_getxattr,			"getxattr"			}, /*    8 */
-	{ 4,	TF,	sys_getxattr,			"lgetxattr"			}, /*    9 */
-	{ 4,	TD,	sys_fgetxattr,			"fgetxattr"			}, /*   10 */
-	{ 3,	TF,	sys_listxattr,			"listxattr"			}, /*   11 */
-	{ 3,	TF,	sys_listxattr,			"llistxattr"			}, /*   12 */
-	{ 3,	TD,	sys_flistxattr,			"flistxattr"			}, /*   13 */
-	{ 2,	TF,	sys_removexattr,		"removexattr"			}, /*   14 */
-	{ 2,	TF,	sys_removexattr,		"lremovexattr"			}, /*   15 */
-	{ 2,	TD,	sys_fremovexattr,		"fremovexattr"			}, /*   16 */
-	{ 2,	TF,	sys_getcwd,			"getcwd"			}, /*   17 */
-	{ 4,	0,	sys_lookup_dcookie,		"lookup_dcookie"		}, /*   18 */
-	{ 2,	TD,	sys_eventfd2,			"eventfd2"			}, /*   19 */
-	{ 1,	TD,	sys_epoll_create1,		"epoll_create1"			}, /*   20 */
-	{ 4,	TD,	sys_epoll_ctl,			"epoll_ctl"			}, /*   21 */
-	{ 6,	TD,	sys_epoll_pwait,		"epoll_pwait"			}, /*   22 */
-	{ 1,	TD,	sys_dup,			"dup"				}, /*   23 */
-	{ 3,	TD,	sys_dup3,			"dup3"				}, /*   24 */
-	{ 3,	TD,	sys_fcntl,			"fcntl"				}, /*   25 */
-	{ 1,	TD,	sys_inotify_init1,		"inotify_init1"			}, /*   26 */
-	{ 3,	TD,	sys_inotify_add_watch,		"inotify_add_watch"		}, /*   27 */
-	{ 2,	TD,	sys_inotify_rm_watch,		"inotify_rm_watch"		}, /*   28 */
-	{ 3,	TD,	sys_ioctl,			"ioctl"				}, /*   29 */
-	{ 3,	0,	sys_ioprio_set,			"ioprio_set"			}, /*   30 */
-	{ 2,	0,	sys_ioprio_get,			"ioprio_get"			}, /*   31 */
-	{ 2,	TD,	sys_flock,			"flock"				}, /*   32 */
-	{ 4,	TD|TF,	sys_mknodat,			"mknodat"			}, /*   33 */
-	{ 3,	TD|TF,	sys_mkdirat,			"mkdirat"			}, /*   34 */
-	{ 3,	TD|TF,	sys_unlinkat,			"unlinkat"			}, /*   35 */
-	{ 3,	TD|TF,	sys_symlinkat,			"symlinkat"			}, /*   36 */
-	{ 5,	TD|TF,	sys_linkat,			"linkat"			}, /*   37 */
-	{ 4,	TD|TF,	sys_renameat,			"renameat"			}, /*   38 */
-	{ 2,	TF,	sys_umount2,			"umount2"			}, /*   39 */
-	{ 5,	TF,	sys_mount,			"mount"				}, /*   40 */
-	{ 2,	TF,	sys_pivotroot,			"pivot_root"			}, /*   41 */
-	{ 3,	0,	sys_nfsservctl,			"nfsservctl"			}, /*   42 */
-	{ 2,	TF,	sys_statfs,			"statfs64"			}, /*   43 */
-	{ 2,	TD,	sys_fstatfs,			"fstatfs64"			}, /*   44 */
-	{ 2,	TF,	sys_truncate,			"truncate64"			}, /*   45 */
-	{ 2,	TD,	sys_ftruncate,			"ftruncate64"			}, /*   46 */
-	{ 6,	TD,	sys_fallocate,			"fallocate"			}, /*   47 */
-	{ 3,	TD|TF,	sys_faccessat,			"faccessat"			}, /*   48 */
-	{ 1,	TF,	sys_chdir,			"chdir"				}, /*   49 */
-	{ 1,	TD,	sys_fchdir,			"fchdir"			}, /*   50 */
-	{ 1,	TF,	sys_chroot,			"chroot"			}, /*   51 */
-	{ 2,	TD,	sys_fchmod,			"fchmod"			}, /*   52 */
-	{ 3,	TD|TF,	sys_fchmodat,			"fchmodat"			}, /*   53 */
-	{ 5,	TD|TF,	sys_fchownat,			"fchownat"			}, /*   54 */
-	{ 3,	TD,	sys_fchown,			"fchown"			}, /*   55 */
-	{ 4,	TD|TF,	sys_openat,			"openat"			}, /*   56 */
-	{ 1,	TD,	sys_close,			"close"				}, /*   57 */
-	{ 0,	0,	sys_vhangup,			"vhangup"			}, /*   58 */
-	{ 2,	TD,	sys_pipe2,			"pipe2"				}, /*   59 */
-	{ 4,	TF,	sys_quotactl,			"quotactl"			}, /*   60 */
-	{ 3,	TD,	sys_getdents64,			"getdents64"			}, /*   61 */
-	{ 3,	TD,	sys_lseek,			"lseek"				}, /*   62 */
-	{ 3,	TD,	sys_read,			"read"				}, /*   63 */
-	{ 3,	TD,	sys_write,			"write"				}, /*   64 */
-	{ 3,	TD,	sys_readv,			"readv"				}, /*   65 */
-	{ 3,	TD,	sys_writev,			"writev"			}, /*   66 */
-	{ 5,	TD,	sys_pread,			"pread64"			}, /*   67 */
-	{ 5,	TD,	sys_pwrite,			"pwrite64"			}, /*   68 */
-	{ 5,	TD,	sys_preadv,			"preadv"			}, /*   69 */
-	{ 5,	TD,	sys_pwritev,			"pwritev"			}, /*   70 */
-	{ 4,	TD|TN,	sys_sendfile,			"sendfile"			}, /*   71 */
-	{ 6,	TD,	sys_pselect6,			"pselect6"			}, /*   72 */
-	{ 5,	TD,	sys_ppoll,			"ppoll"				}, /*   73 */
-	{ 4,	TD|TS,	sys_signalfd4,			"signalfd4"			}, /*   74 */
-	{ 4,	TD,	sys_vmsplice,			"vmsplice"			}, /*   75 */
-	{ 6,	TD,	sys_splice,			"splice"			}, /*   76 */
-	{ 4,	TD,	sys_tee,			"tee"				}, /*   77 */
-	{ 4,	TD|TF,	sys_readlinkat,			"readlinkat"			}, /*   78 */
-	{ 4,	TD|TF,	sys_newfstatat,			"newfstatat"			}, /*   79 */
-	{ 2,	TD,	sys_fstat,			"fstat"				}, /*   80 */
-	{ 0,	0,	sys_sync,			"sync"				}, /*   81 */
-	{ 1,	TD,	sys_fsync,			"fsync"				}, /*   82 */
-	{ 1,	TD,	sys_fdatasync,			"fdatasync"			}, /*   83 */
-	{ 4,	TD,	sys_sync_file_range,		"sync_file_range"		}, /*   84 */
-	{ 2,	TD,	sys_timerfd_create,		"timerfd_create"		}, /*   85 */
-	{ 4,	TD,	sys_timerfd_settime,		"timerfd_settime"		}, /*   86 */
-	{ 2,	TD,	sys_timerfd_gettime,		"timerfd_gettime"		}, /*   87 */
-	{ 4,	TD|TF,	sys_utimensat,			"utimensat"			}, /*   88 */
-	{ 1,	TF,	sys_acct,			"acct"				}, /*   89 */
-	{ 2,	0,	sys_capget,			"capget"			}, /*   90 */
-	{ 2,	0,	sys_capset,			"capset"			}, /*   91 */
-	{ 1,	0,	sys_personality,		"personality"			}, /*   92 */
-	{ 1,	TP,	sys_exit,			"exit"				}, /*   93 */
-	{ 1,	TP,	sys_exit,			"exit_group"			}, /*   94 */
-	{ 5,	TP,	sys_waitid,			"waitid"			}, /*   95 */
-	{ 1,	0,	sys_set_tid_address,		"set_tid_address"		}, /*   96 */
-	{ 1,	TP,	sys_unshare,			"unshare"			}, /*   97 */
-	{ 6,	0,	sys_futex,			"futex"				}, /*   98 */
-	{ 2,	0,	sys_set_robust_list,		"set_robust_list"		}, /*   99 */
-	{ 3,	0,	sys_get_robust_list,		"get_robust_list"		}, /*  100 */
-	{ 2,	0,	sys_nanosleep,			"nanosleep"			}, /*  101 */
-	{ 2,	0,	sys_getitimer,			"getitimer"			}, /*  102 */
-	{ 3,	0,	sys_setitimer,			"setitimer"			}, /*  103 */
-	{ 4,	0,	sys_kexec_load,			"kexec_load"			}, /*  104 */
-	{ 3,	0,	sys_init_module,		"init_module"			}, /*  105 */
-	{ 2,	0,	sys_delete_module,		"delete_module"			}, /*  106 */
-	{ 3,	0,	sys_timer_create,		"timer_create"			}, /*  107 */
-	{ 2,	0,	sys_timer_gettime,		"timer_gettime"			}, /*  108 */
-	{ 1,	0,	sys_timer_getoverrun,		"timer_getoverrun"		}, /*  109 */
-	{ 4,	0,	sys_timer_settime,		"timer_settime"			}, /*  110 */
-	{ 1,	0,	sys_timer_delete,		"timer_delete"			}, /*  111 */
-	{ 2,	0,	sys_clock_settime,		"clock_settime"			}, /*  112 */
-	{ 2,	0,	sys_clock_gettime,		"clock_gettime"			}, /*  113 */
-	{ 2,	0,	sys_clock_getres,		"clock_getres"			}, /*  114 */
-	{ 4,	0,	sys_clock_nanosleep,		"clock_nanosleep"		}, /*  115 */
-	{ 3,	0,	sys_syslog,			"syslog"			}, /*  116 */
-	{ 4,	0,	sys_ptrace,			"ptrace"			}, /*  117 */
-	{ 0,	0,	sys_sched_setparam,		"sched_setparam"		}, /*  118 */
-	{ 3,	0,	sys_sched_setscheduler,		"sched_setscheduler"		}, /*  119 */
-	{ 1,	0,	sys_sched_getscheduler,		"sched_getscheduler"		}, /*  120 */
-	{ 2,	0,	sys_sched_getparam,		"sched_getparam"		}, /*  121 */
-	{ 3,	0,	sys_sched_setaffinity,		"sched_setaffinity"		}, /*  122 */
-	{ 3,	0,	sys_sched_getaffinity,		"sched_getaffinity"		}, /*  123 */
-	{ 0,	0,	sys_sched_yield,		"sched_yield"			}, /*  124 */
-	{ 1,	0,	sys_sched_get_priority_max,	"sched_get_priority_max"	}, /*  125 */
-	{ 1,	0,	sys_sched_get_priority_min,	"sched_get_priority_min"	}, /*  126 */
-	{ 2,	0,	sys_sched_rr_get_interval,	"sched_rr_get_interval"		}, /*  127 */
-	{ 0,	0,	sys_restart_syscall,		"restart_syscall"		}, /*  128 */
-	{ 2,	TS,	sys_kill,			"kill"				}, /*  129 */
-	{ 2,	TS,	sys_kill,			"tkill"				}, /*  130 */
-	{ 3,	TS,	sys_tgkill,			"tgkill"			}, /*  131 */
-	{ 2,	TS,	sys_sigaltstack,		"sigaltstack"			}, /*  132 */
-	{ 2,	TS,	sys_rt_sigsuspend,		"rt_sigsuspend"			}, /*  133 */
-	{ 4,	TS,	sys_rt_sigaction,		"rt_sigaction"			}, /*  134 */
-	{ 4,	TS,	sys_rt_sigprocmask,		"rt_sigprocmask"		}, /*  135 */
-	{ 2,	TS,	sys_rt_sigpending,		"rt_sigpending"			}, /*  136 */
-	{ 4,	TS,	sys_rt_sigtimedwait,		"rt_sigtimedwait"		}, /*  137 */
-	{ 3,	TS,	sys_rt_sigqueueinfo,		"rt_sigqueueinfo"		}, /*  138 */
-	{ 0,	TS,	sys_rt_sigreturn,		"rt_sigreturn"			}, /*  139 */
-	{ 3,	0,	sys_setpriority,		"setpriority"			}, /*  140 */
-	{ 2,	0,	sys_getpriority,		"getpriority"			}, /*  141 */
-	{ 4,	0,	sys_reboot,			"reboot"			}, /*  142 */
-	{ 2,	0,	sys_setregid,			"setregid"			}, /*  143 */
-	{ 1,	0,	sys_setgid,			"setgid"			}, /*  144 */
-	{ 2,	0,	sys_setreuid,			"setreuid"			}, /*  145 */
-	{ 1,	0,	sys_setuid,			"setuid"			}, /*  146 */
-	{ 3,	0,	sys_setresuid,			"setresuid"			}, /*  147 */
-	{ 3,	0,	sys_getresuid,			"getresuid"			}, /*  148 */
-	{ 3,	0,	sys_setresgid,			"setresgid"			}, /*  149 */
-	{ 3,	0,	sys_getresgid,			"getresgid"			}, /*  150 */
-	{ 1,	NF,	sys_setfsuid,			"setfsuid"			}, /*  151 */
-	{ 1,	NF,	sys_setfsgid,			"setfsgid"			}, /*  152 */
-	{ 1,	0,	sys_times,			"times"				}, /*  153 */
-	{ 2,	0,	sys_setpgid,			"setpgid"			}, /*  154 */
-	{ 1,	0,	sys_getpgid,			"getpgid"			}, /*  155 */
-	{ 1,	0,	sys_getsid,			"getsid"			}, /*  156 */
-	{ 0,	0,	sys_setsid,			"setsid"			}, /*  157 */
-	{ 2,	0,	sys_getgroups,			"getgroups"			}, /*  158 */
-	{ 2,	0,	sys_setgroups,			"setgroups"			}, /*  159 */
-	{ 1,	0,	sys_uname,			"uname"				}, /*  160 */
-	{ 2,	0,	sys_sethostname,		"sethostname"			}, /*  161 */
-	{ 2,	0,	sys_setdomainname,		"setdomainname"			}, /*  162 */
-	{ 2,	0,	sys_getrlimit,			"getrlimit"			}, /*  163 */
-	{ 2,	0,	sys_setrlimit,			"setrlimit"			}, /*  164 */
-	{ 2,	0,	sys_getrusage,			"getrusage"			}, /*  165 */
-	{ 1,	0,	sys_umask,			"umask"				}, /*  166 */
-	{ 5,	0,	sys_prctl,			"prctl"				}, /*  167 */
-	{ 3,	0,	sys_getcpu,			"getcpu"			}, /*  168 */
-	{ 2,	0,	sys_gettimeofday,		"gettimeofday"			}, /*  169 */
-	{ 2,	0,	sys_settimeofday,		"settimeofday"			}, /*  170 */
-	{ 1,	0,	sys_adjtimex,			"adjtimex"			}, /*  171 */
-	{ 0,	0,	sys_getpid,			"getpid"			}, /*  172 */
-	{ 0,	0,	sys_getppid,			"getppid"			}, /*  173 */
-	{ 0,	NF,	sys_getuid,			"getuid"			}, /*  174 */
-	{ 0,	NF,	sys_geteuid,			"geteuid"			}, /*  175 */
-	{ 0,	NF,	sys_getgid,			"getgid"			}, /*  176 */
-	{ 0,	NF,	sys_getegid,			"getegid"			}, /*  177 */
-	{ 0,	0,	sys_gettid,			"gettid"			}, /*  178 */
-	{ 1,	0,	sys_sysinfo,			"sysinfo"			}, /*  179 */
-	{ 4,	0,	sys_mq_open,			"mq_open"			}, /*  180 */
-	{ 1,	0,	sys_mq_unlink,			"mq_unlink"			}, /*  181 */
-	{ 5,	0,	sys_mq_timedsend,		"mq_timedsend"			}, /*  182 */
-	{ 5,	0,	sys_mq_timedreceive,		"mq_timedreceive"		}, /*  183 */
-	{ 2,	0,	sys_mq_notify,			"mq_notify"			}, /*  184 */
-	{ 3,	0,	sys_mq_getsetattr,		"mq_getsetattr"			}, /*  185 */
-	{ 4,	TI,	sys_msgget,			"msgget"			}, /*  186 */
-	{ 3,	TI,	sys_msgctl,			"msgctl"			}, /*  187 */
-	{ 5,	TI,	sys_msgrcv,			"msgrcv"			}, /*  188 */
-	{ 4,	TI,	sys_msgsnd,			"msgsnd"			}, /*  189 */
-	{ 4,	TI,	sys_semget,			"semget"			}, /*  190 */
-	{ 4,	TI,	sys_semctl,			"semctl"			}, /*  191 */
-	{ 5,	TI,	sys_semtimedop,			"semtimedop"			}, /*  192 */
-	{ 4,	TI,	sys_semop,			"semop"				}, /*  193 */
-	{ 4,	TI,	sys_shmget,			"shmget"			}, /*  194 */
-	{ 4,	TI,	sys_shmctl,			"shmctl"			}, /*  195 */
-	{ 4,	TI,	sys_shmat,			"shmat"				}, /*  196 */
-	{ 4,	TI,	sys_shmdt,			"shmdt"				}, /*  197 */
-	{ 3,	TN,	sys_socket,			"socket"			}, /*  198 */
-	{ 4,	TN,	sys_socketpair,			"socketpair"			}, /*  199 */
-	{ 3,	TN,	sys_bind,			"bind"				}, /*  200 */
-	{ 2,	TN,	sys_listen,			"listen"			}, /*  201 */
-	{ 3,	TN,	sys_accept,			"accept"			}, /*  202 */
-	{ 3,	TN,	sys_connect,			"connect"			}, /*  203 */
-	{ 3,	TN,	sys_getsockname,		"getsockname"			}, /*  204 */
-	{ 3,	TN,	sys_getpeername,		"getpeername"			}, /*  205 */
-	{ 6,	TN,	sys_sendto,			"sendto"			}, /*  206 */
-	{ 6,	TN,	sys_recvfrom,			"recvfrom"			}, /*  207 */
-	{ 5,	TN,	sys_setsockopt,			"setsockopt"			}, /*  208 */
-	{ 5,	TN,	sys_getsockopt,			"getsockopt"			}, /*  209 */
-	{ 2,	TN,	sys_shutdown,			"shutdown"			}, /*  210 */
-	{ 3,	TN,	sys_sendmsg,			"sendmsg"			}, /*  211 */
-	{ 5,	TN,	sys_recvmsg,			"recvmsg"			}, /*  212 */
-	{ 4,	TD,	sys_readahead,			"readahead"			}, /*  213 */
-	{ 1,	TM,	sys_brk,			"brk"				}, /*  214 */
-	{ 2,	TM,	sys_munmap,			"munmap"			}, /*  215 */
-	{ 5,	TM,	sys_mremap,			"mremap"			}, /*  216 */
-	{ 5,	0,	sys_add_key,			"add_key"			}, /*  217 */
-	{ 4,	0,	sys_request_key,		"request_key"			}, /*  218 */
-	{ 5,	0,	sys_keyctl,			"keyctl"			}, /*  219 */
-	{ 5,	TP,	sys_clone,			"clone"				}, /*  220 */
-	{ 3,	TF|TP,	sys_execve,			"execve"			}, /*  221 */
-	{ 6,	TD|TM,	sys_mmap,			"mmap"				}, /*  222 */
-	{ 4,	TD,	sys_fadvise64,			"fadvise64"			}, /*  223 */
-	{ 2,	TF,	sys_swapon,			"swapon"			}, /*  224 */
-	{ 1,	TF,	sys_swapoff,			"swapoff"			}, /*  225 */
-	{ 3,	TM,	sys_mprotect,			"mprotect"			}, /*  226 */
-	{ 3,	TM,	sys_msync,			"msync"				}, /*  227 */
-	{ 3,	TM,	sys_msync,			"msync"				}, /*  228 */
-	{ 2,	TM,	sys_munlock,			"munlock"			}, /*  229 */
-	{ 1,	TM,	sys_mlockall,			"mlockall"			}, /*  230 */
-	{ 0,	TM,	sys_munlockall,			"munlockall"			}, /*  231 */
-	{ 3,	TM,	sys_mincore,			"mincore"			}, /*  232 */
-	{ 3,	TM,	sys_madvise,			"madvise"			}, /*  233 */
-	{ 5,	TM,	sys_remap_file_pages,		"remap_file_pages"		}, /*  234 */
-	{ 6,	TM,	sys_mbind,			"mbind"				}, /*  235 */
-	{ 5,	TM,	sys_get_mempolicy,		"get_mempolicy"			}, /*  236 */
-	{ 3,	TM,	sys_set_mempolicy,		"set_mempolicy"			}, /*  237 */
-	{ 4,	TM,	sys_migrate_pages,		"migrate_pages"			}, /*  238 */
-	{ 6,	TM,	sys_move_pages,			"move_pages"			}, /*  239 */
-	{ 4,	TP|TS,	sys_rt_tgsigqueueinfo,		"rt_tgsigqueueinfo"		}, /*  240 */
-	{ 5,	TD,	sys_perf_event_open,		"perf_event_open"		}, /*  241 */
-	{ 4,	TN,	sys_accept4,			"accept4"			}, /*  242 */
-	{ 5,	TN,	sys_recvmmsg,			"recvmmsg"			}, /*  243 */
-
-	/* Arch-specific block, not used on AArch64 */
-	[244 ... 259] = { },
-
-	{ 4,	TP,	sys_wait4,			"wait4"				}, /*  260 */
-	{ 4,	0,	sys_prlimit64,			"prlimit64"			}, /*  261 */
-	{ 2,	TD,	sys_fanotify_init,		"fanotify_init"			}, /*  262 */
-	{ 5,	TD|TF,	sys_fanotify_mark,		"fanotify_mark"			}, /*  263 */
-	{ 5,	TD|TF,	sys_name_to_handle_at,		"name_to_handle_at"		}, /*  264 */
-	{ 3,	TD,	sys_open_by_handle_at,		"open_by_handle_at"		}, /*  265 */
-	{ 2,	0,	sys_clock_adjtime,		"clock_adjtime"			}, /*  266 */
-	{ 1,	TD,	sys_syncfs,			"syncfs"			}, /*  267 */
-	{ 2,	TD,	sys_setns,			"setns"				}, /*  268 */
-	{ 4,	TN,	sys_sendmmsg,			"sendmmsg"			}, /*  269 */
-	{ 6,	0,	sys_process_vm_readv,		"process_vm_readv"		}, /*  270 */
-	{ 6,	0,	sys_process_vm_writev,		"process_vm_writev"		}, /*  271 */
-
-	/* Blank down to 1023 */
-	[272 ... 1023] = { },
-
-	/* Quote from asm-generic/unistd.h:
-	 *
-	 * All syscalls below here should go away really,
-	 * these are provided for both review and as a porting
-	 * help for the C library version.
-	 *
-	 * Last chance: are any of these important enough to
-	 * enable by default?
-	 */
-
-	{ 3,	TD|TF,	sys_open,			"open"				}, /* 1024 */
-	{ 2,	TF,	sys_link,			"link"				}, /* 1025 */
-	{ 1,	TF,	sys_unlink,			"unlink"			}, /* 1026 */
-	{ 3,	TF,	sys_mknod,			"mknod"				}, /* 1027 */
-	{ 2,	TF,	sys_chmod,			"chmod"				}, /* 1028 */
-	{ 3,	TF,	sys_chown,			"chown"				}, /* 1029 */
-	{ 2,	TF,	sys_mkdir,			"mkdir"				}, /* 1030 */
-	{ 1,	TF,	sys_rmdir,			"rmdir"				}, /* 1031 */
-	{ 3,	TF,	sys_chown,			"lchown"			}, /* 1032 */
-	{ 2,	TF,	sys_access,			"access"			}, /* 1033 */
-	{ 2,	TF,	sys_rename,			"rename"			}, /* 1034 */
-	{ 3,	TF,	sys_readlink,			"readlink"			}, /* 1035 */
-	{ 2,	TF,	sys_symlink,			"symlink"			}, /* 1036 */
-	{ 2,	TF,	sys_utimes,			"utimes"			}, /* 1037 */
-	{ 2,	TF,	sys_stat,			"stat"				}, /* 1038 */
-	{ 2,	TF,	sys_lstat,			"lstat"				}, /* 1039 */
-	{ 1,	TD,	sys_pipe,			"pipe"				}, /* 1040 */
-	{ 2,	TD,	sys_dup2,			"dup2"				}, /* 1041 */
-	{ 1,	TD,	sys_epoll_create,		"epoll_create"			}, /* 1042 */
-	{ 0,	TD,	sys_inotify_init,		"inotify_init"			}, /* 1043 */
-	{ 1,	TD,	sys_eventfd,			"eventfd"			}, /* 1044 */
-	{ 3,	TD|TS,	sys_signalfd,			"signalfd"			}, /* 1045 */
-	{ 4,	TD|TN,	sys_sendfile,			"sendfile"			}, /* 1046 */
-	{ 2,	TD,	sys_ftruncate,			"ftruncate"			}, /* 1047 */
-	{ 2,	TF,	sys_truncate,			"truncate"			}, /* 1048 */
-	{ 2,	TF,	sys_stat,			"stat"				}, /* 1049 */
-	{ 2,	TF,	sys_lstat,			"lstat"				}, /* 1050 */
-	{ 2,	TD,	sys_fstat,			"fstat"				}, /* 1051 */
-	{ 3,	TD,	sys_fcntl,			"fcntl"				}, /* 1052 */
-	{ 4,	TD,	sys_fadvise64,			"fadvise64"			}, /* 1053 */
-	{ 4,	TD|TF,	sys_newfstatat,			"newfstatat"			}, /* 1054 */
-	{ 2,	TD,	sys_fstatfs,			"fstatfs"			}, /* 1055 */
-	{ 2,	TF,	sys_statfs,			"statfs"			}, /* 1056 */
-	{ 3,	TD,	sys_lseek,			"lseek"				}, /* 1057 */
-	{ 6,	TD|TM,	sys_mmap,			"mmap"				}, /* 1058 */
-	{ 1,	0,	sys_alarm,			"alarm"				}, /* 1059 */
-	{ 0,	0,	sys_getpgrp,			"getpgrp"			}, /* 1060 */
-	{ 0,	TS,	sys_pause,			"pause"				}, /* 1061 */
-	{ 1,	0,	sys_time,			"time"				}, /* 1062 */
-	{ 2,	TF,	sys_utime,			"utime"				}, /* 1063 */
-	{ 2,	TD|TF,	sys_creat,			"creat"				}, /* 1064 */
-	{ 3,	TD,	sys_getdents,			"getdents"			}, /* 1065 */
-	{ 3,	TD|TF,	sys_futimesat,			"futimesat"			}, /* 1066 */
-	{ 5,	TD,	sys_select,			"select"			}, /* 1067 */
-	{ 3,	TD,	sys_poll,			"poll"				}, /* 1068 */
-	{ 4,	TD,	sys_epoll_wait,			"epoll_wait"			}, /* 1069 */
-	{ 2,	0,	sys_ustat,			"ustat"				}, /* 1070 */
-	{ 0,	TP,	sys_vfork,			"vfork"				}, /* 1071 */
-	{ 4,	TP,	sys_wait4,			"wait4"				}, /* 1072 */
-	{ 6,	TN,	sys_recv,			"recv"				}, /* 1073 */
-	{ 4,	TD|TN,	sys_send,			"send"				}, /* 1074 */
-	{ 2,	0,	sys_bdflush,			"bdflush"			}, /* 1075 */
-	{ 2,	TF,	sys_umount,			"umount"			}, /* 1076 */
-	{ 1,	TF,	sys_uselib,			"uselib"			}, /* 1077 */
-	{ 1,	0,	sys_sysctl,			"sysctl"			}, /* 1078 */
-	{ 0,	TP,	sys_fork,			"fork"				}, /* 1079 */
+#include "../arm/syscallent.h"
diff --git a/linux/aarch64/syscallent.h b/linux/aarch64/syscallent1.h
similarity index 100%
copy from linux/aarch64/syscallent.h
copy to linux/aarch64/syscallent1.h
diff --git a/syscall.c b/syscall.c
index 680cbc3..b142b3d 100644
--- a/syscall.c
+++ b/syscall.c
@@ -287,6 +287,12 @@  update_personality(struct tcb *tcp, int personality)
 		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 @@  static long r0;
 #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 @@  get_scno(struct tcb *tcp)
 		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 @@  get_scno(struct tcb *tcp)
 		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 @@  get_syscall_args(struct tcb *tcp)
 	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 @@  get_syscall_result(struct tcb *tcp)
 		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 @@  get_error(struct tcb *tcp)
 	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;
-	}
-	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];
+#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.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) {