summaryrefslogtreecommitdiffstats
path: root/arch/ppc/kernel/ptrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc/kernel/ptrace.c')
-rw-r--r--arch/ppc/kernel/ptrace.c124
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();
}