55f7cc57ed
Added support of peekfd on aarch64
237 lines
6.9 KiB
Diff
237 lines
6.9 KiB
Diff
From 32432ef9bbb44ea74d4dae858786db75c082623f Mon Sep 17 00:00:00 2001
|
|
From: akaher <akaher@vmware.com>
|
|
Date: Tue, 16 Apr 2019 13:50:08 +0000
|
|
Subject: [PATCH 06/11] This patch is to 'Add ARM64 support to peekfd'.
|
|
|
|
ARM64 copy user_pt_regs to user space instead of pt_regs.
|
|
So in this patch, mapping the require user_pt_regs except orig_x0,
|
|
as orig_x0 not available in user_pt_regs for SYSCALL exit.
|
|
|
|
For each SYSCALL, peekfd catches user_pt_regs for SYSCALL entry/exit.
|
|
Value of orig_x0 is available in user_pt_regs->x0 of SYSCALL entry.
|
|
|
|
So to get orig_x0, stores user_pt_regs of SYSCALL entry,
|
|
and then compare 'fd and addr of buffer' of SYSCALL exit
|
|
with SYSCALL entry to retrive orig_x0 at the time of SYSCALL exit.
|
|
|
|
Signed-off-by: Ajay Kaher <akaher@vmware.com>
|
|
---
|
|
Makefile.am | 6 +++
|
|
configure.ac | 3 ++
|
|
src/peekfd.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++--
|
|
3 files changed, 118 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/Makefile.am b/Makefile.am
|
|
index 8859818..441ae94 100644
|
|
--- a/Makefile.am
|
|
+++ b/Makefile.am
|
|
@@ -40,6 +40,12 @@ if WANT_PEEKFD_ARM
|
|
bin_PROGRAMS += src/peekfd
|
|
AM_CPPFLAGS += -DARM
|
|
endif
|
|
+
|
|
+if WANT_PEEKFD_ARM64
|
|
+ bin_PROGRAMS += src/peekfd
|
|
+ AM_CPPFLAGS += -DARM64
|
|
+endif
|
|
+
|
|
if WANT_PEEKFD_MIPS
|
|
bin_PROGRAMS += src/peekfd
|
|
AM_CPPFLAGS += -DMIPS
|
|
diff --git a/configure.ac b/configure.ac
|
|
index 176a2fc..407cd97 100644
|
|
--- a/configure.ac
|
|
+++ b/configure.ac
|
|
@@ -131,6 +131,7 @@ AC_CHECK_MEMBERS([struct user_regs_struct.orig_eax,
|
|
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,
|
|
@@ -163,6 +164,8 @@ AM_CONDITIONAL(WANT_PEEKFD_PPC,
|
|
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 &&
|
|
diff --git a/src/peekfd.c b/src/peekfd.c
|
|
index 5aa990a..f41391a 100644
|
|
--- a/src/peekfd.c
|
|
+++ b/src/peekfd.c
|
|
@@ -35,9 +35,17 @@
|
|
#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
|
|
@@ -72,6 +80,16 @@
|
|
#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
|
|
@@ -94,6 +112,59 @@ int num_attached_pids = 0;
|
|
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++)
|
|
@@ -260,6 +331,10 @@ int main(int argc, char **argv)
|
|
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);
|
|
@@ -274,6 +349,18 @@ int main(int argc, char **argv)
|
|
#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);
|
|
@@ -287,12 +374,26 @@ int main(int argc, char **argv)
|
|
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;
|
|
@@ -348,7 +449,12 @@ int main(int argc, char **argv)
|
|
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);
|
|
}
|
|
}
|
|
--
|
|
2.20.1
|
|
|