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;
84 * Get all user integer registers.
86 static int ptrace_getregs(struct task_struct
*tsk
, void __user
*uregs
)
88 struct pt_regs
*regs
= task_pt_regs(tsk
);
90 return copy_to_user(uregs
, regs
, sizeof(struct pt_regs
)) ? -EFAULT
: 0;
94 * Set all user integer registers.
96 static int ptrace_setregs(struct task_struct
*tsk
, void __user
*uregs
)
98 struct pt_regs newregs
;
102 if (copy_from_user(&newregs
, uregs
, sizeof(struct pt_regs
)) == 0) {
103 struct pt_regs
*regs
= task_pt_regs(tsk
);
111 void user_enable_single_step(struct task_struct
*child
)
113 /* far_epc is the target of branch */
114 unsigned int epc
, far_epc
= 0;
115 unsigned long epc_insn
, far_epc_insn
;
116 int ninsn_type
; /* next insn type 0=16b, 1=32b */
117 unsigned int tmp
, tmp2
;
118 struct pt_regs
*regs
= task_pt_regs(child
);
119 child
->thread
.single_step
= 1;
120 child
->thread
.ss_nextcnt
= 1;
123 read_tsk_long(child
, epc
, &epc_insn
);
125 if (is_16bitinsn(epc_insn
)) {
126 if ((epc_insn
& J16M
) == J16
) {
127 tmp
= epc_insn
& 0xFFE;
128 epc
= (epc
& 0xFFFFF000) | tmp
;
129 } else if ((epc_insn
& B16M
) == B16
) {
130 child
->thread
.ss_nextcnt
= 2;
131 tmp
= (epc_insn
& 0xFF) << 1;
133 tmp
= (unsigned int)((int) tmp
>> 23);
136 } else if ((epc_insn
& BR16M
) == BR16
) {
137 child
->thread
.ss_nextcnt
= 2;
138 tmp
= (epc_insn
>> 4) & 0xF;
139 far_epc
= regs
->regs
[tmp
];
144 if ((epc_insn
& J32M
) == J32
) {
145 tmp
= epc_insn
& 0x03FFFFFE;
147 tmp
= (((tmp
>> 16) & 0x3FF) << 15) | tmp2
;
148 epc
= (epc
& 0xFFC00000) | tmp
;
149 } else if ((epc_insn
& B32M
) == B32
) {
150 child
->thread
.ss_nextcnt
= 2;
151 tmp
= epc_insn
& 0x03FFFFFE; /* discard LK bit */
153 tmp
= (((tmp
>> 16) & 0x3FF) << 10) | tmp2
; /* 20bit */
155 tmp
= (unsigned int)((int) tmp
>> 12);
158 } else if ((epc_insn
& BR32M
) == BR32
) {
159 child
->thread
.ss_nextcnt
= 2;
160 tmp
= (epc_insn
>> 16) & 0x1F;
161 far_epc
= regs
->regs
[tmp
];
167 if (child
->thread
.ss_nextcnt
== 1) {
168 read_tsk_long(child
, epc
, &epc_insn
);
170 if (is_16bitinsn(epc_insn
)) {
171 write_tsk_short(child
, epc
, SINGLESTEP16_INSN
);
174 write_tsk_long(child
, epc
, SINGLESTEP32_INSN
);
178 if (ninsn_type
== 0) { /* 16bits */
179 child
->thread
.insn1_type
= 0;
180 child
->thread
.addr1
= epc
;
181 /* the insn may have 32bit data */
182 child
->thread
.insn1
= (short)epc_insn
;
184 child
->thread
.insn1_type
= 1;
185 child
->thread
.addr1
= epc
;
186 child
->thread
.insn1
= epc_insn
;
189 /* branch! have two target child->thread.ss_nextcnt=2 */
190 read_tsk_long(child
, epc
, &epc_insn
);
191 read_tsk_long(child
, far_epc
, &far_epc_insn
);
192 if (is_16bitinsn(epc_insn
)) {
193 write_tsk_short(child
, epc
, SINGLESTEP16_INSN
);
196 write_tsk_long(child
, epc
, SINGLESTEP32_INSN
);
200 if (ninsn_type
== 0) { /* 16bits */
201 child
->thread
.insn1_type
= 0;
202 child
->thread
.addr1
= epc
;
203 /* the insn may have 32bit data */
204 child
->thread
.insn1
= (short)epc_insn
;
206 child
->thread
.insn1_type
= 1;
207 child
->thread
.addr1
= epc
;
208 child
->thread
.insn1
= epc_insn
;
211 if (is_16bitinsn(far_epc_insn
)) {
212 write_tsk_short(child
, far_epc
, SINGLESTEP16_INSN
);
215 write_tsk_long(child
, far_epc
, SINGLESTEP32_INSN
);
219 if (ninsn_type
== 0) { /* 16bits */
220 child
->thread
.insn2_type
= 0;
221 child
->thread
.addr2
= far_epc
;
222 /* the insn may have 32bit data */
223 child
->thread
.insn2
= (short)far_epc_insn
;
225 child
->thread
.insn2_type
= 1;
226 child
->thread
.addr2
= far_epc
;
227 child
->thread
.insn2
= far_epc_insn
;
232 void user_disable_single_step(struct task_struct
*child
)
234 if (child
->thread
.insn1_type
== 0)
235 write_tsk_short(child
, child
->thread
.addr1
,
236 child
->thread
.insn1
);
238 if (child
->thread
.insn1_type
== 1)
239 write_tsk_long(child
, child
->thread
.addr1
,
240 child
->thread
.insn1
);
242 if (child
->thread
.ss_nextcnt
== 2) { /* branch */
243 if (child
->thread
.insn1_type
== 0)
244 write_tsk_short(child
, child
->thread
.addr1
,
245 child
->thread
.insn1
);
246 if (child
->thread
.insn1_type
== 1)
247 write_tsk_long(child
, child
->thread
.addr1
,
248 child
->thread
.insn1
);
249 if (child
->thread
.insn2_type
== 0)
250 write_tsk_short(child
, child
->thread
.addr2
,
251 child
->thread
.insn2
);
252 if (child
->thread
.insn2_type
== 1)
253 write_tsk_long(child
, child
->thread
.addr2
,
254 child
->thread
.insn2
);
257 child
->thread
.single_step
= 0;
258 child
->thread
.ss_nextcnt
= 0;
261 void ptrace_disable(struct task_struct
*child
)
263 user_disable_single_step(child
);
267 arch_ptrace(struct task_struct
*child
, long request
, long addr
, long data
)
272 /* Read the word at location addr in the USER area. */
273 case PTRACE_PEEKUSR
: {
274 struct pt_regs
*regs
;
277 regs
= task_pt_regs(child
);
279 tmp
= 0; /* Default return value. */
282 tmp
= regs
->regs
[addr
];
300 tmp
= regs
->cp0_condition
;
319 ret
= put_user(tmp
, (unsigned long *) data
);
323 case PTRACE_POKEUSR
: {
324 struct pt_regs
*regs
;
326 regs
= task_pt_regs(child
);
330 regs
->regs
[addr
] = data
;
333 regs
->cp0_epc
= data
;
342 regs
->cp0_condition
= data
;
348 break; /* user can't write the reg */
350 /* The rest are not allowed. */
358 ret
= ptrace_getregs(child
, (void __user
*)data
);
362 ret
= ptrace_setregs(child
, (void __user
*)data
);
366 ret
= ptrace_request(child
, request
, addr
, data
);
374 * Notification of system call entry/exit
375 * - triggered by current->work.syscall_trace
377 asmlinkage
void do_syscall_trace(struct pt_regs
*regs
, int entryexit
)
379 if (!(current
->ptrace
& PT_PTRACED
))
382 if (!test_thread_flag(TIF_SYSCALL_TRACE
))
385 /* The 0x80 provides a way for the tracing parent to distinguish
386 between a syscall stop and SIGTRAP delivery. */
387 ptrace_notify(SIGTRAP
| ((current
->ptrace
& PT_TRACESYSGOOD
) ?
391 * this isn't the same as continuing with a signal, but it will do
392 * for normal use. strace only continues with a signal if the
393 * stopping signal is not SIGTRAP. -brl
395 if (current
->exit_code
) {
396 send_sig(current
->exit_code
, current
, 1);
397 current
->exit_code
= 0;