psmisc/0006-This-patch-is-to-Add-ARM64-support-to-peekfd.patch
Jan Rybar 55f7cc57ed Backport of upstream patches since v23.2 release
Added support of peekfd on aarch64
2019-09-06 14:44:27 +02:00

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 &current->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, &regs);
+
+#elif defined(ARM64)
+ struct user_pt_regs regs, *old_regs;
+ struct iovec io;
+ io.iov_base = &regs;
+ 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, &regs);
#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, &regs);
+ 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,&regs);
+ }
+#endif
ptrace(PTRACE_SYSCALL, pid, 0, 0);
}
}
--
2.20.1