move new files out from platform support patch
[openwrt/openwrt.git] / target / linux / ubicom32 / files / arch / ubicom32 / kernel / ptrace.c
1 /*
2 * arch/ubicom32/kernel/ptrace.c
3 * Ubicom32 architecture ptrace implementation.
4 *
5 * (C) Copyright 2009, Ubicom, Inc.
6 * (C) 1994 by Hamish Macdonald
7 * Taken from linux/kernel/ptrace.c and modified for M680x0.
8 * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
9 *
10 * This file is part of the Ubicom32 Linux Kernel Port.
11 *
12 * The Ubicom32 Linux Kernel Port is free software: you can redistribute
13 * it and/or modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, either version 2 of the
15 * License, or (at your option) any later version.
16 *
17 * The Ubicom32 Linux Kernel Port is distributed in the hope that it
18 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
19 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
20 * the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with the Ubicom32 Linux Kernel Port. If not,
24 * see <http://www.gnu.org/licenses/>.
25 *
26 * Ubicom32 implementation derived from (with many thanks):
27 * arch/m68knommu
28 * arch/blackfin
29 * arch/parisc
30 */
31
32 #include <linux/module.h>
33 #include <linux/kernel.h>
34 #include <linux/sched.h>
35 #include <linux/mm.h>
36 #include <linux/smp.h>
37 #include <linux/errno.h>
38 #include <linux/ptrace.h>
39 #include <linux/user.h>
40 #include <linux/signal.h>
41 #include <linux/uaccess.h>
42
43 #include <asm/page.h>
44 #include <asm/pgtable.h>
45 #include <asm/system.h>
46 #include <asm/cacheflush.h>
47 #include <asm/processor.h>
48
49 /*
50 * ptrace_getregs()
51 *
52 * Get all user integer registers.
53 */
54 static inline int ptrace_getregs(struct task_struct *task, void __user *uregs)
55 {
56 struct pt_regs *regs = task_pt_regs(task);
57 return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0;
58 }
59
60 /*
61 * ptrace_get_reg()
62 *
63 * Get contents of register REGNO in task TASK.
64 */
65 static unsigned long ptrace_get_reg(struct task_struct *task, int regno)
66 {
67 if (regno < sizeof(struct pt_regs)) {
68 struct pt_regs *pt_regs = task_pt_regs(task);
69 return *(unsigned long *)((long) pt_regs + regno);
70 }
71
72 return -EIO;
73 }
74
75 /*
76 * ptrace_put_reg()
77 * Write contents of register REGNO in task TASK.
78 */
79 static int ptrace_put_reg(struct task_struct *task, int regno,
80 unsigned long data)
81 {
82 if (regno <= sizeof(struct pt_regs) && regno != PT_FRAME_TYPE) {
83 struct pt_regs *pt_regs = task_pt_regs(task);
84 *(unsigned long *)((long) pt_regs + regno) = data;
85 return 0;
86 }
87 return -EIO;
88 }
89
90 /*
91 * ptrace_disable_single_step()
92 * Disable Single Step
93 */
94 static int ptrace_disable_single_step(struct task_struct *task)
95 {
96 /*
97 * Single Step not yet implemented, so must always be disabled
98 */
99 return 0;
100 }
101
102 /*
103 * ptrace_disable()
104 * Make sure the single step bit is not set.
105 * Called by kernel/ptrace.c when detaching..
106 */
107 void ptrace_disable(struct task_struct *child)
108 {
109 ptrace_disable_single_step(child);
110 }
111
112 /*
113 * arch_ptrace()
114 * architecture specific ptrace routine.
115 */
116 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
117 {
118 int ret;
119 switch (request) {
120 /* when I and D space are separate, these will need to be fixed. */
121 case PTRACE_PEEKTEXT: /* read word at location addr. */
122 case PTRACE_PEEKDATA:
123 ret = generic_ptrace_peekdata(child, addr, data);
124 break;
125
126 /* read the word at location addr in the USER area. */
127 case PTRACE_PEEKUSR: {
128 unsigned long tmp;
129
130 ret = -EIO;
131 if (((unsigned long) addr > PT_INTERP_FDPIC_LOADMAP)
132 || (addr & 3))
133 break;
134
135 tmp = 0; /* Default return condition */
136
137 ret = -EIO;
138 if (addr < sizeof(struct pt_regs)) {
139 tmp = ptrace_get_reg(child, addr);
140 } else if (addr == PT_TEXT_ADDR) {
141 tmp = child->mm->start_code;
142 } else if (addr == PT_TEXT_END_ADDR) {
143 tmp = child->mm->end_code;
144 } else if (addr == PT_DATA_ADDR) {
145 tmp = child->mm->start_data;
146 } else if (addr == PT_EXEC_FDPIC_LOADMAP) {
147 #ifdef CONFIG_BINFMT_ELF_FDPIC
148 tmp = child->mm->context.exec_fdpic_loadmap;
149 #endif
150 } else if (addr == PT_INTERP_FDPIC_LOADMAP) {
151 #ifdef CONFIG_BINFMT_ELF_FDPIC
152 tmp = child->mm->context.interp_fdpic_loadmap;
153 #endif
154 } else {
155 break;
156 }
157
158 ret = put_user(tmp, (unsigned long *)data);
159 break;
160 }
161
162 case PTRACE_POKETEXT: /* write the word at location addr. */
163 case PTRACE_POKEDATA:
164 ret = generic_ptrace_pokedata(child, addr, data);
165
166 /*
167 * If we just changed some code so we need to
168 * correct the caches
169 */
170 if (request == PTRACE_POKETEXT && ret == 0) {
171 flush_icache_range(addr, addr + 4);
172 }
173 break;
174
175 case PTRACE_POKEUSR: /* write the word at location addr
176 * in the USER area */
177 ret = -EIO;
178
179 if (((unsigned long) addr > PT_DATA_ADDR) || (addr & 3))
180 break;
181
182 if (addr < sizeof(struct pt_regs)) {
183 ret = ptrace_put_reg(child, addr, data);
184 }
185 break;
186
187 case PTRACE_SYSCALL: /* continue and stop at next (return from)
188 * syscall */
189 case PTRACE_CONT: { /* restart after signal. */
190
191 ret = -EIO;
192 if (!valid_signal(data))
193 break;
194 if (request == PTRACE_SYSCALL)
195 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
196 else
197 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
198 child->exit_code = data;
199 /* make sure the single step bit is not set. */
200 ptrace_disable_single_step(child);
201 wake_up_process(child);
202 ret = 0;
203 break;
204 }
205
206 /*
207 * make the child exit. Best I can do is send it a sigkill.
208 * perhaps it should be put in the status that it wants to exit.
209 */
210 case PTRACE_KILL: {
211 ret = 0;
212 if (child->exit_state == EXIT_ZOMBIE) /* already dead */
213 break;
214 child->exit_code = SIGKILL;
215 /* make sure the single step bit is not set. */
216 ptrace_disable_single_step(child);
217 wake_up_process(child);
218 break;
219 }
220
221 case PTRACE_DETACH: /* detach a process that was attached. */
222 ret = ptrace_detach(child, data);
223 break;
224
225 case PTRACE_GETREGS: /* Get all gp regs from the child. */
226 ptrace_getregs(child, (unsigned long *)data);
227 ret = 0;
228 break;
229
230 case PTRACE_SETREGS: { /* Set all gp regs in the child. */
231 int i;
232 unsigned long tmp;
233 int count = sizeof(struct pt_regs) / sizeof(unsigned long);
234 for (i = 0; i < count; i++) {
235 if (get_user(tmp, (unsigned long *) data)) {
236 ret = -EFAULT;
237 break;
238 }
239 ptrace_put_reg(child, sizeof(unsigned long) * i, tmp);
240 data += sizeof(long);
241 }
242 ret = 0;
243 break;
244 }
245
246 default:
247 return ptrace_request(child, request, addr, data);
248 break;
249 }
250 return ret;
251 }
252 /*
253 * syscall_trace
254 *
255 * called by syscall enter/exit when the TIF_SYSCALL_TRACE bit is set.
256 */
257 asmlinkage void syscall_trace(void)
258 {
259 struct task_struct *cur = current;
260 if (!test_thread_flag(TIF_SYSCALL_TRACE))
261 return;
262 if (!(cur->ptrace & PT_PTRACED))
263 return;
264 ptrace_notify(SIGTRAP | ((cur->ptrace & PT_TRACESYSGOOD)
265 ? 0x80 : 0));
266 /*
267 * this isn't the same as continuing with a signal, but it will do
268 * for normal use. strace only continues with a signal if the
269 * stopping signal is not SIGTRAP. -brl
270 */
271 if (cur->exit_code) {
272 send_sig(cur->exit_code, current, 1);
273 current->exit_code = 0;
274 }
275 }