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