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