Hello there,

While working with libunwind using the ptrace interface on linux, we faced an 
unexpected problem. Everything works fine for old architectures like arm or 
x86, but that's not the case any longer for more younger ones like aarch64.
The point is, it looks like linux kernel maintainers seem to not be willing to 
implement some interfaces for the most recent architectures. Among the 
interface that are not expected to be implemented, there are the following:
-       PTRACE_PEEKUSER
-       PTRACE_POKEUSER

These interfaces have been replace by a more generic one:
-       PTRACE_GETREGSET
-       PTRACE_SETREGSET

Therefore I propose the following patch. The idea is to use the new interface 
mechanism as far as possible. Please note that I only implemented it for the 
architectures that I could test, at least for the basics:
-       x86
-       x86_64
-       arm
-       aarch64

The patch is based on the libunwind adaption for BSD systems, and the gdb 
implementation.

Best regards

Frederic Berat
>From ee43b80f6c34bb5e1cb09699d7d2cfd0c12949a1 Mon Sep 17 00:00:00 2001
From: Frederic Berat <[email protected]>
Date: Thu, 12 May 2016 15:49:34 +0200
Subject: [PATCH] ptrace: Add support for GETREGSET

Adding support for PTRACE_GETREGSET that is expected to replace
PTRACE_PEEK for newer architectures.

Signed-off-by: Frederic Berat <[email protected]>
---
 configure.ac                   |    2 +-
 include/libunwind-aarch64.h    |    1 +
 include/libunwind-arm.h        |    1 +
 include/libunwind-hppa.h       |    1 +
 include/libunwind-x86.h        |    1 +
 include/libunwind-x86_64.h     |    1 +
 src/ptrace/_UPT_access_fpreg.c |   35 +++++++++++++++++++++++++++++-
 src/ptrace/_UPT_access_reg.c   |   47 +++++++++++++++++++++++++++++++++++++++-
 8 files changed, 86 insertions(+), 3 deletions(-)

diff --git a/configure.ac b/configure.ac
index 85d78f8..e83b9ee 100644
--- a/configure.ac
+++ b/configure.ac
@@ -59,7 +59,7 @@ AC_CHECK_DECLS([PTRACE_POKEUSER, PTRACE_POKEDATA,
 PTRACE_TRACEME, PTRACE_CONT, PTRACE_SINGLESTEP,
 PTRACE_SYSCALL, PT_IO, PT_GETREGS,
 PT_GETFPREGS, PT_CONTINUE, PT_TRACE_ME,
-PT_STEP, PT_SYSCALL], [], [],
+PT_STEP, PT_SYSCALL, PTRACE_GETREGSET], [], [],
 [$ac_includes_default
 #if HAVE_SYS_TYPES_H
 #include <sys/types.h>
diff --git a/include/libunwind-aarch64.h b/include/libunwind-aarch64.h
index cd01e57..360a053 100644
--- a/include/libunwind-aarch64.h
+++ b/include/libunwind-aarch64.h
@@ -177,6 +177,7 @@ typedef ucontext_t unw_tdep_context_t;

 #define unw_tdep_getcontext(uc)         (getcontext (uc), 0)
 #define unw_tdep_is_fpreg               UNW_ARCH_OBJ(is_fpreg)
+#define _UPT_get_fpreg(fpreg, reg)      &fpreg.vregs[reg]

 extern int unw_tdep_is_fpreg (int);

diff --git a/include/libunwind-arm.h b/include/libunwind-arm.h
index f208487..cdf92ba 100644
--- a/include/libunwind-arm.h
+++ b/include/libunwind-arm.h
@@ -294,6 +294,7 @@ unw_tdep_proc_info_t;

 #define unw_tdep_is_fpreg               UNW_ARCH_OBJ(is_fpreg)
 extern int unw_tdep_is_fpreg (int);
+#define _UPT_get_fpreg(fpreg, reg)      &fpreg.fpregs[reg]

 #if defined(__cplusplus) || defined(c_plusplus)
 }
diff --git a/include/libunwind-hppa.h b/include/libunwind-hppa.h
index 7013aa7..b99722c 100644
--- a/include/libunwind-hppa.h
+++ b/include/libunwind-hppa.h
@@ -104,6 +104,7 @@ unw_tdep_save_loc_t;
 typedef ucontext_t unw_tdep_context_t;

 #define unw_tdep_is_fpreg(r)            ((unsigned) ((r) - UNW_HPPA_FR) < 32)
+#define _UPT_get_fpreg(fpreg, reg)       &fpreg.fp_dregs[reg]

 #include "libunwind-dynamic.h"

diff --git a/include/libunwind-x86.h b/include/libunwind-x86.h
index 40fe046..db0c4ab 100644
--- a/include/libunwind-x86.h
+++ b/include/libunwind-x86.h
@@ -179,6 +179,7 @@ extern int unw_tdep_getcontext (unw_tdep_context_t *);

 #define unw_tdep_is_fpreg               UNW_ARCH_OBJ(is_fpreg)
 extern int unw_tdep_is_fpreg (int);
