Enable vgdb ptrace invoker for aarch64.

This only works in non-bi arch mode. If ever aarch64+arm
are compiled bi-arch, then some more work is needed to have
a 64 bits vgdb able to ptrace invoke a 32 bits valgrind.

Note also that PTRACE_GETREGSET is defined on other platforms
(e.g. ppc64 fedora 18 defines it), but it is not used on
these platforms, as again, PTRACE_GETREGSET implies some
work for bi-arch to work properly.
So, on all platforms except arm64, we use PTRACE_GETREGS
or PTRACE_PEEKUSER.



git-svn-id: svn://svn.valgrind.org/valgrind/trunk@13981 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/README.aarch64 b/README.aarch64
index 28a26cc..2d6c936 100644
--- a/README.aarch64
+++ b/README.aarch64
@@ -7,19 +7,17 @@
 instructions and can run anything generated by gcc-4.8.2 -O3.  The
 port is under active development.
 
-Current limitations, as of mid-March 2014.
+Current limitations, as of mid-May 2014.
 
 * limited support of vector (SIMD) instructions.  Initial target is
   support for instructions created by gcc-4.8.2 -O3
   (via autovectorisation).  This is complete.
 
 * Integration with the built in GDB server:
-   - basically works but breakpoints may be problematic (unclear)
-     Use --vgdb=full to bypass the problem.  
+   - works ok (breakpoint, attach to a process blocked in a syscall, ...)
    - still to do:
       arm64 xml register description files (allowing shadow registers
                                             to be looked at).
-      ptrace invoker : currently disabled for both arm and arm64
       cpsr transfer to/from gdb to be looked at (see also arm equivalent code)
 
 * limited syscall support
diff --git a/coregrind/Makefile.am b/coregrind/Makefile.am
index bd632f9..31ca332 100644
--- a/coregrind/Makefile.am
+++ b/coregrind/Makefile.am
@@ -61,12 +61,6 @@
 
 
 vgdb_SOURCES = vgdb.c
-if VGCONF_PLATFORMS_INCLUDE_ARM64_LINUX
-# vgdb-invoker-ptrace.c isn't buildable on arm64-linux yet
-# so skip it.  Unfortunately this also causes it to be skipped
-# for 32-bit ARM builds which are part of a bi-arch ARM build.
-vgdb_SOURCES += vgdb-invoker-none.c
-else
 if VGCONF_OS_IS_LINUX
 if VGCONF_PLATVARIANT_IS_ANDROID
 vgdb_SOURCES += vgdb-invoker-none.c
@@ -74,7 +68,6 @@
 vgdb_SOURCES += vgdb-invoker-ptrace.c
 endif
 endif
-endif
 if VGCONF_OS_IS_DARWIN
 # Some darwin specific stuff is needed as ptrace is not
 # fully supported on MacOS. Till we find someone courageous
diff --git a/coregrind/m_options.c b/coregrind/m_options.c
index 7b8b141..dd568c5 100644
--- a/coregrind/m_options.c
+++ b/coregrind/m_options.c
@@ -48,8 +48,7 @@
 Int    VG_(clo_error_exitcode) = 0;
 
 #if defined(VGPV_arm_linux_android) || defined(VGPV_x86_linux_android) \
-    || defined(VGPV_mips32_linux_android) \
-    || defined(VGP_arm64_linux) // temporarily disabled on arm64-linux
+    || defined(VGPV_mips32_linux_android)
 VgVgdb VG_(clo_vgdb)           = Vg_VgdbNo; // currently disabled on Android
 #else
 VgVgdb VG_(clo_vgdb)           = Vg_VgdbYes;
diff --git a/coregrind/vgdb-invoker-ptrace.c b/coregrind/vgdb-invoker-ptrace.c
index b0e49a1..b3af26d 100644
--- a/coregrind/vgdb-invoker-ptrace.c
+++ b/coregrind/vgdb-invoker-ptrace.c
@@ -42,6 +42,28 @@
 #include <sys/user.h>
 #include <sys/wait.h>
 
