summaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/ptrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/ptrace.c')
-rw-r--r--arch/mips/kernel/ptrace.c291
1 files changed, 159 insertions, 132 deletions
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index f9172b726..05fafefe3 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -1,8 +1,14 @@
-/* ptrace.c */
-/* By Ross Biro 1/23/92 */
-/* edited by Linus Torvalds */
-/* further hacked for MIPS by David S. Miller (dm@engr.sgi.com) */
-
+/* $Id: ptrace.c,v 1.9 1998/07/16 17:01:52 ralf Exp $
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 Ross Biro
+ * Copyright (C) Linus Torvalds
+ * Copyright (C) 1994, 1995, 1996, 1997, 1998 Ralf Baechle
+ * Copyright (C) 1996 David S. Miller
+ */
#include <linux/head.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -13,10 +19,12 @@
#include <linux/smp_lock.h>
#include <linux/user.h>
-#include <asm/uaccess.h>
+#include <asm/fp.h>
+#include <asm/mipsregs.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/system.h>
+#include <asm/uaccess.h>
/*
* This routine gets a long from any process space by following the page
@@ -326,163 +334,182 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
}
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 long tmp;
+ case PTRACE_PEEKTEXT: /* read word at location addr. */
+ case PTRACE_PEEKDATA: {
+ unsigned long tmp;
- res = read_long(child, addr, &tmp);
- if (res < 0)
- goto out;
- res = put_user(tmp,(unsigned long *) data);
+ res = read_long(child, addr, &tmp);
+ if (res < 0)
goto out;
+ res = put_user(tmp,(unsigned long *) data);
+ goto out;
}
/* read the word at location addr in the USER area. */
/* #define DEBUG_PEEKUSR */
- case PTRACE_PEEKUSR: {
- struct pt_regs *regs;
- unsigned long tmp;
+ case PTRACE_PEEKUSR: {
+ struct pt_regs *regs;
+ unsigned long tmp;
- regs = (struct pt_regs *) ((unsigned long) child +
- KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
- tmp = 0; /* Default return value. */
- if(addr < 32 && addr >= 0) {
- tmp = regs->regs[addr];
- } else if(addr >= 32 && addr < 64) {
- unsigned long long *fregs;
+ regs = (struct pt_regs *) ((unsigned long) child +
+ KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
+ tmp = 0; /* Default return value. */
+ if (addr < 32 && addr >= 0)
+ tmp = regs->regs[addr];
+ else if (addr >= 32 && addr < 64) {
+ unsigned long long *fregs;
- /* We don't want to do a FPU operation here. */
+ if (child->used_math) {
+ if (last_task_used_math == child) {
+ enable_cp1();
+ r4xx0_save_fp(child);
+ disable_cp1();
+ last_task_used_math = NULL;
+ }
fregs = (unsigned long long *)
&child->tss.fpu.hard.fp_regs[0];
tmp = (unsigned long) fregs[(addr - 32)];
} else {
- addr -= 64;
- switch(addr) {
- case 0:
- tmp = regs->cp0_epc;
- break;
- case 1:
- tmp = regs->cp0_cause;
- break;
- case 2:
- tmp = regs->cp0_badvaddr;
- break;
- case 3:
- tmp = regs->lo;
- break;
- case 4:
- tmp = regs->hi;
- break;
- case 5:
- tmp = child->tss.fpu.hard.control;
- break;
- case 6: /* implementation / version register */
- tmp = 0;
- break;
- default:
- tmp = 0;
- res = -EIO;
- goto out;
- };
+ tmp = -1; /* FP not yet used */
}
- res = put_user(tmp, (unsigned long *) data);
- goto out;
+ } else {
+ addr -= 64;
+ switch(addr) {
+ case 0:
+ tmp = regs->cp0_epc;
+ break;
+ case 1:
+ tmp = regs->cp0_cause;
+ break;
+ case 2:
+ tmp = regs->cp0_badvaddr;
+ break;
+ case 3:
+ tmp = regs->lo;
+ break;
+ case 4:
+ tmp = regs->hi;
+ break;
+ case 5:
+ tmp = child->tss.fpu.hard.control;
+ break;
+ case 6: /* implementation / version register */
+ tmp = 0; /* XXX */
+ break;
+ default:
+ tmp = 0;
+ res = -EIO;
+ goto out;
+ }
+ }
+ res = put_user(tmp, (unsigned long *) data);
+ goto out;
}
- /* when I and D space are separate, this will have to be fixed. */
- case PTRACE_POKETEXT: /* write the word at location addr. */
- case PTRACE_POKEDATA:
- res = write_long(child,addr,data);
- goto out;
+ case PTRACE_POKETEXT: /* write the word at location addr. */
+ case PTRACE_POKEDATA:
+ res = write_long(child,addr,data);
+ goto out;
- case PTRACE_POKEUSR: {
- struct pt_regs *regs;
- int res = 0;
+ case PTRACE_POKEUSR: {
+ struct pt_regs *regs;
+ int res = 0;
- regs = (struct pt_regs *) ((unsigned long) child +
- KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
- if(addr < 32 && addr >= 0) {
- regs->regs[addr] = data;
- } else if(addr >= 32 && addr < 64) {
- unsigned long long *fregs;
+ regs = (struct pt_regs *) ((unsigned long) child +
+ KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
+ if (addr < 32 && addr >= 0)
+ regs->regs[addr] = data;
+ else if (addr >= 32 && addr < 64) {
+ unsigned long long *fregs;
- /* We don't want to do a FPU operation here. */
- fregs = (unsigned long long *)
- &child->tss.fpu.hard.fp_regs[0];
- fregs[(addr - 32)] = (unsigned long long) data;
+ if (child->used_math) {
+ if (last_task_used_math == child) {
+ enable_cp1();
+ r4xx0_save_fp(child);
+ disable_cp1();
+ last_task_used_math = NULL;
+ }
} else {
- addr -= 64;
- switch(addr) {
- case 0:
- regs->cp0_epc = data;
- break;
- case 3:
- regs->lo = data;
- break;
- case 4:
- regs->hi = data;
- break;
- case 5:
- child->tss.fpu.hard.control = data;
- break;
- default:
- /* The rest are not allowed. */
- res = -EIO;
- break;
- };
+ /* FP not yet used */
+ memset(&child->tss.fpu.hard, ~0,
+ sizeof(child->tss.fpu.hard));
+ child->tss.fpu.hard.control = 0;
}
- goto out;
- }
-
- case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
- case PTRACE_CONT: { /* restart after signal. */
- if ((unsigned long) data > _NSIG) {
+ fregs = (unsigned long long *)
+ &child->tss.fpu.hard.fp_regs[0];
+ fregs[(addr - 32)] = (unsigned long long) data;
+ } else {
+ addr -= 64;
+ switch (addr) {
+ case 0:
+ regs->cp0_epc = data;
+ break;
+ case 3:
+ regs->lo = data;
+ break;
+ case 4:
+ regs->hi = data;
+ break;
+ case 5:
+ child->tss.fpu.hard.control = data;
+ break;
+ default:
+ /* The rest are not allowed. */
res = -EIO;
- goto out;
- }
- if (request == PTRACE_SYSCALL)
- child->flags |= PF_TRACESYS;
- else
- child->flags &= ~PF_TRACESYS;
- child->exit_code = data;
- wake_up_process(child);
- res = data;
- goto out;
+ break;
+ };
+ }
+ goto out;
}
-/*
- * 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: {
- if (child->state != TASK_ZOMBIE) {
- wake_up_process(child);
- child->exit_code = SIGKILL;
- }
- res = 0;
+ case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+ case PTRACE_CONT: { /* restart after signal. */
+ if ((unsigned long) data > _NSIG) {
+ res = -EIO;
goto out;
}
+ if (request == PTRACE_SYSCALL)
+ child->flags |= PF_TRACESYS;
+ else
+ child->flags &= ~PF_TRACESYS;
+ child->exit_code = data;
+ wake_up_process(child);
+ res = data;
+ goto out;
+ }
- case PTRACE_DETACH: { /* detach a process that was attached. */
- if ((unsigned long) data > _NSIG) {
- res = -EIO;
- goto out;
- }
- child->flags &= ~(PF_PTRACED|PF_TRACESYS);
+ /*
+ * 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: {
+ if (child->state != TASK_ZOMBIE) {
wake_up_process(child);
- child->exit_code = data;
- REMOVE_LINKS(child);
- child->p_pptr = child->p_opptr;
- SET_LINKS(child);
- res = 0;
- goto out;
+ child->exit_code = SIGKILL;
+ }
+ res = 0;
+ goto out;
}
- default:
+ case PTRACE_DETACH: { /* detach a process that was attached. */
+ if ((unsigned long) data > _NSIG) {
res = -EIO;
goto out;
+ }
+ child->flags &= ~(PF_PTRACED|PF_TRACESYS);
+ wake_up_process(child);
+ child->exit_code = data;
+ REMOVE_LINKS(child);
+ child->p_pptr = child->p_opptr;
+ SET_LINKS(child);
+ res = 0;
+ goto out;
+ }
+
+ default:
+ res = -EIO;
+ goto out;
}
out:
unlock_kernel();