AC_CHECK_MEMBERS([struct pt_regs.orig_gpr3,
struct pt_regs.gpr], [],[], [#include <linux/ptrace.h>])
AC_CHECK_MEMBERS([struct pt_regs.uregs],[],[], [#include <asm/ptrace.h>])
+AC_CHECK_MEMBERS([struct user_pt_regs.regs],[],[], [#include <asm/ptrace.h>])
AC_CHECK_MEMBERS([struct pt_regs.regs,
struct pt_regs.cp0_status],[],[], [#include <asm/ptrace.h>])
AC_CHECK_MEMBERS([struct pt_regs.orig_d0,
test $ac_cv_member_struct_pt_regs_gpr = yes )
AM_CONDITIONAL(WANT_PEEKFD_ARM,
test $ac_cv_member_struct_pt_regs_uregs = yes)
+AM_CONDITIONAL(WANT_PEEKFD_ARM64,
+ test $ac_cv_member_struct_user_pt_regs_regs = yes)
AM_CONDITIONAL(WANT_PEEKFD_MIPS,
test $build_cpu = mipsel &&
test $ac_cv_member_struct_pt_regs_regs = yes &&
#include <getopt.h>
#include <ctype.h>
#include <dirent.h>
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
#include "i18n.h"
+#ifdef ARM64
+#include <sys/uio.h>
+#include <linux/elf.h>
+#endif
+
#ifdef I386
#define REG_ORIG_ACCUM orig_eax
#define REG_ACCUM eax
#define REG_PARAM1 ARM_ORIG_r0
#define REG_PARAM2 ARM_r1
#define REG_PARAM3 ARM_r2
+
+#elif defined(ARM64)
+ #define REG_ORIG_ACCUM regs[8]
+ #define REG_ACCUM regs[0]
+ #define REG_PARAM1 regs[0]
+ #define REG_PARAM2 regs[1]
+ #define REG_PARAM3 regs[2]
+
+
+
#elif defined(MIPS)
#ifndef MIPSEL
#error only little endian supported
pid_t attached_pids[MAX_ATTACHED_PIDS];
int *fds = NULL;
+#ifdef ARM64
+struct user_pt_regs_node {
+ struct user_pt_regs regs;
+ struct user_pt_regs_node *user_pt_regs_next;
+};
+
+void user_pt_regs_insert(struct user_pt_regs_node** user_pt_regs_head, struct user_pt_regs *regs)
+{
+ struct user_pt_regs_node* new_node =
+ (struct user_pt_regs_node*) malloc(sizeof(struct user_pt_regs_node));
+
+ memcpy(&new_node->regs, regs, sizeof(struct user_pt_regs));
+ new_node->user_pt_regs_next = (*user_pt_regs_head);
+ (*user_pt_regs_head) = new_node;
+}
+
+struct user_pt_regs * user_pt_regs_search(struct user_pt_regs_node** user_pt_regs_head, struct user_pt_regs *regs)
+{
+ struct user_pt_regs_node* current = *user_pt_regs_head;
+ while (current != NULL)
+ {
+ if ((current->regs.REG_ORIG_ACCUM == regs->REG_ORIG_ACCUM) && (current->regs.REG_PARAM2 == regs->REG_PARAM2))
+ return ¤t->regs;
+ current = current->user_pt_regs_next;
+ }
+ return NULL;
+}
+
+
+int user_pt_regs_delete(struct user_pt_regs_node** user_pt_regs_head, struct user_pt_regs *regs)
+{
+ struct user_pt_regs_node* temp = *user_pt_regs_head, *prev;
+
+ if (temp != NULL && (&temp->regs == regs))
+ {
+ *user_pt_regs_head = temp->user_pt_regs_next;
+ free(temp);
+ return 0;
+ }
+
+ while (temp != NULL && (&temp->regs != regs))
+ {
+ prev = temp;
+ temp = temp->user_pt_regs_next;
+ }
+
+ if (temp == NULL) return -1;
+ prev->user_pt_regs_next = temp->user_pt_regs_next;
+ free(temp);
+ return 0;
+}
+#endif
+
void detach(int signum) {
int i;
for (i = 0; i < num_attached_pids; i++)
unsigned char *lastbuf = NULL;
unsigned long last_buf_size = -1;
+#ifdef ARM64
+ struct user_pt_regs_node* user_pt_regs_head = NULL;
+#endif
+
for(;;) {
int status;
pid_t pid = wait(&status);
#elif defined(ARM)
struct pt_regs regs;
ptrace(PTRACE_GETREGS, pid, 0, ®s);
+
+#elif defined(ARM64)
+ struct user_pt_regs regs, *old_regs;
+ struct iovec io;
+ io.iov_base = ®s;
+ io.iov_len = sizeof(regs);
+
+ if (ptrace(PTRACE_GETREGSET, pid, (void*) NT_PRSTATUS, (void*) &io) == -1) {
+ printf("ARM64: PTRACE_GETREGSET: %s\n", strerror(errno));
+ return errno;
+ }
+
#elif defined(MIPS)
struct pt_regs regs;
long pc = ptrace(PTRACE_PEEKUSER, pid, 64, 0);
ptrace(PTRACE_GETREGS, pid, 0, ®s);
#endif
/*unsigned int b = ptrace(PTRACE_PEEKTEXT, pid, regs.eip, 0);*/
- if ((follow_forks && regs.REG_ORIG_ACCUM == SYS_fork)
- || (follow_clones && regs.REG_ORIG_ACCUM == SYS_clone)) {
+
+#if defined(ARM64)
+ if (follow_forks && regs.REG_ORIG_ACCUM == SYS_clone) {
+#else
+ if ((follow_forks && regs.REG_ORIG_ACCUM == SYS_fork)
+ || (follow_clones && regs.REG_ORIG_ACCUM == SYS_clone)) {
+#endif
if (regs.REG_ACCUM > 0)
attach(regs.REG_ACCUM);
}
if ((regs.REG_ORIG_ACCUM == SYS_read || regs.REG_ORIG_ACCUM == SYS_write) && (regs.REG_PARAM3 == regs.REG_ACCUM)) {
+#ifdef ARM64
+ /* ARM64 doesn't expose orig_x0 to user space,
+ so retrive orig_x0 from older user pt regs */
+ old_regs = user_pt_regs_search(&user_pt_regs_head, ®s);
+ if (old_regs != NULL) {
+ regs.REG_PARAM1 = old_regs->REG_PARAM1;
+ user_pt_regs_delete(&user_pt_regs_head, old_regs);
+ }
+#endif
for (i = 0; i < numfds; i++)
if (fds[i] == (int)regs.REG_PARAM1)
break;
fflush(stdout);
}
}
-
+#ifdef ARM64
+ else if (regs.REG_ORIG_ACCUM == SYS_read || regs.REG_ORIG_ACCUM == SYS_write)
+ {
+ user_pt_regs_insert(&user_pt_regs_head,®s);
+ }
+#endif
ptrace(PTRACE_SYSCALL, pid, 0, 0);
}
}