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;