1
2
3
4
5
6
7
8
9
10
11
12#include <linux/kernel.h>
13#include <linux/sched.h>
14#include <linux/mm.h>
15#include <linux/smp.h>
16#include <linux/smp_lock.h>
17#include <linux/ptrace.h>
18#include <linux/user.h>
19
20#include <asm/uaccess.h>
21#include <asm/pgtable.h>
22#include <asm/system.h>
23
24#include "ptrace.h"
25
26#define REG_PC 15
27#define REG_PSR 16
28
29
30
31
32
33
34
35
36#define BREAKINST 0xef9f0001
37
38
39
40
41
42
43static inline struct pt_regs *
44get_user_regs(struct task_struct *task)
45{
46 return (struct pt_regs *)
47 ((unsigned long)task + 8192 - sizeof(struct pt_regs));
48}
49
50
51
52
53
54
55
56static inline long get_stack_long(struct task_struct *task, int offset)
57{
58 return get_user_regs(task)->uregs[offset];
59}
60
61
62
63
64
65
66
67static inline int
68put_stack_long(struct task_struct *task, int offset, long data)
69{
70 struct pt_regs newregs, *regs = get_user_regs(task);
71 int ret = -EINVAL;
72
73 newregs = *regs;
74 newregs.uregs[offset] = data;
75
76 if (valid_user_regs(&newregs)) {
77 regs->uregs[offset] = data;
78 ret = 0;
79 }
80
81 return ret;
82}
83
84static inline int
85read_tsk_long(struct task_struct *child, unsigned long addr, unsigned long *res)
86{
87 int copied;
88
89 copied = access_process_vm(child, addr, res, sizeof(*res), 0);
90
91 return copied != sizeof(*res) ? -EIO : 0;
92}
93
94static inline int
95write_tsk_long(struct task_struct *child, unsigned long addr, unsigned long val)
96{
97 int copied;
98
99 copied = access_process_vm(child, addr, &val, sizeof(val), 1);
100
101 return copied != sizeof(val) ? -EIO : 0;
102}
103
104
105
106
107static unsigned long
108ptrace_getrn(struct task_struct *child, unsigned long insn)
109{
110 unsigned int reg = (insn >> 16) & 15;
111 unsigned long val;
112
113 val = get_stack_long(child, reg);
114 if (reg == 15)
115 val = pc_pointer(val + 8);
116
117 return val;
118}
119
120
121
122
123static unsigned long
124ptrace_getaluop2(struct task_struct *child, unsigned long insn)
125{
126 unsigned long val;
127 int shift;
128 int type;
129
130 if (insn & 1 << 25) {
131 val = insn & 255;
132 shift = (insn >> 8) & 15;
133 type = 3;
134 } else {
135 val = get_stack_long (child, insn & 15);
136
137 if (insn & (1 << 4))
138 shift = (int)get_stack_long (child, (insn >> 8) & 15);
139 else
140 shift = (insn >> 7) & 31;
141
142 type = (insn >> 5) & 3;
143 }
144
145 switch (type) {
146 case 0: val <<= shift; break;
147 case 1: val >>= shift; break;
148 case 2:
149 val = (((signed long)val) >> shift);
150 break;
151 case 3:
152 val = (val >> shift) | (val << (32 - shift));
153 break;
154 }
155 return val;
156}
157
158
159
160
161static unsigned long
162ptrace_getldrop2(struct task_struct *child, unsigned long insn)
163{
164 unsigned long val;
165 int shift;
166 int type;
167
168 val = get_stack_long(child, insn & 15);
169 shift = (insn >> 7) & 31;
170 type = (insn >> 5) & 3;
171
172 switch (type) {
173 case 0: val <<= shift; break;
174 case 1: val >>= shift; break;
175 case 2:
176 val = (((signed long)val) >> shift);
177 break;
178 case 3:
179 val = (val >> shift) | (val << (32 - shift));
180 break;
181 }
182 return val;
183}
184
185static unsigned long
186get_branch_address(struct task_struct *child, unsigned long pc, unsigned long insn)
187{
188 unsigned long alt = 0;
189
190 switch (insn & 0x0e000000) {
191 case 0x00000000:
192 case 0x02000000: {
193
194
195
196 long aluop1, aluop2, ccbit;
197
198 if ((insn & 0xf000) != 0xf000)
199 break;
200
201 aluop1 = ptrace_getrn(child, insn);
202 aluop2 = ptrace_getaluop2(child, insn);
203 ccbit = get_stack_long(child, REG_PSR) & CC_C_BIT ? 1 : 0;
204
205 switch (insn & 0x01e00000) {
206 case 0x00000000: alt = aluop1 & aluop2; break;
207 case 0x00200000: alt = aluop1 ^ aluop2; break;
208 case 0x00400000: alt = aluop1 - aluop2; break;
209 case 0x00600000: alt = aluop2 - aluop1; break;
210 case 0x00800000: alt = aluop1 + aluop2; break;
211 case 0x00a00000: alt = aluop1 + aluop2 + ccbit; break;
212 case 0x00c00000: alt = aluop1 - aluop2 + ccbit; break;
213 case 0x00e00000: alt = aluop2 - aluop1 + ccbit; break;
214 case 0x01800000: alt = aluop1 | aluop2; break;
215 case 0x01a00000: alt = aluop2; break;
216 case 0x01c00000: alt = aluop1 & ~aluop2; break;
217 case 0x01e00000: alt = ~aluop2; break;
218 }
219 break;
220 }
221
222 case 0x04000000:
223 case 0x06000000:
224
225
226
227 if ((insn & 0x0010f000) == 0x0010f000) {
228 unsigned long base;
229
230 base = ptrace_getrn(child, insn);
231 if (insn & 1 << 24) {
232 long aluop2;
233
234 if (insn & 0x02000000)
235 aluop2 = ptrace_getldrop2(child, insn);
236 else
237 aluop2 = insn & 0xfff;
238
239 if (insn & 1 << 23)
240 base += aluop2;
241 else
242 base -= aluop2;
243 }
244 if (read_tsk_long(child, base, &alt) == 0)
245 alt = pc_pointer(alt);
246 }
247 break;
248
249 case 0x08000000:
250
251
252
253 if ((insn & 0x00108000) == 0x00108000) {
254 unsigned long base;
255 unsigned int nr_regs;
256
257 if (insn & (1 << 23)) {
258 nr_regs = insn & 65535;
259
260 nr_regs = (nr_regs & 0x5555) + ((nr_regs & 0xaaaa) >> 1);
261 nr_regs = (nr_regs & 0x3333) + ((nr_regs & 0xcccc) >> 2);
262 nr_regs = (nr_regs & 0x0707) + ((nr_regs & 0x7070) >> 4);
263 nr_regs = (nr_regs & 0x000f) + ((nr_regs & 0x0f00) >> 8);
264 nr_regs <<= 2;
265
266 if (!(insn & (1 << 24)))
267 nr_regs -= 4;
268 } else {
269 if (insn & (1 << 24))
270 nr_regs = -4;
271 else
272 nr_regs = 0;
273 }
274
275 base = ptrace_getrn(child, insn);
276
277 if (read_tsk_long(child, base + nr_regs, &alt) == 0)
278 alt = pc_pointer (alt);
279 break;
280 }
281 break;
282
283 case 0x0a000000: {
284
285
286
287 signed long displ;
288
289
290
291
292
293
294
295 displ = (insn & 0x00ffffff) << 8;
296 displ = (displ >> 6) + 8;
297 if (displ != 0 && displ != 4)
298 alt = pc + displ;
299 }
300 break;
301 }
302
303 return alt;
304}
305
306static int
307add_breakpoint(struct task_struct *child, struct debug_info *dbg, unsigned long addr)
308{
309 int nr = dbg->nsaved;
310 int res = -EINVAL;
311
312 if (nr < 2) {
313 res = read_tsk_long(child, addr, &dbg->bp[nr].insn);
314 if (res == 0)
315 res = write_tsk_long(child, addr, BREAKINST);
316
317 if (res == 0) {
318 dbg->bp[nr].address = addr;
319 dbg->nsaved += 1;
320 }
321 } else
322 printk(KERN_ERR "ptrace: too many breakpoints\n");
323
324 return res;
325}
326
327int ptrace_set_bpt(struct task_struct *child)
328{
329 struct pt_regs *regs;
330 unsigned long pc, insn;
331 int res;
332
333 regs = get_user_regs(child);
334 pc = instruction_pointer(regs);
335
336 res = read_tsk_long(child, pc, &insn);
337 if (!res) {
338 struct debug_info *dbg = &child->thread.debug;
339 unsigned long alt;
340
341 dbg->nsaved = 0;
342
343 alt = get_branch_address(child, pc, insn);
344 if (alt)
345 res = add_breakpoint(child, dbg, alt);
346
347
348
349
350
351
352
353
354
355
356 if (!alt || predicate(insn) != PREDICATE_ALWAYS)
357 res = add_breakpoint(child, dbg, pc + 4);
358 }
359
360 return res;
361}
362
363
364
365
366
367void __ptrace_cancel_bpt(struct task_struct *child)
368{
369 struct debug_info *dbg = &child->thread.debug;
370 int i, nsaved = dbg->nsaved;
371
372 dbg->nsaved = 0;
373
374 if (nsaved > 2) {
375 printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved);
376 nsaved = 2;
377 }
378
379 for (i = 0; i < nsaved; i++) {
380 unsigned long tmp;
381
382 read_tsk_long(child, dbg->bp[i].address, &tmp);
383 write_tsk_long(child, dbg->bp[i].address, dbg->bp[i].insn);
384 if (tmp != BREAKINST)
385 printk(KERN_ERR "ptrace_cancel_bpt: weirdness\n");
386 }
387}
388
389
390
391
392
393
394void ptrace_disable(struct task_struct *child)
395{
396 __ptrace_cancel_bpt(child);
397}
398
399static int do_ptrace(int request, struct task_struct *child, long addr, long data)
400{
401 unsigned long tmp;
402 int ret;
403
404 switch (request) {
405
406
407
408 case PTRACE_PEEKTEXT:
409 case PTRACE_PEEKDATA:
410 ret = read_tsk_long(child, addr, &tmp);
411 if (!ret)
412 ret = put_user(tmp, (unsigned long *) data);
413 break;
414
415
416
417
418 case PTRACE_PEEKUSR:
419 ret = -EIO;
420 if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
421 break;
422
423 tmp = 0;
424 if (addr < sizeof(struct pt_regs))
425 tmp = get_stack_long(child, (int)addr >> 2);
426 ret = put_user(tmp, (unsigned long *)data);
427 break;
428
429
430
431
432 case PTRACE_POKETEXT:
433 case PTRACE_POKEDATA:
434 ret = write_tsk_long(child, addr, data);
435 break;
436
437
438
439
440 case PTRACE_POKEUSR:
441 ret = -EIO;
442 if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
443 break;
444
445 if (addr < sizeof(struct pt_regs))
446 ret = put_stack_long(child, (int)addr >> 2, data);
447 break;
448
449
450
451
452 case PTRACE_SYSCALL:
453 case PTRACE_CONT:
454 ret = -EIO;
455 if ((unsigned long) data > _NSIG)
456 break;
457 if (request == PTRACE_SYSCALL)
458 child->ptrace |= PT_TRACESYS;
459 else
460 child->ptrace &= ~PT_TRACESYS;
461 child->exit_code = data;
462
463 __ptrace_cancel_bpt(child);
464 wake_up_process(child);
465 ret = 0;
466 break;
467
468
469
470
471
472
473 case PTRACE_KILL:
474
475 ret = 0;
476 if (child->state == TASK_ZOMBIE)
477 break;
478 child->exit_code = SIGKILL;
479
480 __ptrace_cancel_bpt(child);
481 wake_up_process(child);
482 ret = 0;
483 break;
484
485
486
487
488 case PTRACE_SINGLESTEP:
489 ret = -EIO;
490 if ((unsigned long) data > _NSIG)
491 break;
492 child->thread.debug.nsaved = -1;
493 child->ptrace &= ~PT_TRACESYS;
494 child->exit_code = data;
495
496 wake_up_process(child);
497 ret = 0;
498 break;
499
500
501
502
503 case PTRACE_DETACH:
504 ret = ptrace_detach(child, data);
505 break;
506
507
508
509
510 case PTRACE_GETREGS: {
511 struct pt_regs *regs = get_user_regs(child);
512
513 ret = 0;
514 if (copy_to_user((void *)data, regs,
515 sizeof(struct pt_regs)))
516 ret = -EFAULT;
517
518 break;
519 }
520
521
522
523
524 case PTRACE_SETREGS: {
525 struct pt_regs newregs;
526
527 ret = -EFAULT;
528 if (copy_from_user(&newregs, (void *)data,
529 sizeof(struct pt_regs)) == 0) {
530 struct pt_regs *regs = get_user_regs(child);
531
532 ret = -EINVAL;
533 if (valid_user_regs(&newregs)) {
534 *regs = newregs;
535 ret = 0;
536 }
537 }
538 break;
539 }
540
541
542
543
544 case PTRACE_GETFPREGS:
545 ret = -EIO;
546 if (!access_ok(VERIFY_WRITE, (void *)data, sizeof(struct user_fp)))
547 break;
548
549
550 ret = __copy_to_user((void *)data, &child->thread.fpstate,
551 sizeof(struct user_fp)) ? -EFAULT : 0;
552 break;
553
554
555
556
557 case PTRACE_SETFPREGS:
558 ret = -EIO;
559 if (!access_ok(VERIFY_READ, (void *)data, sizeof(struct user_fp)))
560 break;
561
562 child->used_math = 1;
563 ret = __copy_from_user(&child->thread.fpstate, (void *)data,
564 sizeof(struct user_fp)) ? -EFAULT : 0;
565 break;
566
567 default:
568 ret = -EIO;
569 break;
570 }
571
572 return ret;
573}
574
575asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
576{
577 struct task_struct *child;
578 int ret;
579
580 lock_kernel();
581 ret = -EPERM;
582 if (request == PTRACE_TRACEME) {
583
584 if (current->ptrace & PT_PTRACED)
585 goto out;
586
587 current->ptrace |= PT_PTRACED;
588 ret = 0;
589 goto out;
590 }
591 ret = -ESRCH;
592 read_lock(&tasklist_lock);
593 child = find_task_by_pid(pid);
594 if (child)
595 get_task_struct(child);
596 read_unlock(&tasklist_lock);
597 if (!child)
598 goto out;
599
600 ret = -EPERM;
601 if (pid == 1)
602 goto out_tsk;
603
604 if (request == PTRACE_ATTACH) {
605 ret = ptrace_attach(child);
606 goto out_tsk;
607 }
608 ret = -ESRCH;
609 if (!(child->ptrace & PT_PTRACED))
610 goto out_tsk;
611 if (child->state != TASK_STOPPED && request != PTRACE_KILL)
612 goto out_tsk;
613 if (child->p_pptr != current)
614 goto out_tsk;
615
616 ret = do_ptrace(request, child, addr, data);
617
618out_tsk:
619 free_task_struct(child);
620out:
621 unlock_kernel();
622 return ret;
623}
624
625asmlinkage void syscall_trace(int why, struct pt_regs *regs)
626{
627 unsigned long ip;
628
629 if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
630 != (PT_PTRACED|PT_TRACESYS))
631 return;
632
633
634
635
636
637 ip = regs->ARM_ip;
638 regs->ARM_ip = why;
639
640
641
642 current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
643 ? 0x80 : 0);
644 current->state = TASK_STOPPED;
645 notify_parent(current, SIGCHLD);
646 schedule();
647
648
649
650
651
652 if (current->exit_code) {
653 send_sig(current->exit_code, current, 1);
654 current->exit_code = 0;
655 }
656 regs->ARM_ip = ip;
657}
658