mips: use generic ptrace_resume code
[safe/jmp/linux-2.6] / arch / mips / kernel / ptrace.c
index 96ffc9c..c51b95f 100644 (file)
@@ -46,7 +46,8 @@
  */
 void ptrace_disable(struct task_struct *child)
 {
-       /* Nothing to do.. */
+       /* Don't load the watchpoint registers for the ex-child. */
+       clear_tsk_thread_flag(child, TIF_LOAD_WATCH);
 }
 
 /*
@@ -167,6 +168,93 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data)
        return 0;
 }
 
+int ptrace_get_watch_regs(struct task_struct *child,
+                         struct pt_watch_regs __user *addr)
+{
+       enum pt_watch_style style;
+       int i;
+
+       if (!cpu_has_watch || current_cpu_data.watch_reg_use_cnt == 0)
+               return -EIO;
+       if (!access_ok(VERIFY_WRITE, addr, sizeof(struct pt_watch_regs)))
+               return -EIO;
+
+#ifdef CONFIG_32BIT
+       style = pt_watch_style_mips32;
+#define WATCH_STYLE mips32
+#else
+       style = pt_watch_style_mips64;
+#define WATCH_STYLE mips64
+#endif
+
+       __put_user(style, &addr->style);
+       __put_user(current_cpu_data.watch_reg_use_cnt,
+                  &addr->WATCH_STYLE.num_valid);
+       for (i = 0; i < current_cpu_data.watch_reg_use_cnt; i++) {
+               __put_user(child->thread.watch.mips3264.watchlo[i],
+                          &addr->WATCH_STYLE.watchlo[i]);
+               __put_user(child->thread.watch.mips3264.watchhi[i] & 0xfff,
+                          &addr->WATCH_STYLE.watchhi[i]);
+               __put_user(current_cpu_data.watch_reg_masks[i],
+                          &addr->WATCH_STYLE.watch_masks[i]);
+       }
+       for (; i < 8; i++) {
+               __put_user(0, &addr->WATCH_STYLE.watchlo[i]);
+               __put_user(0, &addr->WATCH_STYLE.watchhi[i]);
+               __put_user(0, &addr->WATCH_STYLE.watch_masks[i]);
+       }
+
+       return 0;
+}
+
+int ptrace_set_watch_regs(struct task_struct *child,
+                         struct pt_watch_regs __user *addr)
+{
+       int i;
+       int watch_active = 0;
+       unsigned long lt[NUM_WATCH_REGS];
+       u16 ht[NUM_WATCH_REGS];
+
+       if (!cpu_has_watch || current_cpu_data.watch_reg_use_cnt == 0)
+               return -EIO;
+       if (!access_ok(VERIFY_READ, addr, sizeof(struct pt_watch_regs)))
+               return -EIO;
+       /* Check the values. */
+       for (i = 0; i < current_cpu_data.watch_reg_use_cnt; i++) {
+               __get_user(lt[i], &addr->WATCH_STYLE.watchlo[i]);
+#ifdef CONFIG_32BIT
+               if (lt[i] & __UA_LIMIT)
+                       return -EINVAL;
+#else
+               if (test_tsk_thread_flag(child, TIF_32BIT_ADDR)) {
+                       if (lt[i] & 0xffffffff80000000UL)
+                               return -EINVAL;
+               } else {
+                       if (lt[i] & __UA_LIMIT)
+                               return -EINVAL;
+               }
+#endif
+               __get_user(ht[i], &addr->WATCH_STYLE.watchhi[i]);
+               if (ht[i] & ~0xff8)
+                       return -EINVAL;
+       }
+       /* Install them. */
+       for (i = 0; i < current_cpu_data.watch_reg_use_cnt; i++) {
+               if (lt[i] & 7)
+                       watch_active = 1;
+               child->thread.watch.mips3264.watchlo[i] = lt[i];
+               /* Set the G bit. */
+               child->thread.watch.mips3264.watchhi[i] = ht[i];
+       }
+
+       if (watch_active)
+               set_tsk_thread_flag(child, TIF_LOAD_WATCH);
+       else
+               clear_tsk_thread_flag(child, TIF_LOAD_WATCH);
+
+       return 0;
+}
+
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 {
        int ret;
@@ -405,39 +493,19 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                ret = ptrace_setfpregs(child, (__u32 __user *) data);
                break;
 
-       case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
-       case PTRACE_CONT: { /* restart after signal. */
-               ret = -EIO;
-               if (!valid_signal(data))
-                       break;
-               if (request == PTRACE_SYSCALL) {
-                       set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               }
-               else {
-                       clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-               }
-               child->exit_code = data;
-               wake_up_process(child);
-               ret = 0;
+       case PTRACE_GET_THREAD_AREA:
+               ret = put_user(task_thread_info(child)->tp_value,
+                               (unsigned long __user *) data);
                break;
-       }
 
-       /*
-        * make the child exit.  Best I can do is send it a sigkill.
-        * perhaps it should be put in the status that it wants to
-        * exit.
-        */
-       case PTRACE_KILL:
-               ret = 0;
-               if (child->exit_state == EXIT_ZOMBIE)   /* already dead */
-                       break;
-               child->exit_code = SIGKILL;
-               wake_up_process(child);
+       case PTRACE_GET_WATCH_REGS:
+               ret = ptrace_get_watch_regs(child,
+                                       (struct pt_watch_regs __user *) addr);
                break;
 
-       case PTRACE_GET_THREAD_AREA:
-               ret = put_user(task_thread_info(child)->tp_value,
-                               (unsigned long __user *) data);
+       case PTRACE_SET_WATCH_REGS:
+               ret = ptrace_set_watch_regs(child,
+                                       (struct pt_watch_regs __user *) addr);
                break;
 
        default: