diff options
author | Shuai Xue <xueshuai@linux.alibaba.com> | 2022-10-18 22:46:13 +0800 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2022-10-18 10:03:26 -0700 |
commit | 0353291ec4a1993532baba9d72701a99c12dcd40 (patch) | |
tree | ff6d1afb73f0bbc31ace11ff4e017d407fd9e6fa | |
parent | c8aef396cc8ff29f5c2dcc6dd6dc56ed2d9202ad (diff) | |
download | ras-tools-0353291ec4a1993532baba9d72701a99c12dcd40.tar.gz |
hornet: extend ptrace with PTRACE_GETREGSET on arm64 platform
hornet use ptrace(2) with PTRACE_GETREGS request to read the tracee's
general-purpose registers, but it does not work on arm64 platform.
To extend hornet on both X86 and arm64 platform, retrieve rip or PC in an
architecture-dependent way when PTRACE_GETREGS is not available.
Signed-off-by: Shuai Xue <xueshuai@linux.alibaba.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
-rw-r--r-- | hornet.c | 57 |
1 files changed, 47 insertions, 10 deletions
@@ -27,6 +27,9 @@ #include <sys/wait.h> #include <sys/user.h> #include <sys/ptrace.h> +#include <linux/ptrace.h> +#include <sys/uio.h> +#include <elf.h> static char *progname; @@ -52,14 +55,47 @@ static void usage(void) #define EINJ_DOIT "/sys/kernel/debug/apei/einj/error_inject" #define check_ptrace(req, pid, addr, data) \ - do { \ - if (ptrace(req, pid, addr, data) == -1) { \ + do { \ + if (ptrace(req, pid, addr, data) == -1) { \ fprintf(stderr, "Failed to run "#req": %s\n", \ - strerror(errno)); \ - return 1; \ - } \ + strerror(errno)); \ + return errno; \ + } \ } while (0) +#if defined(__x86_64__) +# define ARCH_REGS struct user_regs_struct +# define ARCH_PC(_regs) (_regs).rip +#elif defined(__arm__) +# define ARCH_REGS struct pt_regs +# define ARCH_PC(_regs) (_regs).ARM_pc +#elif defined(__aarch64__) +# define ARCH_REGS struct user_pt_regs +# define ARCH_PC(_regs) (_regs).pc +# endif + +/* + * Use PTRACE_GETREGS and PTRACE_SETREGS when available. This is useful for + * architectures without HAVE_ARCH_TRACEHOOK (e.g. User-mode Linux). + */ +#if defined(__x86_64__) || defined(__i386__) || defined(__mips__) +# define ARCH_GETREGS(tracee, _regs) check_ptrace(PTRACE_GETREGS, tracee, 0, &(_regs)) +# define ARCH_SETREGS(tracee, _regs) check_ptrace(PTRACE_SETREGS, tracee, 0, &(_regs)) +#else +# define ARCH_GETREGS(tracee, _regs) ({ \ + struct iovec __v; \ + __v.iov_base = &(_regs); \ + __v.iov_len = sizeof(_regs); \ + check_ptrace(PTRACE_GETREGSET, tracee, NT_PRSTATUS, &__v); \ + }) +# define ARCH_SETREGS(tracee, _regs) ({ \ + struct iovec __v; \ + __v.iov_base = &(_regs); \ + __v.iov_len = sizeof(_regs); \ + check_ptrace(PTRACE_SETREGSET, tracee, NT_PRSTATUS, &__v); \ + }) +#endif + static void wfile(char *file, unsigned long val) { FILE *fp; @@ -210,7 +246,7 @@ int main(int argc, char **argv) int c; int status; long lo, hi, phys, virt; - struct user_regs_struct regs; + ARCH_REGS regs; int ret = 0; progname = argv[0]; @@ -240,8 +276,8 @@ int main(int argc, char **argv) if (trace) { check_ptrace(PTRACE_ATTACH, pid, NULL, NULL); waitpid(pid, NULL, 0); - check_ptrace(PTRACE_GETREGS, pid, NULL, ®s); - virt = regs.rip; + ARCH_GETREGS(pid, regs); + virt = ARCH_PC(regs); check_ptrace(PTRACE_PEEKTEXT, pid, virt, NULL); lo = hi = addr = virt; } else { @@ -262,8 +298,9 @@ int main(int argc, char **argv) wfile(EINJ_ADDR, phys); wfile(EINJ_DOIT, 1); - if (vflag) printf("%s: injected UC error at virt=%lx phys=%lx to pid=%d%s\n", - progname, virt, phys, pid, trace == 1 ? "(ptrace)" : ""); + if (vflag) + printf("%s: injected UC error at virt=%lx phys=%lx to pid=%d%s\n", + progname, virt, phys, pid, trace == 1 ? "(ptrace)" : ""); if (trace) { sleep(1); |