aboutsummaryrefslogtreecommitdiff
path: root/arch/cris/arch-v32/kernel/ptrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/cris/arch-v32/kernel/ptrace.c')
-rw-r--r--arch/cris/arch-v32/kernel/ptrace.c201
1 files changed, 47 insertions, 154 deletions
diff --git a/arch/cris/arch-v32/kernel/ptrace.c b/arch/cris/arch-v32/kernel/ptrace.c
index 208489da2a8..f085229cf87 100644
--- a/arch/cris/arch-v32/kernel/ptrace.c
+++ b/arch/cris/arch-v32/kernel/ptrace.c
@@ -1,12 +1,11 @@
/*
- * Copyright (C) 2000-2003, Axis Communications AB.
+ * Copyright (C) 2000-2007, Axis Communications AB.
*/
#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>
@@ -16,9 +15,8 @@
#include <asm/uaccess.h>
#include <asm/page.h>
#include <asm/pgtable.h>
-#include <asm/system.h>
#include <asm/processor.h>
-#include <asm/arch/hwregs/supp_reg.h>
+#include <arch/hwregs/supp_reg.h>
/*
* Determines which bits in CCS the user has access to.
@@ -46,7 +44,7 @@ long get_reg(struct task_struct *task, unsigned int regno)
unsigned long ret;
if (regno <= PT_EDA)
- ret = ((unsigned long *)user_regs(task->thread_info))[regno];
+ ret = ((unsigned long *)task_pt_regs(task))[regno];
else if (regno == PT_USP)
ret = task->thread.usp;
else if (regno == PT_PPC)
@@ -65,13 +63,13 @@ long get_reg(struct task_struct *task, unsigned int regno)
int put_reg(struct task_struct *task, unsigned int regno, unsigned long data)
{
if (regno <= PT_EDA)
- ((unsigned long *)user_regs(task->thread_info))[regno] = data;
+ ((unsigned long *)task_pt_regs(task))[regno] = data;
else if (regno == PT_USP)
task->thread.usp = data;
else if (regno == PT_PPC) {
/* Write pseudo-PC to ERP only if changed. */
if (data != get_pseudo_pc(task))
- ((unsigned long *)user_regs(task->thread_info))[PT_ERP] = data;
+ task_pt_regs(task)->erp = data;
} else if (regno <= PT_MAX)
return put_debugreg(task->pid, regno, data);
else
@@ -79,6 +77,35 @@ int put_reg(struct task_struct *task, unsigned int regno, unsigned long data)
return 0;
}
+void user_enable_single_step(struct task_struct *child)
+{
+ unsigned long tmp;
+
+ /*
+ * Set up SPC if not set already (in which case we have no other
+ * choice but to trust it).
+ */
+ if (!get_reg(child, PT_SPC)) {
+ /* In case we're stopped in a delay slot. */
+ tmp = get_reg(child, PT_ERP) & ~1;
+ put_reg(child, PT_SPC, tmp);
+ }
+ tmp = get_reg(child, PT_CCS) | SBIT_USER;
+ put_reg(child, PT_CCS, tmp);
+}
+
+void user_disable_single_step(struct task_struct *child)
+{
+ put_reg(child, PT_SPC, 0);
+
+ if (!get_debugreg(child->pid, PT_BP_CTRL)) {
+ unsigned long tmp;
+ /* If no h/w bp configured, disable S bit. */
+ tmp = get_reg(child, PT_CCS) & ~SBIT_USER;
+ put_reg(child, PT_CCS, tmp);
+ }
+}
+
/*
* Called by kernel/ptrace.c when detaching.
*
@@ -87,11 +114,8 @@ int put_reg(struct task_struct *task, unsigned int regno, unsigned long data)
void
ptrace_disable(struct task_struct *child)
{
- unsigned long tmp;
-
/* Deconfigure SPC and S-bit. */
- tmp = get_reg(child, PT_CCS) & ~SBIT_USER;
- put_reg(child, PT_CCS, tmp);
+ user_disable_single_step(child);
put_reg(child, PT_SPC, 0);
/* Deconfigure any watchpoints associated with the child. */
@@ -99,55 +123,13 @@ ptrace_disable(struct task_struct *child)
}
-asmlinkage int
-sys_ptrace(long request, long pid, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
- struct task_struct *child;
int ret;
+ unsigned int regno = addr >> 2;
unsigned long __user *datap = (unsigned long __user *)data;
- lock_kernel();
- ret = -EPERM;
-
- if (request == PTRACE_TRACEME) {
- /* are we already being traced? */
- if (current->ptrace & PT_PTRACED)
- goto out;
- ret = security_ptrace(current->parent, current);
- if (ret)
- goto out;
- /* set the ptrace bit in the process flags. */
- current->ptrace |= PT_PTRACED;
- ret = 0;
- goto out;
- }
-
- ret = -ESRCH;
- read_lock(&tasklist_lock);
- child = find_task_by_pid(pid);
-
- if (child)
- get_task_struct(child);
-
- read_unlock(&tasklist_lock);
-
- if (!child)
- goto out;
-
- ret = -EPERM;
-
- if (pid == 1) /* Leave the init process alone! */
- goto out_tsk;
-
- 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) {
/* Read word at location address. */
case PTRACE_PEEKTEXT:
@@ -180,10 +162,10 @@ sys_ptrace(long request, long pid, long addr, long data)
unsigned long tmp;
ret = -EIO;
- if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
+ if ((addr & 3) || regno > PT_MAX)
break;
- tmp = get_reg(child, addr >> 2);
+ tmp = get_reg(child, regno);
ret = put_user(tmp, datap);
break;
}
@@ -191,117 +173,30 @@ sys_ptrace(long request, long pid, long addr, long data)
/* Write the word at location address. */
case PTRACE_POKETEXT:
case PTRACE_POKEDATA:
- ret = 0;
-
- if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
- break;
-
- ret = -EIO;
+ ret = generic_ptrace_pokedata(child, addr, data);
break;
- /* Write the word at location address in the USER area. */
+ /* Write the word at location address in the USER area. */
case PTRACE_POKEUSR:
ret = -EIO;
- if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
+ if ((addr & 3) || regno > PT_MAX)
break;
- addr >>= 2;
-
- if (addr == PT_CCS) {
+ if (regno == PT_CCS) {
/* don't allow the tracing process to change stuff like
* interrupt enable, kernel/user bit, dma enables etc.
*/
data &= CCS_MASK;
data |= get_reg(child, PT_CCS) & ~CCS_MASK;
}
- if (put_reg(child, addr, data))
+ if (put_reg(child, regno, data))
break;
ret = 0;
break;
- case PTRACE_SYSCALL:
- case PTRACE_CONT:
- ret = -EIO;
-
- if (!valid_signal(data))
- break;
-
- /* Continue means no single-step. */
- put_reg(child, PT_SPC, 0);
-
- if (!get_debugreg(child->pid, PT_BP_CTRL)) {
- unsigned long tmp;
- /* If no h/w bp configured, disable S bit. */
- tmp = get_reg(child, PT_CCS) & ~SBIT_USER;
- put_reg(child, PT_CCS, tmp);
- }
-
- 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;
-
- /* TODO: make sure any pending breakpoint is killed */
- wake_up_process(child);
- ret = 0;
-
- break;
-
- /* Make the child exit by sending it a sigkill. */
- case PTRACE_KILL:
- ret = 0;
-
- if (child->exit_state == EXIT_ZOMBIE)
- break;
-
- child->exit_code = SIGKILL;
-
- /* Deconfigure single-step and h/w bp. */
- ptrace_disable(child);
-
- /* TODO: make sure any pending breakpoint is killed */
- wake_up_process(child);
- break;
-
- /* Set the trap flag. */
- case PTRACE_SINGLESTEP: {
- unsigned long tmp;
- ret = -EIO;
-
- /* Set up SPC if not set already (in which case we have
- no other choice but to trust it). */
- if (!get_reg(child, PT_SPC)) {
- /* In case we're stopped in a delay slot. */
- tmp = get_reg(child, PT_ERP) & ~1;
- put_reg(child, PT_SPC, tmp);
- }
- tmp = get_reg(child, PT_CCS) | SBIT_USER;
- put_reg(child, PT_CCS, tmp);
-
- if (!valid_signal(data))
- break;
-
- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-
- /* TODO: set some clever breakpoint mechanism... */
-
- child->exit_code = data;
- wake_up_process(child);
- ret = 0;
- break;
-
- }
- case PTRACE_DETACH:
- ret = ptrace_detach(child, data);
- break;
-
/* Get all GP registers from the child. */
case PTRACE_GETREGS: {
- int i;
+ int i;
unsigned long tmp;
for (i = 0; i <= PT_MAX; i++) {
@@ -347,10 +242,8 @@ sys_ptrace(long request, long pid, long addr, long data)
ret = ptrace_request(child, request, addr, data);
break;
}
+
out_tsk:
- put_task_struct(child);
-out:
- unlock_kernel();
return ret;
}