libunwind-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Libunwind-devel] [PATCH] ptrace: Add support for GETREGSET


From: Berat, Frederic (ADITG/SW1)
Subject: [Libunwind-devel] [PATCH] ptrace: Add support for GETREGSET
Date: Thu, 7 Jul 2016 09:24:18 +0000

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:
 
These interfaces have been replace by a more generic one:
 
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:
 
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 <address@hidden>
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 <address@hidden>
---
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
 
 

reply via email to

[Prev in Thread] Current Thread [Next in Thread]