]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/powerpc/kernel/ptrace32.c
hugetlb: pull gigantic page initialisation out of the default path
[linux-2.6-omap-h63xx.git] / arch / powerpc / kernel / ptrace32.c
index fea6206ff90fd69aaf363075181a927049cb552d..197d49c790ad55b2e67b6b5a989bb9b958dfd14c 100644 (file)
 #include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
+#include <linux/regset.h>
 #include <linux/user.h>
 #include <linux/security.h>
 #include <linux/signal.h>
+#include <linux/compat.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
 static long compat_ptrace_old(struct task_struct *child, long request,
                              long addr, long data)
 {
-       int ret = -EPERM;
-
-       switch(request) {
-       case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
-               int i;
-               unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
-               unsigned int __user *tmp = (unsigned int __user *)addr;
-
-               CHECK_FULL_REGS(child->thread.regs);
-               for (i = 0; i < 32; i++) {
-                       ret = put_user(*reg, tmp);
-                       if (ret)
-                               break;
-                       reg++;
-                       tmp++;
-               }
-               break;
-       }
-
-       case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
-               int i;
-               unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
-               unsigned int __user *tmp = (unsigned int __user *)addr;
-
-               CHECK_FULL_REGS(child->thread.regs);
-               for (i = 0; i < 32; i++) {
-                       ret = get_user(*reg, tmp);
-                       if (ret)
-                               break;
-                       reg++;
-                       tmp++;
-               }
-               break;
+       switch (request) {
+       case PPC_PTRACE_GETREGS:        /* Get GPRs 0 - 31. */
+               return copy_regset_to_user(child,
+                                          task_user_regset_view(current), 0,
+                                          0, 32 * sizeof(compat_long_t),
+                                          compat_ptr(data));
+
+       case PPC_PTRACE_SETREGS:        /* Set GPRs 0 - 31. */
+               return copy_regset_from_user(child,
+                                            task_user_regset_view(current), 0,
+                                            0, 32 * sizeof(compat_long_t),
+                                            compat_ptr(data));
        }
 
-       }
-       return ret;
+       return -EPERM;
 }
 
-long compat_sys_ptrace(int request, int pid, unsigned long addr,
-                      unsigned long data)
+/* Macros to workout the correct index for the FPR in the thread struct */
+#define FPRNUMBER(i) (((i) - PT_FPR0) >> 1)
+#define FPRHALF(i) (((i) - PT_FPR0) & 1)
+#define FPRINDEX(i) TS_FPRWIDTH * FPRNUMBER(i) + FPRHALF(i)
+
+long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
+                       compat_ulong_t caddr, compat_ulong_t cdata)
 {
-       struct task_struct *child;
+       unsigned long addr = caddr;
+       unsigned long data = cdata;
        int ret;
 
-       lock_kernel();
-       if (request == PTRACE_TRACEME) {
-               ret = ptrace_traceme();
-               goto out;
-       }
-
-       child = ptrace_get_task_struct(pid);
-       if (IS_ERR(child)) {
-               ret = PTR_ERR(child);
-               goto out;
-       }
-
-       if (request == PTRACE_ATTACH) {
-               ret = ptrace_attach(child);
-               goto out_tsk;
-       }
-
-       ret = ptrace_check_attach(child, request == PTRACE_KILL);
-       if (ret < 0)
-               goto out_tsk;
-
        switch (request) {
-       /* when I and D space are separate, these will need to be fixed. */
-       case PTRACE_PEEKTEXT: /* read word at location addr. */ 
-       case PTRACE_PEEKDATA: {
-               unsigned int tmp;
-               int copied;
-
-               copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
-               ret = -EIO;
-               if (copied != sizeof(tmp))
-                       break;
-               ret = put_user(tmp, (u32 __user *)data);
-               break;
-       }
-
        /*
         * Read 4 bytes of the other process' storage
         *  data is a pointer specifying where the user wants the
@@ -176,7 +127,8 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
                         * to be an array of unsigned int (32 bits) - the
                         * index passed in is based on this assumption.
                         */
-                       tmp = ((unsigned int *)child->thread.fpr)[index - PT_FPR0];
+                       tmp = ((unsigned int *)child->thread.fpr)
+                               [FPRINDEX(index)];
                }
                ret = put_user((unsigned int)tmp, (u32 __user *)data);
                break;
@@ -216,7 +168,8 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
                CHECK_FULL_REGS(child->thread.regs);
                if (numReg >= PT_FPR0) {
                        flush_fp_to_thread(child);
-                       tmp = ((unsigned long int *)child->thread.fpr)[numReg - PT_FPR0];
+                       tmp = ((unsigned long int *)child->thread.fpr)
+                               [FPRINDEX(numReg)];
                } else { /* register within PT_REGS struct */
                        tmp = ptrace_get_reg(child, numReg);
                } 
@@ -225,19 +178,6 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
                break;
        }
 
