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)
40 read_tsk_long(struct task_struct *child,
41 unsigned long addr, unsigned long *res)
45 copied = access_process_vm(child, addr, res, sizeof(*res), 0);
47 return copied != sizeof(*res) ? -EIO : 0;
51 read_tsk_short(struct task_struct *child,
52 unsigned long addr, unsigned short *res)
56 copied = access_process_vm(child, addr, res, sizeof(*res), 0);
58 return copied != sizeof(*res) ? -EIO : 0;
62 write_tsk_short(struct task_struct *child,
63 unsigned long addr, unsigned short val)
67 copied = access_process_vm(child, addr, &val, sizeof(val), 1);
69 return copied != sizeof(val) ? -EIO : 0;
73 write_tsk_long(struct task_struct *child,
74 unsigned long addr, unsigned long val)
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;
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;
105 tmp = (unsigned int)((int) tmp >> 23);
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];
116 if ((epc_insn & J32M) == J32) {
117 tmp = epc_insn & 0x03FFFFFE;
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 */
125 tmp = (((tmp >> 16) & 0x3FF) << 10) | tmp2; /* 20bit */
127 tmp = (unsigned int)((int) tmp >> 12);
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];
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);
146 write_tsk_long(child, epc, SINGLESTEP32_INSN);
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;
156 child->thread.insn1_type = 1;
157 child->thread.addr1 = epc;
158 child->thread.insn1 = epc_insn;
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);
168 write_tsk_long(child, epc, SINGLESTEP32_INSN);
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;
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);
187 write_tsk_long(child, far_epc, SINGLESTEP32_INSN);
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;
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) {}
237 arch_ptrace(struct task_struct *child, long request, long addr, long data)
241 if (request == PTRACE_TRACEME) {
242 /* are we already being traced? */
243 if (current->ptrace & PT_PTRACED)
246 /* set the ptrace bit in the process flags. */
247 current->ptrace |= PT_PTRACED;
257 if (request == PTRACE_ATTACH) {
258 ret = ptrace_attach(child);
262 ret = ptrace_check_attach(child, request == PTRACE_KILL);
267 case PTRACE_PEEKTEXT: /* read word at location addr. */
268 case PTRACE_PEEKDATA: {
272 copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
274 if (copied != sizeof(tmp))
277 ret = put_user(tmp, (unsigned long *) data);
281 /* Read the word at location addr in the USER area. */
282 case PTRACE_PEEKUSR: {
283 struct pt_regs *regs;
286 regs = task_pt_regs(child);
288 tmp = 0; /* Default return value. */
291 tmp = regs->regs[addr];
309 tmp = regs->cp0_condition;
328 ret = put_user(tmp, (unsigned long *) data);
332 case PTRACE_POKETEXT: /* write the word at location addr. */
333 case PTRACE_POKEDATA:
335 if (access_process_vm(child, addr, &data, sizeof(data), 1)
341 case PTRACE_POKEUSR: {
342 struct pt_regs *regs;
344 regs = task_pt_regs(child);
348 regs->regs[addr] = data;
351 regs->cp0_epc = data;
360 regs->cp0_condition = data;
366 break; /* user can't write the reg */
368 /* The rest are not allowed. */
375 case PTRACE_SYSCALL: /* continue and stop at next
376 (return from) syscall. */
377 case PTRACE_CONT: { /* restart after signal. */
379 if (!valid_signal(data))
381 if (request == PTRACE_SYSCALL)
382 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
384 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
386 child->exit_code = data;
387 wake_up_process(child);
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
399 if (child->state == EXIT_ZOMBIE) /* already dead. */
401 child->exit_code = SIGKILL;
402 clear_single_step(child);
403 wake_up_process(child);
406 case PTRACE_SINGLESTEP: { /* set the trap flag. */
408 if ((unsigned long) data > _NSIG)
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);
419 case PTRACE_DETACH: /* detach a process that was attached. */
420 ret = ptrace_detach(child, data);
423 case PTRACE_SETOPTIONS:
424 if (data & PTRACE_O_TRACESYSGOOD)
425 child->ptrace |= PT_TRACESYSGOOD;
427 child->ptrace &= ~PT_TRACESYSGOOD;
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))
448 if (!test_thread_flag(TIF_SYSCALL_TRACE))
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) ?
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;