From: Frederic Berat Date: Thu, 12 May 2016 13:49:34 +0000 (+0200) Subject: ptrace: Add support for GETREGSET X-Git-Tag: accepted/tizen/4.0/base/20170811.092652~2 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fupstream%2Flibunwind.git;a=commitdiff_plain;h=019b3f6ed2a4e0ccb7dacf3e089a8d45a55d27f7 ptrace: Add support for GETREGSET 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 --- diff --git a/configure.ac b/configure.ac index 863fb8f..66f5165 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 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 = ®s; + 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 *)®s + _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)