+#define _UPT_get_fpreg(fpreg, reg)      &fpreg->_st[reg]

 #if defined(__cplusplus) || defined(c_plusplus)
 }
diff --git a/include/libunwind-x86_64.h b/include/libunwind-x86_64.h
index 78eb541..6aa8060 100644
--- a/include/libunwind-x86_64.h
+++ b/include/libunwind-x86_64.h
@@ -130,6 +130,7 @@ unw_tdep_proc_info_t;

 #define unw_tdep_getcontext             UNW_ARCH_OBJ(getcontext)
 #define unw_tdep_is_fpreg               UNW_ARCH_OBJ(is_fpreg)
+#define _UPT_get_fpreg(fpreg, reg)      &fpreg->_st[reg]

 extern int unw_tdep_getcontext (unw_tdep_context_t *);
 extern int unw_tdep_is_fpreg (int);
diff --git a/src/ptrace/_UPT_access_fpreg.c b/src/ptrace/_UPT_access_fpreg.c
index e90ec47..56ac3c4 100644
--- a/src/ptrace/_UPT_access_fpreg.c
+++ b/src/ptrace/_UPT_access_fpreg.c
@@ -26,7 +26,40 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
SOFTWARE.  */

 #include "_UPT_internal.h"

-#if HAVE_DECL_PTRACE_POKEUSER || HAVE_TTRACE
+/* Architecture specific ptrace helper must be implemented,
+ * else we fall back to the old - and deprecated -  ABI implementation
+ */
+#if HAVE_DECL_PTRACE_GETREGSET && defined(_UPT_get_fpreg)
+int
+_UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
+                   int write, void *arg)
+{
+  struct UPT_info *ui = arg;
+  pid_t pid = ui->pid;
+  struct iovec iovec = { 0 };
+  fpregset_t fpreg = { 0 };
+
+  if ((unsigned) reg >= ARRAY_SIZE (_UPT_reg_offset))
+    return -UNW_EBADREG;
+
+  iovec.iov_base = &fpreg;
+  iovec.iov_len = sizeof(fpreg);
+
+  if (ptrace(PTRACE_GETREGSET, pid, NT_FPREGSET, &iovec) == -1)
+    return -UNW_EBADREG;
+
+  if (write)
+  {
+    memcpy(_UPT_get_fpreg(fpreg, reg), val, sizeof(unw_fpreg_t));
+
+    if (ptrace(PTRACE_SETREGSET, pid, NT_FPREGSET, &iovec) == -1)
+      return -UNW_EBADREG;
+  } else
+    memcpy(val, _UPT_get_fpreg(fpreg, reg), sizeof(unw_fpreg_t));
+
+  return 0;
+}
+#elif HAVE_DECL_PTRACE_POKEUSER || HAVE_TTRACE
 int
 _UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
                    int write, void *arg)
diff --git a/src/ptrace/_UPT_access_reg.c b/src/ptrace/_UPT_access_reg.c
index ae71608..bc20fae 100644
--- a/src/ptrace/_UPT_access_reg.c
+++ b/src/ptrace/_UPT_access_reg.c
@@ -34,7 +34,52 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
SOFTWARE.  */
 # include "tdep-ia64/rse.h"
 #endif

-#if HAVE_DECL_PTRACE_POKEUSER || HAVE_TTRACE
+#if HAVE_DECL_PTRACE_GETREGSET
+int
+_UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val,
+    int write, void *arg)
+{
+  struct UPT_info *ui = arg;
+  pid_t pid = ui->pid;
+  gregset_t regs = { 0 };
+  struct iovec iovec = { 0 };
+  char *r;
+
+  iovec.iov_base = &regs;
+  iovec.iov_len = sizeof(regs);
+
+  Debug(16, "using getregset: reg: %s [%u], val: %lx, write: %u\n",
+        unw_regname(reg), (unsigned int)reg, (unsigned long)*val, write);
+
+  if (write)
+    Debug(16, "%s [%u] <- %lx\n",
+          unw_regname (reg), (unsigned int)reg, (unsigned long)*val);
+
+  if ((unsigned int)reg >= ARRAY_SIZE (_UPT_reg_offset))
+  {
+    errno = EINVAL;
+    goto badreg;
+  }
+
+  r = (char *)&regs + _UPT_reg_offset[reg];
+  if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iovec) == -1)
+    goto badreg;
+
+  if (write) {
+    memcpy(r, val, sizeof(unw_word_t));
+    if (ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iovec) == -1)
+      goto badreg;
+  } else
+    memcpy(val, r, sizeof(unw_word_t));
+
+  return 0;
+
+badreg:
+  Debug(1, "bad register %s [%u] (error: %s)\n",
+         unw_regname(reg), reg, strerror (errno));
+  return -UNW_EBADREG;
+}
+#elif HAVE_DECL_PTRACE_POKEUSER || HAVE_TTRACE
 int
 _UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val,
                  int write, void *arg)
--
1.7.9.5


_______________________________________________
Libunwind-devel mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/libunwind-devel

Reply via email to