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