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
17#include <asm/uaccess.h>
18#include <asm/pgtable.h>
19#include <asm/system.h>
20#include <asm/fpu.h>
21
22#include "proto.h"
23
24#define DEBUG DBG_MEM
25#undef DEBUG
26
27#ifdef DEBUG
28enum {
29 DBG_MEM = (1<<0),
30 DBG_BPT = (1<<1),
31 DBG_MEM_ALL = (1<<2)
32};
33#define DBG(fac,args) {if ((fac) & DEBUG) printk args;}
34#else
35#define DBG(fac,args)
36#endif
37
38#define BREAKINST 0x00000080
39
40
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
69enum {
70 REG_R0 = 0, REG_F0 = 32, REG_FPCR = 63, REG_PC = 64
71};
72
73static int regoff[] = {
74 PT_REG( r0), PT_REG( r1), PT_REG( r2), PT_REG( r3),
75 PT_REG( r4), PT_REG( r5), PT_REG( r6), PT_REG( r7),
76 PT_REG( r8), SW_REG( r9), SW_REG( r10), SW_REG( r11),
77 SW_REG( r12), SW_REG( r13), SW_REG( r14), SW_REG( r15),
78 PT_REG( r16), PT_REG( r17), PT_REG( r18), PT_REG( r19),
79 PT_REG( r20), PT_REG( r21), PT_REG( r22), PT_REG( r23),
80 PT_REG( r24), PT_REG( r25), PT_REG( r26), PT_REG( r27),
81 PT_REG( r28), PT_REG( gp), -1, -1,
82 SW_REG(fp[ 0]), SW_REG(fp[ 1]), SW_REG(fp[ 2]), SW_REG(fp[ 3]),
83 SW_REG(fp[ 4]), SW_REG(fp[ 5]), SW_REG(fp[ 6]), SW_REG(fp[ 7]),
84 SW_REG(fp[ 8]), SW_REG(fp[ 9]), SW_REG(fp[10]), SW_REG(fp[11]),
85 SW_REG(fp[12]), SW_REG(fp[13]), SW_REG(fp[14]), SW_REG(fp[15]),
86 SW_REG(fp[16]), SW_REG(fp[17]), SW_REG(fp[18]), SW_REG(fp[19]),
87 SW_REG(fp[20]), SW_REG(fp[21]), SW_REG(fp[22]), SW_REG(fp[23]),
88 SW_REG(fp[24]), SW_REG(fp[25]), SW_REG(fp[26]), SW_REG(fp[27]),
89 SW_REG(fp[28]), SW_REG(fp[29]), SW_REG(fp[30]), SW_REG(fp[31]),
90 PT_REG( pc)
91};
92
93static long zero;
94
95
96
97
98static long *
99get_reg_addr(struct task_struct * task, unsigned long regno)
100{
101 long *addr;
102
103 if (regno == 30) {
104 addr = &task->thread.usp;
105 } else if (regno == 31 || regno > 64) {
106 zero = 0;
107 addr = &zero;
108 } else {
109 addr = (long *)((long)task + regoff[regno]);
110 }
111 return addr;
112}
113
114
115
116
117static long
118get_reg(struct task_struct * task, unsigned long regno)
119{
120
121 if (regno == 63) {
122 unsigned long fpcr = *get_reg_addr(task, regno);
123 unsigned long swcr = task->thread.flags & IEEE_SW_MASK;
124 swcr = swcr_update_status(swcr, fpcr);
125 return fpcr | swcr;
126 }
127 return *get_reg_addr(task, regno);
128}
129
130
131
132
133static int
134put_reg(struct task_struct *task, unsigned long regno, long data)
135{
136 if (regno == 63) {
137 task->thread.flags = ((task->thread.flags & ~IEEE_SW_MASK)
138 | (data & IEEE_SW_MASK));
139 data = (data & FPCR_DYN_MASK) | ieee_swcr_to_fpcr(data);
140 }
141 *get_reg_addr(task, regno) = data;
142 return 0;
143}
144
145static inline int
146read_int(struct task_struct *task, unsigned long addr, int * data)
147{
148 int copied = access_process_vm(task, addr, data, sizeof(int), 0);
149 return (copied == sizeof(int)) ? 0 : -EIO;
150}
151
152static inline int
153write_int(struct task_struct *task, unsigned long addr, int data)
154{
155 int copied = access_process_vm(task, addr, &data, sizeof(int), 1);
156 return (copied == sizeof(int)) ? 0 : -EIO;
157}
158
159
160
161
162int
163ptrace_set_bpt(struct task_struct * child)
164{
165 int displ, i, res, reg_b, nsaved = 0;
166 u32 insn, op_code;
167 unsigned long pc;
168
169 pc = get_reg(child, REG_PC);
170 res = read_int(child, pc, &insn);
171 if (res < 0)
172 return res;
173
174 op_code = insn >> 26;
175 if (op_code >= 0x30) {
176
177
178
179
180
181
182
183
184 displ = ((s32)(insn << 11)) >> 9;
185 child->thread.bpt_addr[nsaved++] = pc + 4;
186 if (displ)
187 child->thread.bpt_addr[nsaved++] = pc + 4 + displ;
188 DBG(DBG_BPT, ("execing branch\n"));
189 } else if (op_code == 0x1a) {
190 reg_b = (insn >> 16) & 0x1f;
191 child->thread.bpt_addr[nsaved++] = get_reg(child, reg_b);
192 DBG(DBG_BPT, ("execing jump\n"));
193 } else {
194 child->thread.bpt_addr[nsaved++] = pc + 4;
195 DBG(DBG_BPT, ("execing normal insn\n"));
196 }
197
198
199 for (i = 0; i < nsaved; ++i) {
200 res = read_int(child, child->thread.bpt_addr[i], &insn);
201 if (res < 0)
202 return res;
203 child->thread.bpt_insn[i] = insn;
204 DBG(DBG_BPT, (" -> next_pc=%lx\n", child->thread.bpt_addr[i]));
205 res = write_int(child, child->thread.bpt_addr[i], BREAKINST);
206 if (res < 0)
207 return res;
208 }
209 child->thread.bpt_nsaved = nsaved;
210 return 0;
211}
212
213
214
215
216
217int
218ptrace_cancel_bpt(struct task_struct * child)
219{
220 int i, nsaved = child->thread.bpt_nsaved;
221
222 child->thread.bpt_nsaved = 0;
223
224 if (nsaved > 2) {
225 printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved);
226 nsaved = 2;
227 }
228
229 for (i = 0; i < nsaved; ++i) {
230 write_int(child, child->thread.bpt_addr[i],
231 child->thread.bpt_insn[i]);
232 }
233 return (nsaved != 0);
234}
235
236
237
238
239
240
241void ptrace_disable(struct task_struct *child)
242{
243 ptrace_cancel_bpt(child);
244}
245
246asmlinkage long
247sys_ptrace(long request, long pid, long addr, long data,
248 int a4, int a5, struct pt_regs regs)
249{
250 struct task_struct *child;
251 long ret;
252
253 lock_kernel();
254 DBG(DBG_MEM, ("request=%ld pid=%ld addr=0x%lx data=0x%lx\n",
255 request, pid, addr, data));
256 ret = -EPERM;
257 if (request == PTRACE_TRACEME) {
258
259 if (current->ptrace & PT_PTRACED)
260 goto out_notsk;
261
262 current->ptrace |= PT_PTRACED;
263 ret = 0;
264 goto out_notsk;
265 }
266 if (pid == 1)
267 goto out_notsk;
268 ret = -ESRCH;
269 read_lock(&tasklist_lock);
270 child = find_task_by_pid(pid);
271 if (child)
272 get_task_struct(child);
273 read_unlock(&tasklist_lock);
274 if (!child)
275 goto out_notsk;
276 if (request == PTRACE_ATTACH) {
277 ret = ptrace_attach(child);
278 goto out;
279 }
280 ret = -ESRCH;
281 if (!(child->ptrace & PT_PTRACED)) {
282 DBG(DBG_MEM, ("child not traced\n"));
283 goto out;
284 }
285 if (child->state != TASK_STOPPED) {
286 DBG(DBG_MEM, ("child process not stopped\n"));
287 if (request != PTRACE_KILL)
288 goto out;
289 }
290 if (child->p_pptr != current) {
291 DBG(DBG_MEM, ("child not parent of this process\n"));
292 goto out;
293 }
294
295 switch (request) {
296
297 case PTRACE_PEEKTEXT:
298 case PTRACE_PEEKDATA: {
299 unsigned long tmp;
300 int copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
301 ret = -EIO;
302 if (copied != sizeof(tmp))
303 goto out;
304
305 regs.r0 = 0;
306 ret = tmp;
307 goto out;
308 }
309
310
311 case PTRACE_PEEKUSR:
312 regs.r0 = 0;
313 ret = get_reg(child, addr);
314 DBG(DBG_MEM, ("peek $%ld->%#lx\n", addr, ret));
315 goto out;
316
317
318 case PTRACE_POKETEXT:
319 case PTRACE_POKEDATA: {
320 unsigned long tmp = data;
321 int copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 1);
322 ret = (copied == sizeof(tmp)) ? 0 : -EIO;
323 goto out;
324 }
325
326 case PTRACE_POKEUSR:
327 DBG(DBG_MEM, ("poke $%ld<-%#lx\n", addr, data));
328 ret = put_reg(child, addr, data);
329 goto out;
330
331 case PTRACE_SYSCALL:
332
333 case PTRACE_CONT:
334 ret = -EIO;
335 if ((unsigned long) data > _NSIG)
336 goto out;
337 if (request == PTRACE_SYSCALL)
338 child->ptrace |= PT_TRACESYS;
339 else
340 child->ptrace &= ~PT_TRACESYS;
341 child->exit_code = data;
342 wake_up_process(child);
343
344 ptrace_cancel_bpt(child);
345 ret = data;
346 goto out;
347
348
349
350
351
352
353 case PTRACE_KILL:
354 if (child->state != TASK_ZOMBIE) {
355 wake_up_process(child);
356 child->exit_code = SIGKILL;
357 }
358
359 ptrace_cancel_bpt(child);
360 ret = 0;
361 goto out;
362
363 case PTRACE_SINGLESTEP:
364 ret = -EIO;
365 if ((unsigned long) data > _NSIG)
366 goto out;
367 child->thread.bpt_nsaved = -1;
368 child->ptrace &= ~PT_TRACESYS;
369 wake_up_process(child);
370 child->exit_code = data;
371
372 ret = 0;
373 goto out;
374
375 case PTRACE_DETACH:
376 ret = ptrace_detach(child, data);
377 goto out;
378
379 default:
380 ret = -EIO;
381 goto out;
382 }
383 out:
384 free_task_struct(child);
385 out_notsk:
386 unlock_kernel();
387 return ret;
388}
389
390asmlinkage void
391syscall_trace(void)
392{
393 if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
394 != (PT_PTRACED|PT_TRACESYS))
395 return;
396 current->exit_code = SIGTRAP;
397 current->state = TASK_STOPPED;
398 notify_parent(current, SIGCHLD);
399 schedule();
400
401
402
403
404
405 if (current->exit_code) {
406 send_sig(current->exit_code, current, 1);
407 current->exit_code = 0;
408 }
409}
410