-       /* If I and D space are separate, this will have to be fixed. */
-       case PTRACE_POKETEXT: /* write the word at location addr. */
-       case PTRACE_POKEDATA: {
-               unsigned int tmp;
-               tmp = data;
-               ret = 0;
-               if (access_process_vm(child, addr, &tmp, sizeof(tmp), 1)
-                               == sizeof(tmp))
-                       break;
-               ret = -EIO;
-               break;
-       }
-
        /*
         * Write 4 bytes into the other process' storage
         *  data is the 4 bytes that the user wants written
@@ -284,7 +224,8 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
                         * to be an array of unsigned int (32 bits) - the
                         * index passed in is based on this assumption.
                         */
-                       ((unsigned int *)child->thread.fpr)[index - PT_FPR0] = data;
+                       ((unsigned int *)child->thread.fpr)
+                               [FPRINDEX(index)] = data;
                        ret = 0;
                }
                break;
@@ -337,51 +278,24 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
                break;
        }
 
-       case PTRACE_GETEVENTMSG:
-               ret = put_user(child->ptrace_message, (unsigned int __user *) data);
-               break;
+       case PTRACE_GETREGS:    /* Get all pt_regs from the child. */
+               return copy_regset_to_user(
+                       child, task_user_regset_view(current), 0,
+                       0, PT_REGS_COUNT * sizeof(compat_long_t),
+                       compat_ptr(data));
 
-       case PTRACE_GETREGS: { /* Get all pt_regs from the child. */
-               int ui;
-               if (!access_ok(VERIFY_WRITE, (void __user *)data,
-                              PT_REGS_COUNT * sizeof(int))) {
-                       ret = -EIO;
-                       break;
-               }
-               CHECK_FULL_REGS(child->thread.regs);
-               ret = 0;
-               for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
-                       ret |= __put_user(ptrace_get_reg(child, ui),
-                                         (unsigned int __user *) data);
-                       data += sizeof(int);
-               }
-               break;
-       }
-
-       case PTRACE_SETREGS: { /* Set all gp regs in the child. */
-               unsigned long tmp;
-               int ui;
-               if (!access_ok(VERIFY_READ, (void __user *)data,
-                              PT_REGS_COUNT * sizeof(int))) {
-                       ret = -EIO;
-                       break;
-               }
-               CHECK_FULL_REGS(child->thread.regs);
-               ret = 0;
-               for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
-                       ret = __get_user(tmp, (unsigned int __user *) data);
-                       if (ret)
-                               break;
-                       ptrace_put_reg(child, ui, tmp);
-                       data += sizeof(int);
-               }
-               break;
-       }
+       case PTRACE_SETREGS:    /* Set all gp regs in the child. */
+               return copy_regset_from_user(
+                       child, task_user_regset_view(current), 0,
+                       0, PT_REGS_COUNT * sizeof(compat_long_t),
+                       compat_ptr(data));
 
        case PTRACE_GETFPREGS:
        case PTRACE_SETFPREGS:
        case PTRACE_GETVRREGS:
        case PTRACE_SETVRREGS:
+       case PTRACE_GETVSRREGS:
+       case PTRACE_SETVSRREGS:
        case PTRACE_GETREGS64:
        case PTRACE_SETREGS64:
        case PPC_PTRACE_GETFPREGS:
@@ -402,12 +316,9 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
                break;
 
        default:
-               ret = ptrace_request(child, request, addr, data);
+               ret = compat_ptrace_request(child, request, addr, data);
                break;
        }
-out_tsk:
-       put_task_struct(child);
-out:
-       unlock_kernel();
+
        return ret;
 }