File: /usr/src/linux/arch/sparc/kernel/ptrace.c
1 /* ptrace.c: Sparc process tracing support.
2 *
3 * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu)
4 *
5 * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
6 * and David Mosberger.
7 *
8 * Added Linux support -miguel (weird, eh?, the orignal code was meant
9 * to emulate SunOS).
10 */
11
12 #include <linux/kernel.h>
13 #include <linux/sched.h>
14 #include <linux/mm.h>
15 #include <linux/errno.h>
16 #include <linux/ptrace.h>
17 #include <linux/user.h>
18 #include <linux/smp.h>
19 #include <linux/smp_lock.h>
20
21 #include <asm/pgtable.h>
22 #include <asm/system.h>
23 #include <asm/uaccess.h>
24
25 #define MAGIC_CONSTANT 0x80000000
26
27
28 /* Returning from ptrace is a bit tricky because the syscall return
29 * low level code assumes any value returned which is negative and
30 * is a valid errno will mean setting the condition codes to indicate
31 * an error return. This doesn't work, so we have this hook.
32 */
33 static inline void pt_error_return(struct pt_regs *regs, unsigned long error)
34 {
35 regs->u_regs[UREG_I0] = error;
36 regs->psr |= PSR_C;
37 regs->pc = regs->npc;
38 regs->npc += 4;
39 }
40
41 static inline void pt_succ_return(struct pt_regs *regs, unsigned long value)
42 {
43 regs->u_regs[UREG_I0] = value;
44 regs->psr &= ~PSR_C;
45 regs->pc = regs->npc;
46 regs->npc += 4;
47 }
48
49 static void
50 pt_succ_return_linux(struct pt_regs *regs, unsigned long value, long *addr)
51 {
52 if(put_user(value, addr))
53 return pt_error_return(regs, EFAULT);
54 regs->u_regs[UREG_I0] = 0;
55 regs->psr &= ~PSR_C;
56 regs->pc = regs->npc;
57 regs->npc += 4;
58 }
59
60 static void
61 pt_os_succ_return (struct pt_regs *regs, unsigned long val, long *addr)
62 {
63 if (current->personality == PER_SUNOS)
64 pt_succ_return (regs, val);
65 else
66 pt_succ_return_linux (regs, val, addr);
67 }
68
69 /* Fuck me gently with a chainsaw... */
70 static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset,
71 struct task_struct *tsk, long *addr)
72 {
73 struct pt_regs *cregs = tsk->thread.kregs;
74 struct thread_struct *t = &tsk->thread;
75 int v;
76
77 if(offset >= 1024)
78 offset -= 1024; /* whee... */
79 if(offset & ((sizeof(unsigned long) - 1))) {
80 pt_error_return(regs, EIO);
81 return;
82 }
83 if(offset >= 16 && offset < 784) {
84 offset -= 16; offset >>= 2;
85 pt_os_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset), addr);
86 return;
87 }
88 if(offset >= 784 && offset < 832) {
89 offset -= 784; offset >>= 2;
90 pt_os_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset), addr);
91 return;
92 }
93 switch(offset) {
94 case 0:
95 v = t->ksp;
96 break;
97 case 4:
98 v = t->kpc;
99 break;
100 case 8:
101 v = t->kpsr;
102 break;
103 case 12:
104 v = t->uwinmask;
105 break;
106 case 832:
107 v = t->w_saved;
108 break;
109 case 896:
110 v = cregs->u_regs[UREG_I0];
111 break;
112 case 900:
113 v = cregs->u_regs[UREG_I1];
114 break;
115 case 904:
116 v = cregs->u_regs[UREG_I2];
117 break;
118 case 908:
119 v = cregs->u_regs[UREG_I3];
120 break;
121 case 912:
122 v = cregs->u_regs[UREG_I4];
123 break;
124 case 916:
125 v = cregs->u_regs[UREG_I5];
126 break;
127 case 920:
128 v = cregs->u_regs[UREG_I6];
129 break;
130 case 924:
131 if(tsk->thread.flags & MAGIC_CONSTANT)
132 v = cregs->u_regs[UREG_G1];
133 else
134 v = 0;
135 break;
136 case 940:
137 v = cregs->u_regs[UREG_I0];
138 break;
139 case 944:
140 v = cregs->u_regs[UREG_I1];
141 break;
142
143 case 948:
144 /* Isn't binary compatibility _fun_??? */
145 if(cregs->psr & PSR_C)
146 v = cregs->u_regs[UREG_I0] << 24;
147 else
148 v = 0;
149 break;
150
151 /* Rest of them are completely unsupported. */
152 default:
153 printk("%s [%d]: Wants to read user offset %ld\n",
154 current->comm, current->pid, offset);
155 pt_error_return(regs, EIO);
156 return;
157 }
158 if (current->personality == PER_SUNOS)
159 pt_succ_return (regs, v);
160 else
161 pt_succ_return_linux (regs, v, addr);
162 return;
163 }
164
165 static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset,
166 struct task_struct *tsk)
167 {
168 struct pt_regs *cregs = tsk->thread.kregs;
169 struct thread_struct *t = &tsk->thread;
170 unsigned long value = regs->u_regs[UREG_I3];
171
172 if(offset >= 1024)
173 offset -= 1024; /* whee... */
174 if(offset & ((sizeof(unsigned long) - 1)))
175 goto failure;
176 if(offset >= 16 && offset < 784) {
177 offset -= 16; offset >>= 2;
178 *(((unsigned long *)(&t->reg_window[0]))+offset) = value;
179 goto success;
180 }
181 if(offset >= 784 && offset < 832) {
182 offset -= 784; offset >>= 2;
183 *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value;
184 goto success;
185 }
186 switch(offset) {
187 case 896:
188 cregs->u_regs[UREG_I0] = value;
189 break;
190 case 900:
191 cregs->u_regs[UREG_I1] = value;
192 break;
193 case 904:
194 cregs->u_regs[UREG_I2] = value;
195 break;
196 case 908:
197 cregs->u_regs[UREG_I3] = value;
198 break;
199 case 912:
200 cregs->u_regs[UREG_I4] = value;
201 break;
202 case 916:
203 cregs->u_regs[UREG_I5] = value;
204 break;
205 case 920:
206 cregs->u_regs[UREG_I6] = value;
207 break;
208 case 924:
209 cregs->u_regs[UREG_I7] = value;
210 break;
211 case 940:
212 cregs->u_regs[UREG_I0] = value;
213 break;
214 case 944:
215 cregs->u_regs[UREG_I1] = value;
216 break;
217
218 /* Rest of them are completely unsupported or "no-touch". */
219 default:
220 printk("%s [%d]: Wants to write user offset %ld\n",
221 current->comm, current->pid, offset);
222 goto failure;
223 }
224 success:
225 pt_succ_return(regs, 0);
226 return;
227 failure:
228 pt_error_return(regs, EIO);
229 return;
230 }
231
232 /* #define ALLOW_INIT_TRACING */
233 /* #define DEBUG_PTRACE */
234
235 #ifdef DEBUG_PTRACE
236 char *pt_rq [] = {
237 "TRACEME",
238 "PEEKTEXT",
239 "PEEKDATA",
240 "PEEKUSR",
241 "POKETEXT",
242 "POKEDATA",
243 "POKEUSR",
244 "CONT",
245 "KILL",
246 "SINGLESTEP",
247 "SUNATTACH",
248 "SUNDETACH",
249 "GETREGS",
250 "SETREGS",
251 "GETFPREGS",
252 "SETFPREGS",
253 "READDATA",
254 "WRITEDATA",
255 "READTEXT",
256 "WRITETEXT",
257 "GETFPAREGS",
258 "SETFPAREGS",
259 ""
260 };
261 #endif
262
263 /*
264 * Called by kernel/ptrace.c when detaching..
265 *
266 * Make sure single step bits etc are not set.
267 */
268 void ptrace_disable(struct task_struct *child)
269 {
270 /* nothing to do */
271 }
272
273 asmlinkage void do_ptrace(struct pt_regs *regs)
274 {
275 unsigned long request = regs->u_regs[UREG_I0];
276 unsigned long pid = regs->u_regs[UREG_I1];
277 unsigned long addr = regs->u_regs[UREG_I2];
278 unsigned long data = regs->u_regs[UREG_I3];
279 unsigned long addr2 = regs->u_regs[UREG_I4];
280 struct task_struct *child;
281
282 lock_kernel();
283 #ifdef DEBUG_PTRACE
284 {
285 char *s;
286
287 if ((request > 0) && (request < 21))
288 s = pt_rq [request];
289 else
290 s = "unknown";
291
292 if (request == PTRACE_POKEDATA && data == 0x91d02001){
293 printk ("do_ptrace: breakpoint pid=%d, addr=%08lx addr2=%08lx\n",
294 pid, addr, addr2);
295 } else
296 printk("do_ptrace: rq=%s(%d) pid=%d addr=%08lx data=%08lx addr2=%08lx\n",
297 s, (int) request, (int) pid, addr, data, addr2);
298 }
299 #endif
300 if(request == PTRACE_TRACEME) {
301 /* are we already being traced? */
302 if (current->ptrace & PT_PTRACED) {
303 pt_error_return(regs, EPERM);
304 goto out;
305 }
306 /* set the ptrace bit in the process flags. */
307 current->ptrace |= PT_PTRACED;
308 pt_succ_return(regs, 0);
309 goto out;
310 }
311 #ifndef ALLOW_INIT_TRACING
312 if(pid == 1) {
313 /* Can't dork with init. */
314 pt_error_return(regs, EPERM);
315 goto out;
316 }
317 #endif
318 read_lock(&tasklist_lock);
319 child = find_task_by_pid(pid);
320 if (child)
321 get_task_struct(child);
322 read_unlock(&tasklist_lock);
323
324 if (!child) {
325 pt_error_return(regs, ESRCH);
326 goto out;
327 }
328
329 if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH)
330 || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) {
331 if (ptrace_attach(child)) {
332 pt_error_return(regs, EPERM);
333 goto out_tsk;
334 }
335 pt_succ_return(regs, 0);
336 goto out_tsk;
337 }
338 if (!(child->ptrace & PT_PTRACED)) {
339 pt_error_return(regs, ESRCH);
340 goto out_tsk;
341 }
342 if(child->state != TASK_STOPPED) {
343 if(request != PTRACE_KILL) {
344 pt_error_return(regs, ESRCH);
345 goto out_tsk;
346 }
347 }
348 if(child->p_pptr != current) {
349 pt_error_return(regs, ESRCH);
350 goto out_tsk;
351 }
352 switch(request) {
353 case PTRACE_PEEKTEXT: /* read word at location addr. */
354 case PTRACE_PEEKDATA: {
355 unsigned long tmp;
356
357 if (access_process_vm(child, addr,
358 &tmp, sizeof(tmp), 0) == sizeof(tmp))
359 pt_os_succ_return(regs, tmp, (long *)data);
360 else
361 pt_error_return(regs, EIO);
362 goto out_tsk;
363 }
364
365 case PTRACE_PEEKUSR:
366 read_sunos_user(regs, addr, child, (long *) data);
367 goto out_tsk;
368
369 case PTRACE_POKEUSR:
370 write_sunos_user(regs, addr, child);
371 goto out_tsk;
372
373 case PTRACE_POKETEXT: /* write the word at location addr. */
374 case PTRACE_POKEDATA: {
375 if (access_process_vm(child, addr,
376 &data, sizeof(data), 1) == sizeof(data))
377 pt_succ_return(regs, 0);
378 else
379 pt_error_return(regs, EIO);
380 goto out_tsk;
381 }
382
383 case PTRACE_GETREGS: {
384 struct pt_regs *pregs = (struct pt_regs *) addr;
385 struct pt_regs *cregs = child->thread.kregs;
386 int rval;
387
388 rval = verify_area(VERIFY_WRITE, pregs, sizeof(struct pt_regs));
389 if(rval) {
390 pt_error_return(regs, -rval);
391 goto out_tsk;
392 }
393 __put_user(cregs->psr, (&pregs->psr));
394 __put_user(cregs->pc, (&pregs->pc));
395 __put_user(cregs->npc, (&pregs->npc));
396 __put_user(cregs->y, (&pregs->y));
397 for(rval = 1; rval < 16; rval++)
398 __put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]));
399 pt_succ_return(regs, 0);
400 #ifdef DEBUG_PTRACE
401 printk ("PC=%x nPC=%x o7=%x\n", cregs->pc, cregs->npc, cregs->u_regs [15]);
402 #endif
403 goto out_tsk;
404 }
405
406 case PTRACE_SETREGS: {
407 struct pt_regs *pregs = (struct pt_regs *) addr;
408 struct pt_regs *cregs = child->thread.kregs;
409 unsigned long psr, pc, npc, y;
410 int i;
411
412 /* Must be careful, tracing process can only set certain
413 * bits in the psr.
414 */
415 i = verify_area(VERIFY_READ, pregs, sizeof(struct pt_regs));
416 if(i) {
417 pt_error_return(regs, -i);
418 goto out_tsk;
419 }
420 __get_user(psr, (&pregs->psr));
421 __get_user(pc, (&pregs->pc));
422 __get_user(npc, (&pregs->npc));
423 __get_user(y, (&pregs->y));
424 psr &= PSR_ICC;
425 cregs->psr &= ~PSR_ICC;
426 cregs->psr |= psr;
427 if(!((pc | npc) & 3)) {
428 cregs->pc = pc;
429 cregs->npc =npc;
430 }
431 cregs->y = y;
432 for(i = 1; i < 16; i++)
433 __get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]));
434 pt_succ_return(regs, 0);
435 goto out_tsk;
436 }
437
438 case PTRACE_GETFPREGS: {
439 struct fps {
440 unsigned long regs[32];
441 unsigned long fsr;
442 unsigned long flags;
443 unsigned long extra;
444 unsigned long fpqd;
445 struct fq {
446 unsigned long *insnaddr;
447 unsigned long insn;
448 } fpq[16];
449 } *fps = (struct fps *) addr;
450 int i;
451
452 i = verify_area(VERIFY_WRITE, fps, sizeof(struct fps));
453 if(i) {
454 pt_error_return(regs, -i);
455 goto out_tsk;
456 }
457 for(i = 0; i < 32; i++)
458 __put_user(child->thread.float_regs[i], (&fps->regs[i]));
459 __put_user(child->thread.fsr, (&fps->fsr));
460 __put_user(child->thread.fpqdepth, (&fps->fpqd));
461 __put_user(0, (&fps->flags));
462 __put_user(0, (&fps->extra));
463 for(i = 0; i < 16; i++) {
464 __put_user(child->thread.fpqueue[i].insn_addr,
465 (&fps->fpq[i].insnaddr));
466 __put_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn));
467 }
468 pt_succ_return(regs, 0);
469 goto out_tsk;
470 }
471
472 case PTRACE_SETFPREGS: {
473 struct fps {
474 unsigned long regs[32];
475 unsigned long fsr;
476 unsigned long flags;
477 unsigned long extra;
478 unsigned long fpqd;
479 struct fq {
480 unsigned long *insnaddr;
481 unsigned long insn;
482 } fpq[16];
483 } *fps = (struct fps *) addr;
484 int i;
485
486 i = verify_area(VERIFY_READ, fps, sizeof(struct fps));
487 if(i) {
488 pt_error_return(regs, -i);
489 goto out_tsk;
490 }
491 copy_from_user(&child->thread.float_regs[0], &fps->regs[0], (32 * sizeof(unsigned long)));
492 __get_user(child->thread.fsr, (&fps->fsr));
493 __get_user(child->thread.fpqdepth, (&fps->fpqd));
494 for(i = 0; i < 16; i++) {
495 __get_user(child->thread.fpqueue[i].insn_addr,
496 (&fps->fpq[i].insnaddr));
497 __get_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn));
498 }
499 pt_succ_return(regs, 0);
500 goto out_tsk;
501 }
502
503 case PTRACE_READTEXT:
504 case PTRACE_READDATA: {
505 int res = ptrace_readdata(child, addr, (void *) addr2, data);
506
507 if (res == data) {
508 pt_succ_return(regs, 0);
509 goto out_tsk;
510 }
511 /* Partial read is an IO failure */
512 if (res >= 0)
513 res = -EIO;
514 pt_error_return(regs, -res);
515 goto out_tsk;
516 }
517
518 case PTRACE_WRITETEXT:
519 case PTRACE_WRITEDATA: {
520 int res = ptrace_writedata(child, (void *) addr2, addr, data);
521
522 if (res == data) {
523 pt_succ_return(regs, 0);
524 goto out_tsk;
525 }
526 /* Partial write is an IO failure */
527 if (res >= 0)
528 res = -EIO;
529 pt_error_return(regs, -res);
530 goto out_tsk;
531 }
532
533 case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
534 addr = 1;
535
536 case PTRACE_CONT: { /* restart after signal. */
537 if ((unsigned long) data > _NSIG) {
538 pt_error_return(regs, EIO);
539 goto out_tsk;
540 }
541 if (addr != 1) {
542 if (addr & 3) {
543 pt_error_return(regs, EINVAL);
544 goto out_tsk;
545 }
546 #ifdef DEBUG_PTRACE
547 printk ("Original: %08lx %08lx\n", child->thread.kregs->pc, child->thread.kregs->npc);
548 printk ("Continuing with %08lx %08lx\n", addr, addr+4);
549 #endif
550 child->thread.kregs->pc = addr;
551 child->thread.kregs->npc = addr + 4;
552 }
553
554 if (request == PTRACE_SYSCALL)
555 child->ptrace |= PT_TRACESYS;
556 else
557 child->ptrace &= ~PT_TRACESYS;
558
559 child->exit_code = data;
560 #ifdef DEBUG_PTRACE
561 printk("CONT: %s [%d]: set exit_code = %x %x %x\n", child->comm,
562 child->pid, child->exit_code,
563 child->thread.kregs->pc,
564 child->thread.kregs->npc);
565
566 #endif
567 wake_up_process(child);
568 pt_succ_return(regs, 0);
569 goto out_tsk;
570 }
571
572 /*
573 * make the child exit. Best I can do is send it a sigkill.
574 * perhaps it should be put in the status that it wants to
575 * exit.
576 */
577 case PTRACE_KILL: {
578 if (child->state == TASK_ZOMBIE) { /* already dead */
579 pt_succ_return(regs, 0);
580 goto out_tsk;
581 }
582 wake_up_process(child);
583 child->exit_code = SIGKILL;
584 pt_succ_return(regs, 0);
585 goto out_tsk;
586 }
587
588 case PTRACE_SUNDETACH: { /* detach a process that was attached. */
589 int err = ptrace_detach(child, data);
590 if (err) {
591 pt_error_return(regs, EIO);
592 goto out_tsk;
593 }
594 pt_succ_return(regs, 0);
595 goto out_tsk;
596 }
597
598 /* PTRACE_DUMPCORE unsupported... */
599
600 default:
601 pt_error_return(regs, EIO);
602 goto out_tsk;
603 }
604 out_tsk:
605 if (child)
606 free_task_struct(child);
607 out:
608 unlock_kernel();
609 }
610
611 asmlinkage void syscall_trace(void)
612 {
613 #ifdef DEBUG_PTRACE
614 printk("%s [%d]: syscall_trace\n", current->comm, current->pid);
615 #endif
616 if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
617 != (PT_PTRACED|PT_TRACESYS))
618 return;
619 current->exit_code = SIGTRAP;
620 current->state = TASK_STOPPED;
621 current->thread.flags ^= MAGIC_CONSTANT;
622 notify_parent(current, SIGCHLD);
623 schedule();
624 /*
625 * this isn't the same as continuing with a signal, but it will do
626 * for normal use. strace only continues with a signal if the
627 * stopping signal is not SIGTRAP. -brl
628 */
629 #ifdef DEBUG_PTRACE
630 printk("%s [%d]: syscall_trace exit= %x\n", current->comm,
631 current->pid, current->exit_code);
632 #endif
633 if (current->exit_code) {
634 send_sig (current->exit_code, current, 1);
635 current->exit_code = 0;
636 }
637 }
638