]> granicus.if.org Git - psmisc/commitdiff
This patch is to 'Add ARM64 support to peekfd'.
authorakaher <akaher@vmware.com>
Tue, 16 Apr 2019 13:50:08 +0000 (13:50 +0000)
committerCraig Small <csmall@enc.com.au>
Thu, 9 May 2019 11:27:09 +0000 (21:27 +1000)
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
configure.ac
src/peekfd.c

index 88598180f91fcc6db40268d65b274fd8d2a07403..441ae9435850b8c3650f077b9d63364b07f0dd63 100644 (file)
@@ -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
index 176a2fcc94b8a06e4b02e8f50f3f4073d3bae774..407cd97f707754cec1b2b20891e7da8d6a772b73 100644 (file)
@@ -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 &&
index 5aa990a76630900d92fdbbf1ca4812bc8da4f0b3..f41391a2ecbaaff989fe796e66d600316ce1ef90 100644 (file)
 #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
@@ -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);
                }
        }