+#ifdef PTRACE_GETREGSET
+// TBD: better have a configure test instead ?
+#define HAVE_PTRACE_GETREGSET
+
+// A bi-arch build using PTRACE_GET/SETREGSET needs
+// some conversion code for register structures.
+// So, better do not use PTRACE_GET/SETREGSET
+// Rather we use PTRACE_GETREGS or PTRACE_PEEKUSER.
+
+// The only platform on which we must use PTRACE_GETREGSET is arm64.
+// The resulting vgdb cannot work in a bi-arch setup.
+// -1 means we will check that PTRACE_GETREGSET works.
+#  if defined(VGA_arm64)
+#define USE_PTRACE_GETREGSET
+#  endif
+#endif
+
+#include <sys/uio.h>
+#include <elf.h>
+
+#include <sys/procfs.h>
+
 #if VEX_HOST_WORDSIZE == 8
 typedef Addr64 CORE_ADDR;
 #elif VEX_HOST_WORDSIZE == 4
@@ -492,8 +514,11 @@
    }
 }
 
+#  if defined(VGA_arm64)
+static struct user_pt_regs user_save;
+#  else
 static struct user user_save;
-
+#  endif
 // The below indicates if ptrace_getregs (and ptrace_setregs) can be used.
 // Note that some linux versions are defining PTRACE_GETREGS but using
 // it gives back EIO.
@@ -505,6 +530,10 @@
 #ifdef HAVE_PTRACE_GETREGS
 static int has_working_ptrace_getregs = -1;
 #endif
+// Similar but for PTRACE_GETREGSET
+#ifdef HAVE_PTRACE_GETREGSET
+static int has_working_ptrace_getregset = -1;
+#endif
 
 /* Get the registers from pid into regs.
    regs_bsz value gives the length of *regs. 
@@ -513,6 +542,52 @@
 Bool getregs (pid_t pid, void *regs, long regs_bsz)
 {
    DEBUG(1, "getregs regs_bsz %ld\n", regs_bsz);
+#  ifdef HAVE_PTRACE_GETREGSET
+#  ifndef USE_PTRACE_GETREGSET
+   if (has_working_ptrace_getregset)
+      DEBUG(1, "PTRACE_GETREGSET defined, not used (yet?) by vgdb\n");
+   has_working_ptrace_getregset = 0;
+#  endif
+   if (has_working_ptrace_getregset) {
+      // Platforms having GETREGSET
+      long res;
+      elf_gregset_t elf_regs;
+      struct iovec iovec;
+
+      DEBUG(1, "getregs PTRACE_GETREGSET sizeof(elf_regs) %d\n", sizeof(elf_regs));
+      iovec.iov_base = regs;
+      iovec.iov_len =  sizeof(elf_regs);
+
+      res = ptrace (PTRACE_GETREGSET, pid, NT_PRSTATUS, &iovec);
+      if (res == 0) {
+         if (has_working_ptrace_getregset == -1) {
+            // First call to PTRACE_GETREGSET succesful =>
+            has_working_ptrace_getregset = 1;
+            DEBUG(1, "detected a working PTRACE_GETREGSET\n");
+         }
+         assert (has_working_ptrace_getregset == 1);
+         return True;
+      }
+      else if (has_working_ptrace_getregset == 1) {
+         // We had a working call, but now it fails.
+         // This is unexpected.
+         ERROR(errno, "PTRACE_GETREGSET %ld\n", res);
+         return False;
+      } else {
+         // Check this is the first call:
+         assert (has_working_ptrace_getregset == -1);
+         if (errno == EIO) {
+            DEBUG(1, "detected a broken PTRACE_GETREGSET with EIO\n");
+            has_working_ptrace_getregset = 0;
+            // Fall over to the PTRACE_GETREGS or PTRACE_PEEKUSER case.
+         } else {
+            ERROR(errno, "broken PTRACE_GETREGSET unexpected errno %ld\n", res);
+            return False;
+         }
+      }
+   }
+#  endif
+
 #  ifdef HAVE_PTRACE_GETREGS
    if (has_working_ptrace_getregs) {
       // Platforms having GETREGS
@@ -570,8 +645,8 @@
       return True;
    }
 
-   // If neither PTRACE_GETREGS not PTRACE_PEEKUSER have returned,
-   // then we are in serious trouble.
+   // If neither of PTRACE_GETREGSET PTRACE_GETREGS PTRACE_PEEKUSER have
+   // returned, then we are in serious trouble.
    assert (0);
 }
 
@@ -582,6 +657,30 @@
 Bool setregs (pid_t pid, void *regs, long regs_bsz)
 {
    DEBUG(1, "setregs regs_bsz %ld\n", regs_bsz);
+
+// Note : the below is checking for GETREGSET, not SETREGSET
+// as if one is defined and working, the other one should also work.
+#  ifdef HAVE_PTRACE_GETREGSET
+   if (has_working_ptrace_getregset) {
+      // Platforms having SETREGSET
+      long res;
+      elf_gregset_t elf_regs;
+      struct iovec iovec;
+
+      // setregset can never be called before getregset has done a runtime check.
+      assert (has_working_ptrace_getregset == 1);
+      DEBUG(1, "setregs PTRACE_SETREGSET sizeof(elf_regs) %d\n", sizeof(elf_regs));
+      iovec.iov_base = regs;
+      iovec.iov_len =  sizeof(elf_regs);
+      res = ptrace (PTRACE_SETREGSET, pid, NT_PRSTATUS, &iovec);
+      if (res != 0) {
+         ERROR(errno, "PTRACE_SETREGSET %ld\n", res);
+         return False;
+      }
+      return True;
+   }
+#  endif
+
 // Note : the below is checking for GETREGS, not SETREGS
 // as if one is defined and working, the other one should also work.
 #  ifdef HAVE_PTRACE_GETREGS
@@ -683,7 +782,11 @@
 {
    long res;
    Bool stopped;
+#  if defined(VGA_arm64)
+   struct user_pt_regs user_mod;
+#  else
    struct user user_mod;
+#  endif
    Addr sp;
    /* A specific int value is passed to invoke_gdbserver, to check
       everything goes according to the plan. */
@@ -736,6 +839,8 @@
    }
 #elif defined(VGA_arm)
    sp = user_mod.regs.uregs[13];
+#elif defined(VGA_arm64)
+   sp = user_mod.sp;
 #elif defined(VGA_ppc32)
    sp = user_mod.regs.gpr[1];
 #elif defined(VGA_ppc64)
@@ -817,6 +922,9 @@
       user_mod.regs.uregs[14] = bad_return;
       user_mod.regs.uregs[15] = shared32->invoke_gdbserver;
 
+#elif defined(VGA_arm64)
+      XERROR(0, "TBD arm64: vgdb a 32 bits executable with a 64 bits exe");
+
 #elif defined(VGA_s390x)
       XERROR(0, "(fn32) s390x has no 32bits implementation");
 #elif defined(VGA_mips32)
@@ -867,6 +975,13 @@
 
 #elif defined(VGA_arm)
       assert(0); // cannot vgdb a 64 bits executable with a 32 bits exe
+#elif defined(VGA_arm64)
+      user_mod.regs[0] = check;
+      user_mod.sp = sp;
+      user_mod.pc = shared64->invoke_gdbserver;
+      /* put NULL return address in Link Register */
+      user_mod.regs[30] = bad_return;
+
 #elif defined(VGA_ppc32)
       assert(0); // cannot vgdb a 64 bits executable with a 32 bits exe
 #elif defined(VGA_ppc64)