1 /* ptrace.c: Sparc process tracing support.
3 * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu)
4 * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
6 * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
9 * Added Linux support -miguel (weird, eh?, the orignal code was meant
13 #include <linux/kernel.h>
14 #include <linux/sched.h>
16 #include <linux/errno.h>
17 #include <linux/ptrace.h>
18 #include <linux/user.h>
19 #include <linux/smp.h>
20 #include <linux/smp_lock.h>
23 #include <asm/pgtable.h>
24 #include <asm/system.h>
25 #include <asm/uaccess.h>
26 #include <asm/psrcompat.h>
27 #include <asm/visasm.h>
29 #define MAGIC_CONSTANT 0x80000000
31 /* Returning from ptrace is a bit tricky because the syscall return
32 * low level code assumes any value returned which is negative and
33 * is a valid errno will mean setting the condition codes to indicate
34 * an error return. This doesn't work, so we have this hook.
36 static inline void pt_error_return(struct pt_regs *regs, unsigned long error)
38 regs->u_regs[UREG_I0] = error;
39 regs->tstate |= (TSTATE_ICARRY | TSTATE_XCARRY);
40 regs->tpc = regs->tnpc;
44 static inline void pt_succ_return(struct pt_regs *regs, unsigned long value)
46 regs->u_regs[UREG_I0] = value;
47 regs->tstate &= ~(TSTATE_ICARRY | TSTATE_XCARRY);
48 regs->tpc = regs->tnpc;
53 pt_succ_return_linux(struct pt_regs *regs, unsigned long value, long *addr)
55 if (current->thread.flags & SPARC_FLAG_32BIT) {
56 if (put_user(value, (unsigned int *)addr))
57 return pt_error_return(regs, EFAULT);
59 if (put_user(value, addr))
60 return pt_error_return(regs, EFAULT);
62 regs->u_regs[UREG_I0] = 0;
63 regs->tstate &= ~(TSTATE_ICARRY | TSTATE_XCARRY);
64 regs->tpc = regs->tnpc;
69 pt_os_succ_return (struct pt_regs *regs, unsigned long val, long *addr)
71 if (current->personality == PER_SUNOS)
72 pt_succ_return (regs, val);
74 pt_succ_return_linux (regs, val, addr);
77 /* #define ALLOW_INIT_TRACING */
78 /* #define DEBUG_PTRACE */
108 asmlinkage void do_ptrace(struct pt_regs *regs)
110 int request = regs->u_regs[UREG_I0];
111 pid_t pid = regs->u_regs[UREG_I1];
112 unsigned long addr = regs->u_regs[UREG_I2];
113 unsigned long data = regs->u_regs[UREG_I3];
114 unsigned long addr2 = regs->u_regs[UREG_I4];
115 struct task_struct *child;
117 if (current->thread.flags & SPARC_FLAG_32BIT) {
118 addr &= 0xffffffffUL;
119 data &= 0xffffffffUL;
120 addr2 &= 0xffffffffUL;
127 if ((request > 0) && (request < 21))
132 if (request == PTRACE_POKEDATA && data == 0x91d02001){
133 printk ("do_ptrace: breakpoint pid=%d, addr=%016lx addr2=%016lx\n",
136 printk("do_ptrace: rq=%s(%d) pid=%d addr=%016lx data=%016lx addr2=%016lx\n",
137 s, request, pid, addr, data, addr2);
140 if (request == PTRACE_TRACEME) {
141 /* are we already being traced? */
142 if (current->ptrace & PT_PTRACED) {
143 pt_error_return(regs, EPERM);
146 /* set the ptrace bit in the process flags. */
147 current->ptrace |= PT_PTRACED;
148 pt_succ_return(regs, 0);
151 #ifndef ALLOW_INIT_TRACING
153 /* Can't dork with init. */
154 pt_error_return(regs, EPERM);
158 read_lock(&tasklist_lock);
159 child = find_task_by_pid(pid);
161 get_task_struct(child);
162 read_unlock(&tasklist_lock);
165 pt_error_return(regs, ESRCH);
169 if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH)
170 || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) {
173 if (child == current) {
174 /* Try this under SunOS/Solaris, bwa haha
175 * You'll never be able to kill the process. ;-)
177 pt_error_return(regs, EPERM);
180 if ((!child->dumpable ||
181 (current->uid != child->euid) ||
182 (current->uid != child->uid) ||
183 (current->uid != child->suid) ||
184 (current->gid != child->egid) ||
185 (current->gid != child->sgid) ||
186 (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
187 (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) {
188 pt_error_return(regs, EPERM);
191 /* the same process cannot be attached many times */
192 if (child->ptrace & PT_PTRACED) {
193 pt_error_return(regs, EPERM);
196 child->ptrace |= PT_PTRACED;
197 write_lock_irqsave(&tasklist_lock, flags);
198 if (child->p_pptr != current) {
200 child->p_pptr = current;
203 write_unlock_irqrestore(&tasklist_lock, flags);
204 send_sig(SIGSTOP, child, 1);
205 pt_succ_return(regs, 0);
208 if (!(child->ptrace & PT_PTRACED)) {
209 pt_error_return(regs, ESRCH);
212 if (child->state != TASK_STOPPED) {
213 if (request != PTRACE_KILL) {
214 pt_error_return(regs, ESRCH);
218 if (child->p_pptr != current) {
219 pt_error_return(regs, ESRCH);
223 if (!(child->thread.flags & SPARC_FLAG_32BIT) &&
224 ((request == PTRACE_READDATA64) ||
225 (request == PTRACE_WRITEDATA64) ||
226 (request == PTRACE_READTEXT64) ||
227 (request == PTRACE_WRITETEXT64) ||
228 (request == PTRACE_PEEKTEXT64) ||
229 (request == PTRACE_POKETEXT64) ||
230 (request == PTRACE_PEEKDATA64) ||
231 (request == PTRACE_POKEDATA64))) {
232 addr = regs->u_regs[UREG_G2];
233 addr2 = regs->u_regs[UREG_G3];
234 request -= 30; /* wheee... */
238 case PTRACE_PEEKTEXT: /* read word at location addr. */
239 case PTRACE_PEEKDATA: {
245 if (current->thread.flags & SPARC_FLAG_32BIT) {
246 copied = access_process_vm(child, addr,
247 &tmp32, sizeof(tmp32), 0);
248 tmp64 = (unsigned long) tmp32;
249 if (copied == sizeof(tmp32))
252 copied = access_process_vm(child, addr,
253 &tmp64, sizeof(tmp64), 0);
254 if (copied == sizeof(tmp64))
258 pt_error_return(regs, -res);
260 pt_os_succ_return(regs, tmp64, (long *) data);
264 case PTRACE_POKETEXT: /* write the word at location addr. */
265 case PTRACE_POKEDATA: {
268 int copied, res = -EIO;
270 if (current->thread.flags & SPARC_FLAG_32BIT) {
272 copied = access_process_vm(child, addr,
273 &tmp32, sizeof(tmp32), 1);
274 if (copied == sizeof(tmp32))
278 copied = access_process_vm(child, addr,
279 &tmp64, sizeof(tmp64), 1);
280 if (copied == sizeof(tmp64))
284 pt_error_return(regs, -res);
286 pt_succ_return(regs, res);
290 case PTRACE_GETREGS: {
291 struct pt_regs32 *pregs = (struct pt_regs32 *) addr;
292 struct pt_regs *cregs = child->thread.kregs;
295 if (__put_user(tstate_to_psr(cregs->tstate), (&pregs->psr)) ||
296 __put_user(cregs->tpc, (&pregs->pc)) ||
297 __put_user(cregs->tnpc, (&pregs->npc)) ||
298 __put_user(cregs->y, (&pregs->y))) {
299 pt_error_return(regs, EFAULT);
302 for (rval = 1; rval < 16; rval++)
303 if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) {
304 pt_error_return(regs, EFAULT);
307 pt_succ_return(regs, 0);
309 printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]);
314 case PTRACE_GETREGS64: {
315 struct pt_regs *pregs = (struct pt_regs *) addr;
316 struct pt_regs *cregs = child->thread.kregs;
317 unsigned long tpc = cregs->tpc;
320 if ((child->thread.flags & SPARC_FLAG_32BIT) != 0)
322 if (__put_user(cregs->tstate, (&pregs->tstate)) ||
323 __put_user(tpc, (&pregs->tpc)) ||
324 __put_user(cregs->tnpc, (&pregs->tnpc)) ||
325 __put_user(cregs->y, (&pregs->y))) {
326 pt_error_return(regs, EFAULT);
329 for (rval = 1; rval < 16; rval++)
330 if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) {
331 pt_error_return(regs, EFAULT);
334 pt_succ_return(regs, 0);
336 printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]);
341 case PTRACE_SETREGS: {
342 struct pt_regs32 *pregs = (struct pt_regs32 *) addr;
343 struct pt_regs *cregs = child->thread.kregs;
344 unsigned int psr, pc, npc, y;
347 /* Must be careful, tracing process can only set certain
350 if (__get_user(psr, (&pregs->psr)) ||
351 __get_user(pc, (&pregs->pc)) ||
352 __get_user(npc, (&pregs->npc)) ||
353 __get_user(y, (&pregs->y))) {
354 pt_error_return(regs, EFAULT);
357 cregs->tstate &= ~(TSTATE_ICC);
358 cregs->tstate |= psr_to_tstate_icc(psr);
359 if (!((pc | npc) & 3)) {
364 for (i = 1; i < 16; i++) {
365 if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
366 pt_error_return(regs, EFAULT);
370 pt_succ_return(regs, 0);
374 case PTRACE_SETREGS64: {
375 struct pt_regs *pregs = (struct pt_regs *) addr;
376 struct pt_regs *cregs = child->thread.kregs;
377 unsigned long tstate, tpc, tnpc, y;
380 /* Must be careful, tracing process can only set certain
383 if (__get_user(tstate, (&pregs->tstate)) ||
384 __get_user(tpc, (&pregs->tpc)) ||
385 __get_user(tnpc, (&pregs->tnpc)) ||
386 __get_user(y, (&pregs->y))) {
387 pt_error_return(regs, EFAULT);
390 if ((child->thread.flags & SPARC_FLAG_32BIT) != 0) {
394 tstate &= (TSTATE_ICC | TSTATE_XCC);
395 cregs->tstate &= ~(TSTATE_ICC | TSTATE_XCC);
396 cregs->tstate |= tstate;
397 if (!((tpc | tnpc) & 3)) {
402 for (i = 1; i < 16; i++) {
403 if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
404 pt_error_return(regs, EFAULT);
408 pt_succ_return(regs, 0);
412 case PTRACE_GETFPREGS: {
414 unsigned int regs[32];
420 unsigned int insnaddr;
423 } *fps = (struct fps *) addr;
424 unsigned long *fpregs = (unsigned long *)(((char *)child) + AOFF_task_fpregs);
426 if (copy_to_user(&fps->regs[0], fpregs,
427 (32 * sizeof(unsigned int))) ||
428 __put_user(child->thread.xfsr[0], (&fps->fsr)) ||
429 __put_user(0, (&fps->fpqd)) ||
430 __put_user(0, (&fps->flags)) ||
431 __put_user(0, (&fps->extra)) ||
432 clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) {
433 pt_error_return(regs, EFAULT);
436 pt_succ_return(regs, 0);
440 case PTRACE_GETFPREGS64: {
442 unsigned int regs[64];
444 } *fps = (struct fps *) addr;
445 unsigned long *fpregs = (unsigned long *)(((char *)child) + AOFF_task_fpregs);
447 if (copy_to_user(&fps->regs[0], fpregs,
448 (64 * sizeof(unsigned int))) ||
449 __put_user(child->thread.xfsr[0], (&fps->fsr))) {
450 pt_error_return(regs, EFAULT);
453 pt_succ_return(regs, 0);
457 case PTRACE_SETFPREGS: {
459 unsigned int regs[32];
465 unsigned int insnaddr;
468 } *fps = (struct fps *) addr;
469 unsigned long *fpregs = (unsigned long *)(((char *)child) + AOFF_task_fpregs);
472 if (copy_from_user(fpregs, &fps->regs[0],
473 (32 * sizeof(unsigned int))) ||
474 __get_user(fsr, (&fps->fsr))) {
475 pt_error_return(regs, EFAULT);
478 child->thread.xfsr[0] &= 0xffffffff00000000UL;
479 child->thread.xfsr[0] |= fsr;
480 if (!(child->thread.fpsaved[0] & FPRS_FEF))
481 child->thread.gsr[0] = 0;
482 child->thread.fpsaved[0] |= (FPRS_FEF | FPRS_DL);
483 pt_succ_return(regs, 0);
487 case PTRACE_SETFPREGS64: {
489 unsigned int regs[64];
491 } *fps = (struct fps *) addr;
492 unsigned long *fpregs = (unsigned long *)(((char *)child) + AOFF_task_fpregs);
494 if (copy_from_user(fpregs, &fps->regs[0],
495 (64 * sizeof(unsigned int))) ||
496 __get_user(child->thread.xfsr[0], (&fps->fsr))) {
497 pt_error_return(regs, EFAULT);
500 if (!(child->thread.fpsaved[0] & FPRS_FEF))
501 child->thread.gsr[0] = 0;
502 child->thread.fpsaved[0] |= (FPRS_FEF | FPRS_DL | FPRS_DU);
503 pt_succ_return(regs, 0);
507 case PTRACE_READTEXT:
508 case PTRACE_READDATA: {
509 int res = ptrace_readdata(child, addr,
510 (void *)addr2, data);
512 pt_succ_return(regs, 0);
517 pt_error_return(regs, -res);
521 case PTRACE_WRITETEXT:
522 case PTRACE_WRITEDATA: {
523 int res = ptrace_writedata(child, (void *) addr2,
526 pt_succ_return(regs, 0);
531 pt_error_return(regs, -res);
534 case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
537 case PTRACE_CONT: { /* restart after signal. */
539 pt_error_return(regs, EIO);
543 unsigned long pc_mask = ~0UL;
545 if ((child->thread.flags & SPARC_FLAG_32BIT) != 0)
546 pc_mask = 0xffffffff;
549 pt_error_return(regs, EINVAL);
553 printk ("Original: %016lx %016lx\n", child->thread.kregs->tpc, child->thread.kregs->tnpc);
554 printk ("Continuing with %016lx %016lx\n", addr, addr+4);
556 child->thread.kregs->tpc = (addr & pc_mask);
557 child->thread.kregs->tnpc = ((addr + 4) & pc_mask);
560 if (request == PTRACE_SYSCALL)
561 child->ptrace |= PT_TRACESYS;
563 child->ptrace &= ~PT_TRACESYS;
565 child->exit_code = data;
567 printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n", child->comm,
568 child->pid, child->exit_code,
569 child->thread.kregs->tpc,
570 child->thread.kregs->tnpc);
573 wake_up_process(child);
574 pt_succ_return(regs, 0);
579 * make the child exit. Best I can do is send it a sigkill.
580 * perhaps it should be put in the status that it wants to
584 if (child->state == TASK_ZOMBIE) { /* already dead */
585 pt_succ_return(regs, 0);
588 child->exit_code = SIGKILL;
589 wake_up_process(child);
590 pt_succ_return(regs, 0);
594 case PTRACE_SUNDETACH: { /* detach a process that was attached. */
597 if ((unsigned long) data > _NSIG) {
598 pt_error_return(regs, EIO);
601 child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
602 child->exit_code = data;
604 write_lock_irqsave(&tasklist_lock, flags);
606 child->p_pptr = child->p_opptr;
608 write_unlock_irqrestore(&tasklist_lock, flags);
610 wake_up_process(child);
611 pt_succ_return(regs, 0);
615 /* PTRACE_DUMPCORE unsupported... */
618 pt_error_return(regs, EIO);
625 if (tlb_type == cheetah) {
626 for (va = 0; va < (1 << 16); va += (1 << 5))
627 spitfire_put_dcache_tag(va, 0x0);
628 /* No need to mess with I-cache on Cheetah. */
630 for (va = 0; va < (PAGE_SIZE << 1); va += 32)
631 spitfire_put_dcache_tag(va, 0x0);
632 if (request == PTRACE_PEEKTEXT ||
633 request == PTRACE_POKETEXT ||
634 request == PTRACE_READTEXT ||
635 request == PTRACE_WRITETEXT) {
636 for (va = 0; va < (PAGE_SIZE << 1); va += 32)
637 spitfire_put_icache_tag(va, 0x0);
638 __asm__ __volatile__("flush %g6");
644 free_task_struct(child);
649 asmlinkage void syscall_trace(void)
652 printk("%s [%d]: syscall_trace\n", current->comm, current->pid);
654 if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
655 != (PT_PTRACED|PT_TRACESYS))
657 current->exit_code = SIGTRAP;
658 current->state = TASK_STOPPED;
659 current->thread.flags ^= MAGIC_CONSTANT;
660 notify_parent(current, SIGCHLD);
663 * this isn't the same as continuing with a signal, but it will do
664 * for normal use. strace only continues with a signal if the
665 * stopping signal is not SIGTRAP. -brl
668 printk("%s [%d]: syscall_trace exit= %x\n", current->comm,
669 current->pid, current->exit_code);
671 if (current->exit_code) {
672 send_sig (current->exit_code, current, 1);
673 current->exit_code = 0;