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/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)