ptrace: Add support for GETREGSET
authorFrederic Berat <fberat@de.adit-jv.com>
Thu, 12 May 2016 13:49:34 +0000 (15:49 +0200)
committerKarol Lewandowski <k.lewandowsk@samsung.com>
Fri, 26 May 2017 13:26:08 +0000 (15:26 +0200)
Adding support for PTRACE_GETREGSET that is expected to replace
PTRACE_PEEK for newer architectures.

Origin: https://lists.nongnu.org/archive/html/libunwind-devel/2016-07/msg00001.html
Change-Id: I2e720e6697fbc1facf1d7547b398f5665b17731e
Signed-off-by: Frederic Berat <fberat@de.adit-jv.com>
configure.ac
include/libunwind-aarch64.h
include/libunwind-arm.h
include/libunwind-hppa.h
include/libunwind-x86.h
include/libunwind-x86_64.h
src/ptrace/_UPT_access_fpreg.c
src/ptrace/_UPT_access_reg.c

index 863fb8f..66f5165 100644 (file)
@@ -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>
index cd01e57..360a053 100644 (file)
@@ -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);
 
index f208487..cdf92ba 100644 (file)
@@ -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)
 }
index 7013aa7..b99722c 100644 (file)
@@ -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"
 
index 40fe046..db0c4ab 100644 (file)
@@ -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)
 }
index 78eb541..6aa8060 100644 (file)
@@ -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);
index e90ec47..56ac3c4 100644 (file)
@@ -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)
index ae71608..bc20fae 100644 (file)
@@ -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)