1
2
3
4
5
6
7#include <linux/kernel.h>
8#include <linux/sched.h>
9#include <linux/mm.h>
10#include <linux/smp.h>
11#include <linux/smp_lock.h>
12#include <linux/errno.h>
13#include <linux/ptrace.h>
14#include <linux/user.h>
15#include <linux/slab.h>
16#include <linux/security.h>
17#include <linux/signal.h>
18
19#include <asm/uaccess.h>
20#include <asm/pgtable.h>
21#include <asm/system.h>
22#include <asm/fpu.h>
23
24#include "proto.h"
25
26#define DEBUG DBG_MEM
27#undef DEBUG
28
29#ifdef DEBUG
30enum {
31 DBG_MEM = (1<<0),
32 DBG_BPT = (1<<1),
33 DBG_MEM_ALL = (1<<2)
34};
35#define DBG(fac,args) {if ((fac) & DEBUG) printk args;}
36#else
37#define DBG(fac,args)
38#endif
39
40#define BREAKINST 0x00000080
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71enum {
72 REG_R0 = 0, REG_F0 = 32, REG_FPCR = 63, REG_PC = 64
73};
74
75#define PT_REG(reg) \
76 (PAGE_SIZE*2 - sizeof(struct pt_regs) + offsetof(struct pt_regs, reg))
77
78#define SW_REG(reg) \
79 (PAGE_SIZE*2 - sizeof(struct pt_regs) - sizeof(struct switch_stack) \
80 + offsetof(struct switch_stack, reg))
81
82static int regoff[] = {
83 PT_REG( r0), PT_REG( r1), PT_REG( r2), PT_REG( r3),
84 PT_REG( r4), PT_REG( r5), PT_REG( r6), PT_REG( r7),
85 PT_REG( r8), SW_REG( r9), SW_REG( r10), SW_REG( r11),
86 SW_REG( r12), SW_REG( r13), SW_REG( r14), SW_REG( r15),
87 PT_REG( r16), PT_REG( r17), PT_REG( r18), PT_REG( r19),
88 PT_REG( r20), PT_REG( r21), PT_REG( r22), PT_REG( r23),
89 PT_REG( r24), PT_REG( r25), PT_REG( r26), PT_REG( r27),
90 PT_REG( r28), PT_REG( gp), -1, -1,
91 SW_REG(fp[ 0]), SW_REG(fp[ 1]), SW_REG(fp[ 2]), SW_REG(fp[ 3]),
92 SW_REG(fp[ 4]), SW_REG(fp[ 5]), SW_REG(fp[ 6]), SW_REG(fp[ 7]),
93 SW_REG(fp[ 8]), SW_REG(fp[ 9]), SW_REG(fp[10]), SW_REG(fp[11]),
94 SW_REG(fp[12]), SW_REG(fp[13]), SW_REG(fp[14]), SW_REG(fp[15]),
95 SW_REG(fp[16]), SW_REG(fp[17]), SW_REG(fp[18]), SW_REG(fp[19]),
96 SW_REG(fp[20]), SW_REG(fp[21]), SW_REG(fp[22]), SW_REG(fp[23]),
97 SW_REG(fp[24]), SW_REG(fp[25]), SW_REG(fp[26]), SW_REG(fp[27]),
98 SW_REG(fp[28]), SW_REG(fp[29]), SW_REG(fp[30]), SW_REG(fp[31]),
99 PT_REG( pc)
100};
101
102static unsigned long zero;
103
104
105
106
107static unsigned long *
108get_reg_addr(struct task_struct * task, unsigned long regno)
109{
110 unsigned long *addr;
111
112 if (regno == 30) {
113 addr = &task_thread_info(task)->pcb.usp;
114 } else if (regno == 65) {
115 addr = &task_thread_info(task)->pcb.unique;
116 } else if (regno == 31 || regno > 65) {
117 zero = 0;
118 addr = &zero;
119 } else {
120 addr = task_stack_page(task) + regoff[regno];
121 }
122 return addr;
123}
124
125
126
127
128static unsigned long
129get_reg(struct task_struct * task, unsigned long regno)
130{
131
132 if (regno == 63) {
133 unsigned long fpcr = *get_reg_addr(task, regno);
134 unsigned long swcr
135 = task_thread_info(task)->ieee_state & IEEE_SW_MASK;
136 swcr = swcr_update_status(swcr, fpcr);
137 return fpcr | swcr;
138 }
139 return *get_reg_addr(task, regno);
140}
141
142
143
144
145static int
146put_reg(struct task_struct *task, unsigned long regno, unsigned long data)
147{
148 if (regno == 63) {
149 task_thread_info(task)->ieee_state
150 = ((task_thread_info(task)->ieee_state & ~IEEE_SW_MASK)
151 | (data & IEEE_SW_MASK));
152 data = (data & FPCR_DYN_MASK) | ieee_swcr_to_fpcr(data);
153 }
154 *get_reg_addr(task, regno) = data;
155 return 0;
156}
157
158static inline int
159read_int(struct task_struct *task, unsigned long addr, int * data)
160{
161 int copied = access_process_vm(task, addr, data, sizeof(int), 0);
162 return (copied == sizeof(int)) ? 0 : -EIO;
163}
164
165static inline int
166write_int(struct task_struct *task, unsigned long addr, int data)
167{
168 int copied = access_process_vm(task, addr, &data, sizeof(int), 1);
169 return (copied == sizeof(int)) ? 0 : -EIO;
170}
171
172
173
174
175int
176ptrace_set_bpt(struct task_struct * child)
177{
178 int displ, i, res, reg_b, nsaved = 0;
179 unsigned int insn, op_code;
180 unsigned long pc;
181
182 pc = get_reg(child, REG_PC);
183 res = read_int(child, pc, (int *) &insn);
184 if (res < 0)
185 return res;
186
187 op_code = insn >> 26;
188 if (op_code >= 0x30) {
189
190
191
192
193
194
195
196
197 displ = ((s32)(insn << 11)) >> 9;
198 task_thread_info(child)->bpt_addr[nsaved++] = pc + 4;
199 if (displ)
200 task_thread_info(child)->bpt_addr[nsaved++]
201 = pc + 4 + displ;
202 DBG(DBG_BPT, ("execing branch\n"));
203 } else if (op_code == 0x1a) {
204 reg_b = (insn >> 16) & 0x1f;
205 task_thread_info(child)->bpt_addr[nsaved++] = get_reg(child, reg_b);
206 DBG(DBG_BPT, ("execing jump\n"));
207 } else {
208 task_thread_info(child)->bpt_addr[nsaved++] = pc + 4;
209 DBG(DBG_BPT, ("execing normal insn\n"));
210 }
211
212
213 for (i = 0; i < nsaved; ++i) {
214 res = read_int(child, task_thread_info(child)->bpt_addr[i],
215 (int *) &insn);
216 if (res < 0)
217 return res;
218 task_thread_info(child)->bpt_insn[i] = insn;
219 DBG(DBG_BPT, (" -> next_pc=%lx\n",
220 task_thread_info(child)->bpt_addr[i]));
221 res = write_int(child, task_thread_info(child)->bpt_addr[i],
222 BREAKINST);
223 if (res < 0)
224 return res;
225 }
226 task_thread_info(child)->bpt_nsaved = nsaved;
227 return 0;
228}
229
230
231
232
233
234int
235ptrace_cancel_bpt(struct task_struct * child)
236{
237 int i, nsaved = task_thread_info(child)->bpt_nsaved;
238
239 task_thread_info(child)->bpt_nsaved = 0;
240
241 if (nsaved > 2) {
242 printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved);
243 nsaved = 2;
244 }
245
246 for (i = 0; i < nsaved; ++i) {
247 write_int(child, task_thread_info(child)->bpt_addr[i],
248 task_thread_info(child)->bpt_insn[i]);
249 }
250 return (nsaved != 0);
251}
252
253
254
255
256
257
258void ptrace_disable(struct task_struct *child)
259{
260 ptrace_cancel_bpt(child);
261}
262
263long arch_ptrace(struct task_struct *child, long request, long addr, long data)
264{
265 unsigned long tmp;
266 size_t copied;
267 long ret;
268
269 switch (request) {
270
271 case PTRACE_PEEKTEXT:
272 case PTRACE_PEEKDATA:
273 copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
274 ret = -EIO;
275 if (copied != sizeof(tmp))
276 break;
277
278 force_successful_syscall_return();
279 ret = tmp;
280 break;
281
282
283 case PTRACE_PEEKUSR:
284 force_successful_syscall_return();
285 ret = get_reg(child, addr);
286 DBG(DBG_MEM, ("peek $%ld->%#lx\n", addr, ret));
287 break;
288
289
290 case PTRACE_POKETEXT:
291 case PTRACE_POKEDATA:
292 ret = generic_ptrace_pokedata(child, addr, data);
293 break;
294
295 case PTRACE_POKEUSR:
296 DBG(DBG_MEM, ("poke $%ld<-%#lx\n", addr, data));
297 ret = put_reg(child, addr, data);
298 break;
299
300 case PTRACE_SYSCALL:
301
302 case PTRACE_CONT:
303 ret = -EIO;
304 if (!valid_signal(data))
305 break;
306 if (request == PTRACE_SYSCALL)
307 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
308 else
309 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
310 child->exit_code = data;
311
312 ptrace_cancel_bpt(child);
313 wake_up_process(child);
314 ret = 0;
315 break;
316
317
318
319
320
321
322 case PTRACE_KILL:
323 ret = 0;
324 if (child->exit_state == EXIT_ZOMBIE)
325 break;
326 child->exit_code = SIGKILL;
327
328 ptrace_cancel_bpt(child);
329 wake_up_process(child);
330 break;
331
332 case PTRACE_SINGLESTEP:
333 ret = -EIO;
334 if (!valid_signal(data))
335 break;
336
337 task_thread_info(child)->bpt_nsaved = -1;
338 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
339 child->exit_code = data;
340 wake_up_process(child);
341
342 ret = 0;
343 break;
344
345 default:
346 ret = ptrace_request(child, request, addr, data);
347 break;
348 }
349 return ret;
350}
351
352asmlinkage void
353syscall_trace(void)
354{
355 if (!test_thread_flag(TIF_SYSCALL_TRACE))
356 return;
357 if (!(current->ptrace & PT_PTRACED))
358 return;
359
360
361 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
362 ? 0x80 : 0));
363
364
365
366
367
368
369 if (current->exit_code) {
370 send_sig(current->exit_code, current, 1);
371 current->exit_code = 0;
372 }
373}
374