aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'libsandbox/trace/linux/ia64.c')
-rw-r--r--libsandbox/trace/linux/ia64.c81
1 files changed, 81 insertions, 0 deletions
diff --git a/libsandbox/trace/linux/ia64.c b/libsandbox/trace/linux/ia64.c
new file mode 100644
index 0000000..5029994
--- /dev/null
+++ b/libsandbox/trace/linux/ia64.c
@@ -0,0 +1,81 @@
+#include <asm/ptrace_offsets.h>
+#include <asm/rse.h>
+
+/* We only care about two ptrace regs, so extract them ourselves rather than
+ * get the "full" set via GETREGS. We still need to extract the out regs by
+ * hand either way.
+ */
+#undef trace_regs
+struct sb_ia64_trace_regs {
+ unsigned long r8, r10, r15;
+ unsigned long out[6];
+};
+#define trace_regs struct sb_ia64_trace_regs
+
+#define trace_reg_sysnum r15
+
+static unsigned long trace_arg(void *vregs, int num)
+{
+ trace_regs *regs = vregs;
+ if (num < 7)
+ return regs->out[num - 1];
+ else
+ return -1;
+}
+
+static long do_peekuser(long offset)
+{
+ return do_ptrace(PTRACE_PEEKUSER, (void *)offset, NULL);
+}
+
+static long do_pokeuser(long offset, long val)
+{
+ return do_ptrace(PTRACE_POKEUSER, (void *)offset, (void *)val);
+}
+
+#undef trace_get_regs
+static long trace_get_regs(void *vregs)
+{
+ trace_regs *regs = vregs;
+ size_t i;
+ unsigned long *out0, cfm, sof, sol;
+ long rbs_end;
+
+ regs->r15 = do_peekuser(PT_R15);
+
+ /* Here there be gremlins! */
+ rbs_end = do_peekuser(PT_AR_BSP);
+ cfm = do_peekuser(PT_CFM);
+ sof = (cfm >> 0) & 0x7f;
+ sol = (cfm >> 7) & 0x7f;
+ out0 = ia64_rse_skip_regs((unsigned long *)rbs_end, -sof + sol);
+ for (i = 0; i < 7; ++i)
+ regs->out[i] = do_peekdata((uintptr_t)ia64_rse_skip_regs(out0, i));
+
+ return 0;
+}
+
+#undef trace_set_regs
+static long trace_set_regs(void *vregs)
+{
+ trace_regs *regs = vregs;
+ /* We only support rewriting of syscall/err # currently (not args). */
+ do_pokeuser(PT_R8, regs->r8);
+ do_pokeuser(PT_R10, regs->r10);
+ do_pokeuser(PT_R15, regs->r15);
+ return 0;
+}
+
+static long trace_raw_ret(void *vregs)
+{
+ trace_regs *regs = vregs;
+ return regs->r8;
+}
+
+static void trace_set_ret(void *vregs, int err)
+{
+ trace_regs *regs = vregs;
+ regs->r8 = err;
+ regs->r10 = -1;
+ trace_set_regs(regs);
+}