aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libsandbox/trace.c1
-rw-r--r--libsandbox/trace/linux/arch.c2
-rw-r--r--libsandbox/trace/linux/ia64.c81
3 files changed, 84 insertions, 0 deletions
diff --git a/libsandbox/trace.c b/libsandbox/trace.c
index 5ccda2a..fb1fc32 100644
--- a/libsandbox/trace.c
+++ b/libsandbox/trace.c
@@ -9,6 +9,7 @@
#include "wrappers.h"
#include "sb_nr.h"
+static long do_peekdata(long offset);
static long _do_ptrace(enum __ptrace_request request, const char *srequest, void *addr, void *data);
#define do_ptrace(request, addr, data) _do_ptrace(request, #request, addr, data)
#define _trace_possible(data) true
diff --git a/libsandbox/trace/linux/arch.c b/libsandbox/trace/linux/arch.c
index fbf5b79..4b3d615 100644
--- a/libsandbox/trace/linux/arch.c
+++ b/libsandbox/trace/linux/arch.c
@@ -17,6 +17,8 @@
# include "hppa.c"
#elif defined(__i386__)
# include "i386.c"
+#elif defined(__ia64__)
+# include "ia64.c"
#elif defined(__powerpc__)
# include "powerpc.c"
#elif defined(__s390__)
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);
+}