diff options
Diffstat (limited to 'arch/ppc/kernel/ptrace.c')
-rw-r--r-- | arch/ppc/kernel/ptrace.c | 124 |
1 files changed, 73 insertions, 51 deletions
diff --git a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c index dc4012f57..2d960c8cd 100644 --- a/arch/ppc/kernel/ptrace.c +++ b/arch/ppc/kernel/ptrace.c @@ -7,6 +7,7 @@ * * Adapted from 'linux/arch/m68k/kernel/ptrace.c' * PowerPC version by Gary Thomas (gdt@linuxppc.org) + * Modified by Cort Dougan (cort@cs.nmt.edu) * * This file is subject to the terms and conditions of the GNU General * Public License. See the file README.legal in the main directory of @@ -17,6 +18,8 @@ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> #include <linux/errno.h> #include <linux/ptrace.h> #include <linux/user.h> @@ -264,7 +267,7 @@ static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigne struct vm_area_struct * vma; addr &= PAGE_MASK; - vma = find_vma(tsk,addr); + vma = find_vma(tsk->mm,addr); if (!vma) return NULL; if (vma->vm_start <= addr) @@ -375,34 +378,37 @@ static int write_long(struct task_struct * tsk, unsigned long addr, asmlinkage int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; - struct user * dummy; - - dummy = NULL; + struct user * dummy = NULL; + int ret = -EPERM; + lock_kernel(); if (request == PTRACE_TRACEME) { /* are we already being traced? */ if (current->flags & PF_PTRACED) - return -EPERM; + goto out; /* set the ptrace bit in the process flags. */ current->flags |= PF_PTRACED; - return 0; + ret = 0; + goto out; } if (pid == 1) /* you may not mess with init */ - return -EPERM; + goto out; + ret = -ESRCH; if (!(child = get_task(pid))) - return -ESRCH; + goto out; + ret = -EPERM; if (request == PTRACE_ATTACH) { if (child == current) - return -EPERM; + goto out; if ((!child->dumpable || (current->uid != child->euid) || (current->uid != child->uid) || (current->gid != child->egid) || (current->gid != child->gid)) && !suser()) - return -EPERM; + goto out; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) - return -EPERM; + goto out; child->flags |= PF_PTRACED; if (child->p_pptr != current) { REMOVE_LINKS(child); @@ -410,73 +416,75 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) SET_LINKS(child); } send_sig(SIGSTOP, child, 1); - return 0; + ret = 0; + goto out; } + ret = -ESRCH; if (!(child->flags & PF_PTRACED)) - return -ESRCH; + goto out; if (child->state != TASK_STOPPED) { if (request != PTRACE_KILL) - return -ESRCH; + goto out; } if (child->p_pptr != current) - return -ESRCH; + goto out; switch (request) { /* If I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: { unsigned long tmp; - int res; - res = read_long(child, addr, &tmp); - if (res < 0) - return res; - res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long)); - if (!res) + ret = read_long(child, addr, &tmp); + if (ret < 0) + goto out; + ret = verify_area(VERIFY_WRITE, (void *) data, sizeof(long)); + if (!ret) put_user(tmp, (unsigned long *) data); - return res; + goto out; } /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { unsigned long tmp; - int res; if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) return -EIO; - res = verify_area(VERIFY_WRITE, (void *) data, + ret = verify_area(VERIFY_WRITE, (void *) data, sizeof(long)); - if (res) - return res; + if (ret) + goto out; tmp = 0; /* Default return condition */ addr = addr >> 2; /* temporary hack. */ - if (addr < PT_FPR0) { + if (addr < PT_FPR0) tmp = get_reg(child, addr); - } #if 0 else if (addr >= PT_FPR0 && addr < PT_FPR31) tmp = child->tss.fpr[addr - PT_FPR0]; #endif else - return -EIO; - put_user(tmp,(unsigned long *) data); - return 0; + ret = -EIO; + if(!ret) + put_user(tmp,(unsigned long *) data); + goto out; } /* 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: - return write_long(child,addr,data); + ret = write_long(child,addr,data); + goto out; case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + ret = -EIO; if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) - return -EIO; + goto out; addr = addr >> 2; /* temporary hack. */ if (addr == PT_ORIG_R3) - return -EIO; + goto out; #if 0 /* Let this check be in 'put_reg' */ if (addr == PT_SR) { data &= SR_MASK; @@ -486,22 +494,24 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) #endif if (addr < PT_FPR0) { if (put_reg(child, addr, data)) - return -EIO; - return 0; + goto out; + ret = 0; + goto out; } #if 0 - if (addr >= 21 && addr < 48) - { + if (addr >= 21 && addr < 48) { child->tss.fp[addr - 21] = data; - return 0; + ret = 0; + goto out; } #endif - return -EIO; + goto out; case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ + ret = -EIO; if ((unsigned long) data >= NSIG) - return -EIO; + goto out; if (request == PTRACE_SYSCALL) child->flags |= PF_TRACESYS; else @@ -510,7 +520,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) wake_up_process(child); /* make sure the single step bit is not set. */ clear_single_step(child); - return 0; + ret = 0; + goto out; } /* @@ -519,29 +530,33 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) * exit. */ case PTRACE_KILL: { + ret = 0; if (child->state == TASK_ZOMBIE) /* already dead */ - return 0; + goto out; wake_up_process(child); child->exit_code = SIGKILL; /* make sure the single step bit is not set. */ clear_single_step(child); - return 0; + goto out; } case PTRACE_SINGLESTEP: { /* set the trap flag. */ + ret = -EIO; if ((unsigned long) data >= NSIG) - return -EIO; + goto out; child->flags &= ~PF_TRACESYS; set_single_step(child); wake_up_process(child); child->exit_code = data; /* give it a chance to run. */ - return 0; + ret = 0; + goto out; } case PTRACE_DETACH: { /* detach a process that was attached. */ + ret = -EIO; if ((unsigned long) data >= NSIG) - return -EIO; + goto out; child->flags &= ~(PF_PTRACED|PF_TRACESYS); wake_up_process(child); child->exit_code = data; @@ -550,19 +565,25 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) SET_LINKS(child); /* make sure the single step bit is not set. */ clear_single_step(child); - return 0; + ret = 0; + goto out; } default: - return -EIO; + ret = -EIO; + goto out; } +out: + unlock_kernel(); + return ret; } asmlinkage void syscall_trace(void) { + lock_kernel(); if ((current->flags & (PF_PTRACED|PF_TRACESYS)) != (PF_PTRACED|PF_TRACESYS)) - return; + goto out; current->exit_code = SIGTRAP; current->state = TASK_STOPPED; notify_parent(current); @@ -575,5 +596,6 @@ asmlinkage void syscall_trace(void) if (current->exit_code) current->signal |= (1 << (current->exit_code - 1)); current->exit_code = 0; - return; +out: + unlock_kernel(); } |