powerpc: Syscall hooks for context tracking subsystem
[cascardo/linux.git] / arch / powerpc / kernel / ptrace.c
index f9b30c6..98c2fc1 100644 (file)
@@ -32,6 +32,7 @@
 #include <trace/syscall.h>
 #include <linux/hw_breakpoint.h>
 #include <linux/perf_event.h>
+#include <linux/context_tracking.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -180,9 +181,10 @@ static int set_user_msr(struct task_struct *task, unsigned long msr)
 }
 
 #ifdef CONFIG_PPC64
-static unsigned long get_user_dscr(struct task_struct *task)
+static int get_user_dscr(struct task_struct *task, unsigned long *data)
 {
-       return task->thread.dscr;
+       *data = task->thread.dscr;
+       return 0;
 }
 
 static int set_user_dscr(struct task_struct *task, unsigned long dscr)
@@ -192,7 +194,7 @@ static int set_user_dscr(struct task_struct *task, unsigned long dscr)
        return 0;
 }
 #else
-static unsigned long get_user_dscr(struct task_struct *task)
+static int get_user_dscr(struct task_struct *task, unsigned long *data)
 {
        return -EIO;
 }
@@ -216,19 +218,23 @@ static int set_user_trap(struct task_struct *task, unsigned long trap)
 /*
  * Get contents of register REGNO in task TASK.
  */
-unsigned long ptrace_get_reg(struct task_struct *task, int regno)
+int ptrace_get_reg(struct task_struct *task, int regno, unsigned long *data)
 {
-       if (task->thread.regs == NULL)
+       if ((task->thread.regs == NULL) || !data)
                return -EIO;
 
-       if (regno == PT_MSR)
-               return get_user_msr(task);
+       if (regno == PT_MSR) {
+               *data = get_user_msr(task);
+               return 0;
+       }
 
        if (regno == PT_DSCR)
-               return get_user_dscr(task);
+               return get_user_dscr(task, data);
 
-       if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long)))
-               return ((unsigned long *)task->thread.regs)[regno];
+       if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long))) {
+               *data = ((unsigned long *)task->thread.regs)[regno];
+               return 0;
+       }
 
        return -EIO;
 }
@@ -1560,7 +1566,9 @@ long arch_ptrace(struct task_struct *child, long request,
 
                CHECK_FULL_REGS(child->thread.regs);
                if (index < PT_FPR0) {
-                       tmp = ptrace_get_reg(child, (int) index);
+                       ret = ptrace_get_reg(child, (int) index, &tmp);
+                       if (ret)
+                               break;
                } else {
                        unsigned int fpidx = index - PT_FPR0;
 
@@ -1637,6 +1645,8 @@ long arch_ptrace(struct task_struct *child, long request,
                dbginfo.sizeof_condition = 0;
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
                dbginfo.features = PPC_DEBUG_FEATURE_DATA_BP_RANGE;
+               if (cpu_has_feature(CPU_FTR_DAWR))
+                       dbginfo.features |= PPC_DEBUG_FEATURE_DATA_BP_DAWR;
 #else
                dbginfo.features = 0;
 #endif /* CONFIG_HAVE_HW_BREAKPOINT */
@@ -1779,6 +1789,8 @@ long do_syscall_trace_enter(struct pt_regs *regs)
 {
        long ret = 0;
 
+       user_exit();
+
        secure_computing_strict(regs->gpr[0]);
 
        if (test_thread_flag(TIF_SYSCALL_TRACE) &&
@@ -1823,4 +1835,6 @@ void do_syscall_trace_leave(struct pt_regs *regs)
        step = test_thread_flag(TIF_SINGLESTEP);
        if (step || test_thread_flag(TIF_SYSCALL_TRACE))
                tracehook_report_syscall_exit(regs, step);
+
+       user_enter();
 }