aboutsummaryrefslogtreecommitdiffstats
path: root/arch/microblaze/kernel/ptrace.c
diff options
context:
space:
mode:
authorMichal Simek <monstr@monstr.eu>2009-03-27 09:25:27 -0400
committerMichal Simek <monstr@monstr.eu>2009-03-27 09:25:27 -0400
commit2b4384542691fddd309f9324b5a9af976b75e918 (patch)
treef3efa65d108504d72e228687ccab9c718f1fe7a9 /arch/microblaze/kernel/ptrace.c
parent216f03481d2fca7094f5f982a65acfc2ca14fa85 (diff)
microblaze_v8: ptrace support
Reviewed-by: Ingo Molnar <mingo@elte.hu> Acked-by: John Linn <john.linn@xilinx.com> Acked-by: Stephen Neuendorffer <stephen.neuendorffer@xilinx.com> Acked-by: John Williams <john.williams@petalogix.com> Signed-off-by: Michal Simek <monstr@monstr.eu>
Diffstat (limited to 'arch/microblaze/kernel/ptrace.c')
-rw-r--r--arch/microblaze/kernel/ptrace.c182
1 files changed, 182 insertions, 0 deletions
diff --git a/arch/microblaze/kernel/ptrace.c b/arch/microblaze/kernel/ptrace.c
new file mode 100644
index 000000000000..3171e39e3220
--- /dev/null
+++ b/arch/microblaze/kernel/ptrace.c
@@ -0,0 +1,182 @@
1/*
2 * `ptrace' system call
3 *
4 * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
5 * Copyright (C) 2007-2009 PetaLogix
6 * Copyright (C) 2004-2007 John Williams <john.williams@petalogix.com>
7 *
8 * derived from arch/v850/kernel/ptrace.c
9 *
10 * Copyright (C) 2002,03 NEC Electronics Corporation
11 * Copyright (C) 2002,03 Miles Bader <miles@gnu.org>
12 *
13 * Derived from arch/mips/kernel/ptrace.c:
14 *
15 * Copyright (C) 1992 Ross Biro
16 * Copyright (C) Linus Torvalds
17 * Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle
18 * Copyright (C) 1996 David S. Miller
19 * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
20 * Copyright (C) 1999 MIPS Technologies, Inc.
21 *
22 * This file is subject to the terms and conditions of the GNU General
23 * Public License. See the file COPYING in the main directory of this
24 * archive for more details.
25 */
26
27#include <linux/kernel.h>
28#include <linux/mm.h>
29#include <linux/sched.h>
30#include <linux/smp_lock.h>
31#include <linux/ptrace.h>
32#include <linux/signal.h>
33
34#include <linux/errno.h>
35#include <linux/ptrace.h>
36#include <asm/processor.h>
37#include <linux/uaccess.h>
38#include <asm/asm-offsets.h>
39
40/* Returns the address where the register at REG_OFFS in P is stashed away. */
41static microblaze_reg_t *reg_save_addr(unsigned reg_offs,
42 struct task_struct *t)
43{
44 struct pt_regs *regs;
45
46 /*
47 * Three basic cases:
48 *
49 * (1) A register normally saved before calling the scheduler, is
50 * available in the kernel entry pt_regs structure at the top
51 * of the kernel stack. The kernel trap/irq exit path takes
52 * care to save/restore almost all registers for ptrace'd
53 * processes.
54 *
55 * (2) A call-clobbered register, where the process P entered the
56 * kernel via [syscall] trap, is not stored anywhere; that's
57 * OK, because such registers are not expected to be preserved
58 * when the trap returns anyway (so we don't actually bother to
59 * test for this case).
60 *
61 * (3) A few registers not used at all by the kernel, and so
62 * normally never saved except by context-switches, are in the
63 * context switch state.
64 */
65
66 /* Register saved during kernel entry (or not available). */
67 regs = task_pt_regs(t);
68
69 return (microblaze_reg_t *)((char *)regs + reg_offs);
70}
71
72long arch_ptrace(struct task_struct *child, long request, long addr, long data)
73{
74 int rval;
75 unsigned long val = 0;
76 unsigned long copied;
77
78 switch (request) {
79 case PTRACE_PEEKTEXT: /* read word at location addr. */
80 case PTRACE_PEEKDATA:
81 pr_debug("PEEKTEXT/PEEKDATA at %08lX\n", addr);
82 copied = access_process_vm(child, addr, &val, sizeof(val), 0);
83 rval = -EIO;
84 if (copied != sizeof(val))
85 break;
86 rval = put_user(val, (unsigned long *)data);
87 break;
88
89 case PTRACE_POKETEXT: /* write the word at location addr. */
90 case PTRACE_POKEDATA:
91 pr_debug("POKETEXT/POKEDATA to %08lX\n", addr);
92 rval = 0;
93 if (access_process_vm(child, addr, &data, sizeof(data), 1)
94 == sizeof(data))
95 break;
96 rval = -EIO;
97 break;
98
99 /* Read/write the word at location ADDR in the registers. */
100 case PTRACE_PEEKUSR:
101 case PTRACE_POKEUSR:
102 pr_debug("PEEKUSR/POKEUSR : 0x%08lx\n", addr);
103 rval = 0;
104 if (addr >= PT_SIZE && request == PTRACE_PEEKUSR) {
105 /*
106 * Special requests that don't actually correspond
107 * to offsets in struct pt_regs.
108 */
109 if (addr == PT_TEXT_ADDR) {
110 val = child->mm->start_code;
111 } else if (addr == PT_DATA_ADDR) {
112 val = child->mm->start_data;
113 } else if (addr == PT_TEXT_LEN) {
114 val = child->mm->end_code
115 - child->mm->start_code;
116 } else {
117 rval = -EIO;
118 }
119 } else if (addr >= 0 && addr < PT_SIZE && (addr & 0x3) == 0) {
120 microblaze_reg_t *reg_addr = reg_save_addr(addr, child);
121 if (request == PTRACE_PEEKUSR)
122 val = *reg_addr;
123 else
124 *reg_addr = data;
125 } else
126 rval = -EIO;
127
128 if (rval == 0 && request == PTRACE_PEEKUSR)
129 rval = put_user(val, (unsigned long *)data);
130 break;
131 /* Continue and stop at next (return from) syscall */
132 case PTRACE_SYSCALL:
133 pr_debug("PTRACE_SYSCALL\n");
134 case PTRACE_SINGLESTEP:
135 pr_debug("PTRACE_SINGLESTEP\n");
136 /* Restart after a signal. */
137 case PTRACE_CONT:
138 pr_debug("PTRACE_CONT\n");
139 rval = -EIO;
140 if (!valid_signal(data))
141 break;
142
143 if (request == PTRACE_SYSCALL)
144 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
145 else
146 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
147
148 child->exit_code = data;
149 pr_debug("wakeup_process\n");
150 wake_up_process(child);
151 rval = 0;
152 break;
153
154 /*
155 * make the child exit. Best I can do is send it a sigkill.
156 * perhaps it should be put in the status that it wants to
157 * exit.
158 */
159 case PTRACE_KILL:
160 pr_debug("PTRACE_KILL\n");
161 rval = 0;
162 if (child->exit_state == EXIT_ZOMBIE) /* already dead */
163 break;
164 child->exit_code = SIGKILL;
165 wake_up_process(child);
166 break;
167
168 case PTRACE_DETACH: /* detach a process that was attached. */
169 pr_debug("PTRACE_DETACH\n");
170 rval = ptrace_detach(child, data);
171 break;
172 default:
173 /* rval = ptrace_request(child, request, addr, data); noMMU */
174 rval = -EIO;
175 }
176 return rval;
177}
178
179void ptrace_disable(struct task_struct *child)
180{
181 /* nothing to do */
182}