ptrace: Add support for GETREGSET
[platform/upstream/libunwind.git] / src / ptrace / _UPT_access_reg.c
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)