score: Add support for Sunplus S+core architecture
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / arch / score / kernel / ptrace.c
blob8fe7209355aa448b5f49fa6d3d08462c572c4858
1 /*
2 * arch/score/kernel/ptrace.c
4 * Score Processor version.
6 * Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
7 * Chen Liqin <liqin.chen@sunplusct.com>
8 * Lennox Wu <lennox.wu@sunplusct.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, see the file COPYING, or write
22 * to the Free Software Foundation, Inc.,
23 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 #include <linux/kernel.h>
27 #include <linux/ptrace.h>
29 #include <asm/uaccess.h>
31 static int is_16bitinsn(unsigned long insn)
33 if ((insn & INSN32_MASK) == INSN32_MASK)
34 return 0;
35 else
36 return 1;
39 int
40 read_tsk_long(struct task_struct *child,
41 unsigned long addr, unsigned long *res)
43 int copied;
45 copied = access_process_vm(child, addr, res, sizeof(*res), 0);
47 return copied != sizeof(*res) ? -EIO : 0;
50 int
51 read_tsk_short(struct task_struct *child,
52 unsigned long addr, unsigned short *res)
54 int copied;
56 copied = access_process_vm(child, addr, res, sizeof(*res), 0);
58 return copied != sizeof(*res) ? -EIO : 0;
61 static int
62 write_tsk_short(struct task_struct *child,
63 unsigned long addr, unsigned short val)
65 int copied;
67 copied = access_process_vm(child, addr, &val, sizeof(val), 1);
69 return copied != sizeof(val) ? -EIO : 0;
72 static int
73 write_tsk_long(struct task_struct *child,
74 unsigned long addr, unsigned long val)
76 int copied;
78 copied = access_process_vm(child, addr, &val, sizeof(val), 1);
80 return copied != sizeof(val) ? -EIO : 0;
83 void set_single_step(struct task_struct *child)
85 /* far_epc is the target of branch */
86 unsigned int epc, far_epc = 0;
87 unsigned long epc_insn, far_epc_insn;
88 int ninsn_type; /* next insn type 0=16b, 1=32b */
89 unsigned int tmp, tmp2;
90 struct pt_regs *regs = task_pt_regs(child);
91 child->thread.single_step = 1;
92 child->thread.ss_nextcnt = 1;
93 epc = regs->cp0_epc;
95 read_tsk_long(child, epc, &epc_insn);
97 if (is_16bitinsn(epc_insn)) {
98 if ((epc_insn & J16M) == J16) {
99 tmp = epc_insn & 0xFFE;
100 epc = (epc & 0xFFFFF000) | tmp;
101 } else if ((epc_insn & B16M) == B16) {
102 child->thread.ss_nextcnt = 2;
103 tmp = (epc_insn & 0xFF) << 1;
104 tmp = tmp << 23;
105 tmp = (unsigned int)((int) tmp >> 23);
106 far_epc = epc + tmp;
107 epc += 2;
108 } else if ((epc_insn & BR16M) == BR16) {
109 child->thread.ss_nextcnt = 2;
110 tmp = (epc_insn >> 4) & 0xF;
111 far_epc = regs->regs[tmp];
112 epc += 2;
113 } else
114 epc += 2;
115 } else {
116 if ((epc_insn & J32M) == J32) {
117 tmp = epc_insn & 0x03FFFFFE;
118 tmp2 = tmp & 0x7FFF;
119 tmp = (((tmp >> 16) & 0x3FF) << 15) | tmp2;
120 epc = (epc & 0xFFC00000) | tmp;
121 } else if ((epc_insn & B32M) == B32) {
122 child->thread.ss_nextcnt = 2;
123 tmp = epc_insn & 0x03FFFFFE; /* discard LK bit */
124 tmp2 = tmp & 0x3FF;
125 tmp = (((tmp >> 16) & 0x3FF) << 10) | tmp2; /* 20bit */
126 tmp = tmp << 12;
127 tmp = (unsigned int)((int) tmp >> 12);
128 far_epc = epc + tmp;
129 epc += 4;
130 } else if ((epc_insn & BR32M) == BR32) {
131 child->thread.ss_nextcnt = 2;
132 tmp = (epc_insn >> 16) & 0x1F;
133 far_epc = regs->regs[tmp];
134 epc += 4;
135 } else
136 epc += 4;
139 if (child->thread.ss_nextcnt == 1) {
140 read_tsk_long(child, epc, &epc_insn);
142 if (is_16bitinsn(epc_insn)) {
143 write_tsk_short(child, epc, SINGLESTEP16_INSN);
144 ninsn_type = 0;
145 } else {
146 write_tsk_long(child, epc, SINGLESTEP32_INSN);
147 ninsn_type = 1;
150 if (ninsn_type == 0) { /* 16bits */
151 child->thread.insn1_type = 0;
152 child->thread.addr1 = epc;
153 /* the insn may have 32bit data */
154 child->thread.insn1 = (short)epc_insn;
155 } else {
156 child->thread.insn1_type = 1;
157 child->thread.addr1 = epc;
158 child->thread.insn1 = epc_insn;
160 } else {
161 /* branch! have two target child->thread.ss_nextcnt=2 */
162 read_tsk_long(child, epc, &epc_insn);
163 read_tsk_long(child, far_epc, &far_epc_insn);
164 if (is_16bitinsn(epc_insn)) {
165 write_tsk_short(child, epc, SINGLESTEP16_INSN);
166 ninsn_type = 0;
167 } else {
168 write_tsk_long(child, epc, SINGLESTEP32_INSN);
169 ninsn_type = 1;
172 if (ninsn_type == 0) { /* 16bits */
173 child->thread.insn1_type = 0;
174 child->thread.addr1 = epc;
175 /* the insn may have 32bit data */
176 child->thread.insn1 = (short)epc_insn;
177 } else {
178 child->thread.insn1_type = 1;
179 child->thread.addr1 = epc;
180 child->thread.insn1 = epc_insn;
183 if (is_16bitinsn(far_epc_insn)) {
184 write_tsk_short(child, far_epc, SINGLESTEP16_INSN);
185 ninsn_type = 0;
186 } else {
187 write_tsk_long(child, far_epc, SINGLESTEP32_INSN);
188 ninsn_type = 1;
191 if (ninsn_type == 0) { /* 16bits */
192 child->thread.insn2_type = 0;
193 child->thread.addr2 = far_epc;
194 /* the insn may have 32bit data */
195 child->thread.insn2 = (short)far_epc_insn;
196 } else {
197 child->thread.insn2_type = 1;
198 child->thread.addr2 = far_epc;
199 child->thread.insn2 = far_epc_insn;
204 void clear_single_step(struct task_struct *child)
206 if (child->thread.insn1_type == 0)
207 write_tsk_short(child, child->thread.addr1,
208 child->thread.insn1);
210 if (child->thread.insn1_type == 1)
211 write_tsk_long(child, child->thread.addr1,
212 child->thread.insn1);
214 if (child->thread.ss_nextcnt == 2) { /* branch */
215 if (child->thread.insn1_type == 0)
216 write_tsk_short(child, child->thread.addr1,
217 child->thread.insn1);
218 if (child->thread.insn1_type == 1)
219 write_tsk_long(child, child->thread.addr1,
220 child->thread.insn1);
221 if (child->thread.insn2_type == 0)
222 write_tsk_short(child, child->thread.addr2,
223 child->thread.insn2);
224 if (child->thread.insn2_type == 1)
225 write_tsk_long(child, child->thread.addr2,
226 child->thread.insn2);
229 child->thread.single_step = 0;
230 child->thread.ss_nextcnt = 0;
234 void ptrace_disable(struct task_struct *child) {}
236 long
237 arch_ptrace(struct task_struct *child, long request, long addr, long data)
239 int ret;
241 if (request == PTRACE_TRACEME) {
242 /* are we already being traced? */
243 if (current->ptrace & PT_PTRACED)
244 return -EPERM;
246 /* set the ptrace bit in the process flags. */
247 current->ptrace |= PT_PTRACED;
248 return 0;
251 ret = -ESRCH;
252 if (!child)
253 return ret;
255 ret = -EPERM;
257 if (request == PTRACE_ATTACH) {
258 ret = ptrace_attach(child);
259 return ret;
262 ret = ptrace_check_attach(child, request == PTRACE_KILL);
263 if (ret < 0)
264 return ret;
266 switch (request) {
267 case PTRACE_PEEKTEXT: /* read word at location addr. */
268 case PTRACE_PEEKDATA: {
269 unsigned long tmp;
270 int copied;
272 copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
273 ret = -EIO;
274 if (copied != sizeof(tmp))
275 break;
277 ret = put_user(tmp, (unsigned long *) data);
278 return ret;
281 /* Read the word at location addr in the USER area. */
282 case PTRACE_PEEKUSR: {
283 struct pt_regs *regs;
284 unsigned long tmp;
286 regs = task_pt_regs(child);
288 tmp = 0; /* Default return value. */
289 switch (addr) {
290 case 0 ... 31:
291 tmp = regs->regs[addr];
292 break;
293 case PC:
294 tmp = regs->cp0_epc;
295 break;
296 case ECR:
297 tmp = regs->cp0_ecr;
298 break;
299 case EMA:
300 tmp = regs->cp0_ema;
301 break;
302 case CEH:
303 tmp = regs->ceh;
304 break;
305 case CEL:
306 tmp = regs->cel;
307 break;
308 case CONDITION:
309 tmp = regs->cp0_condition;
310 break;
311 case PSR:
312 tmp = regs->cp0_psr;
313 break;
314 case COUNTER:
315 tmp = regs->sr0;
316 break;
317 case LDCR:
318 tmp = regs->sr1;
319 break;
320 case STCR:
321 tmp = regs->sr2;
322 break;
323 default:
324 tmp = 0;
325 return -EIO;
328 ret = put_user(tmp, (unsigned long *) data);
329 return ret;
332 case PTRACE_POKETEXT: /* write the word at location addr. */
333 case PTRACE_POKEDATA:
334 ret = 0;
335 if (access_process_vm(child, addr, &data, sizeof(data), 1)
336 == sizeof(data))
337 break;
338 ret = -EIO;
339 return ret;
341 case PTRACE_POKEUSR: {
342 struct pt_regs *regs;
343 ret = 0;
344 regs = task_pt_regs(child);
346 switch (addr) {
347 case 0 ... 31:
348 regs->regs[addr] = data;
349 break;
350 case PC:
351 regs->cp0_epc = data;
352 break;
353 case CEH:
354 regs->ceh = data;
355 break;
356 case CEL:
357 regs->cel = data;
358 break;
359 case CONDITION:
360 regs->cp0_condition = data;
361 break;
362 case PSR:
363 case COUNTER:
364 case STCR:
365 case LDCR:
366 break; /* user can't write the reg */
367 default:
368 /* The rest are not allowed. */
369 ret = -EIO;
370 break;
372 break;
375 case PTRACE_SYSCALL: /* continue and stop at next
376 (return from) syscall. */
377 case PTRACE_CONT: { /* restart after signal. */
378 ret = -EIO;
379 if (!valid_signal(data))
380 break;
381 if (request == PTRACE_SYSCALL)
382 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
383 else
384 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
386 child->exit_code = data;
387 wake_up_process(child);
388 ret = 0;
389 break;
393 * make the child exit. Best I can do is send it a sigkill.
394 * perhaps it should be put in the status that it wants to
395 * exit.
397 case PTRACE_KILL:
398 ret = 0;
399 if (child->state == EXIT_ZOMBIE) /* already dead. */
400 break;
401 child->exit_code = SIGKILL;
402 clear_single_step(child);
403 wake_up_process(child);
404 break;
406 case PTRACE_SINGLESTEP: { /* set the trap flag. */
407 ret = -EIO;
408 if ((unsigned long) data > _NSIG)
409 break;
410 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
411 set_single_step(child);
412 child->exit_code = data;
413 /* give it a chance to run. */
414 wake_up_process(child);
415 ret = 0;
416 break;
419 case PTRACE_DETACH: /* detach a process that was attached. */
420 ret = ptrace_detach(child, data);
421 break;
423 case PTRACE_SETOPTIONS:
424 if (data & PTRACE_O_TRACESYSGOOD)
425 child->ptrace |= PT_TRACESYSGOOD;
426 else
427 child->ptrace &= ~PT_TRACESYSGOOD;
428 ret = 0;
429 break;
431 default:
432 ret = -EIO;
433 break;
436 return ret;
440 * Notification of system call entry/exit
441 * - triggered by current->work.syscall_trace
443 asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
445 if (!(current->ptrace & PT_PTRACED))
446 return;
448 if (!test_thread_flag(TIF_SYSCALL_TRACE))
449 return;
451 /* The 0x80 provides a way for the tracing parent to distinguish
452 between a syscall stop and SIGTRAP delivery. */
453 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ?
454 0x80 : 0));
457 * this isn't the same as continuing with a signal, but it will do
458 * for normal use. strace only continues with a signal if the
459 * stopping signal is not SIGTRAP. -brl
461 if (current->exit_code) {
462 send_sig(current->exit_code, current, 1);
463 current->exit_code = 0;