Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc
[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 = task_thread_info(tsk);
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 = task_thread_info(tsk);
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
290         if (request == PTRACE_TRACEME) {
291                 ret = ptrace_traceme();
292                 if (ret < 0)
293                         pt_error_return(regs, -ret);
294                 else
295                         pt_succ_return(regs, 0);
296                 goto out;
297         }
298
299         child = ptrace_get_task_struct(pid);
300         if (IS_ERR(child)) {
301                 ret = PTR_ERR(child);
302                 pt_error_return(regs, -ret);
303                 goto out;
304         }
305
306         if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH)
307             || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) {
308                 if (ptrace_attach(child)) {
309                         pt_error_return(regs, EPERM);
310                         goto out_tsk;
311                 }
312                 pt_succ_return(regs, 0);
313                 goto out_tsk;
314         }
315
316         ret = ptrace_check_attach(child, request == PTRACE_KILL);
317         if (ret < 0) {
318                 pt_error_return(regs, -ret);
319                 goto out_tsk;
320         }
321
322         switch(request) {
323         case PTRACE_PEEKTEXT: /* read word at location addr. */ 
324         case PTRACE_PEEKDATA: {
325                 unsigned long tmp;
326
327                 if (access_process_vm(child, addr,
328                                       &tmp, sizeof(tmp), 0) == sizeof(tmp))
329                         pt_os_succ_return(regs, tmp, (long __user *)data);
330                 else
331                         pt_error_return(regs, EIO);
332                 goto out_tsk;
333         }
334
335         case PTRACE_PEEKUSR:
336                 read_sunos_user(regs, addr, child, (long __user *) data);
337                 goto out_tsk;
338
339         case PTRACE_POKEUSR:
340                 write_sunos_user(regs, addr, child);
341                 goto out_tsk;
342
343         case PTRACE_POKETEXT: /* write the word at location addr. */
344         case PTRACE_POKEDATA: {
345                 if (access_process_vm(child, addr,
346                                       &data, sizeof(data), 1) == sizeof(data))
347                         pt_succ_return(regs, 0);
348                 else
349                         pt_error_return(regs, EIO);
350                 goto out_tsk;
351         }
352
353         case PTRACE_GETREGS: {
354                 struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
355                 struct pt_regs *cregs = child->thread.kregs;
356                 int rval;
357
358                 if (!access_ok(VERIFY_WRITE, pregs, sizeof(struct pt_regs))) {
359                         rval = -EFAULT;
360                         pt_error_return(regs, -rval);
361                         goto out_tsk;
362                 }
363                 __put_user(cregs->psr, (&pregs->psr));
364                 __put_user(cregs->pc, (&pregs->pc));
365                 __put_user(cregs->npc, (&pregs->npc));
366                 __put_user(cregs->y, (&pregs->y));
367                 for(rval = 1; rval < 16; rval++)
368                         __put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]));
369                 pt_succ_return(regs, 0);
370 #ifdef DEBUG_PTRACE
371                 printk ("PC=%x nPC=%x o7=%x\n", cregs->pc, cregs->npc, cregs->u_regs [15]);
372 #endif
373                 goto out_tsk;
374         }
375
376         case PTRACE_SETREGS: {
377                 struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
378                 struct pt_regs *cregs = child->thread.kregs;
379                 unsigned long psr, pc, npc, y;
380                 int i;
381
382                 /* Must be careful, tracing process can only set certain
383                  * bits in the psr.
384                  */
385                 if (!access_ok(VERIFY_READ, pregs, sizeof(struct pt_regs))) {
386                         pt_error_return(regs, EFAULT);
387                         goto out_tsk;
388                 }
389                 __get_user(psr, (&pregs->psr));
390                 __get_user(pc, (&pregs->pc));
391                 __get_user(npc, (&pregs->npc));
392                 __get_user(y, (&pregs->y));
393                 psr &= PSR_ICC;
394                 cregs->psr &= ~PSR_ICC;
395                 cregs->psr |= psr;
396                 if (!((pc | npc) & 3)) {
397                         cregs->pc = pc;
398                         cregs->npc =npc;
399                 }
400                 cregs->y = y;
401                 for(i = 1; i < 16; i++)
402                         __get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]));
403                 pt_succ_return(regs, 0);
404                 goto out_tsk;
405         }
406
407         case PTRACE_GETFPREGS: {
408                 struct fps {
409                         unsigned long regs[32];
410                         unsigned long fsr;
411                         unsigned long flags;
412                         unsigned long extra;
413                         unsigned long fpqd;
414                         struct fq {
415                                 unsigned long *insnaddr;
416                                 unsigned long insn;
417                         } fpq[16];
418                 };
419                 struct fps __user *fps = (struct fps __user *) addr;
420                 int i;
421
422                 if (!access_ok(VERIFY_WRITE, fps, sizeof(struct fps))) {
423                         i = -EFAULT;
424                         pt_error_return(regs, -i);
425                         goto out_tsk;
426                 }
427                 for(i = 0; i < 32; i++)
428                         __put_user(child->thread.float_regs[i], (&fps->regs[i]));
429                 __put_user(child->thread.fsr, (&fps->fsr));
430                 __put_user(child->thread.fpqdepth, (&fps->fpqd));
431                 __put_user(0, (&fps->flags));
432                 __put_user(0, (&fps->extra));
433                 for(i = 0; i < 16; i++) {
434                         __put_user(child->thread.fpqueue[i].insn_addr,
435                                    (&fps->fpq[i].insnaddr));
436                         __put_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn));
437                 }
438                 pt_succ_return(regs, 0);
439                 goto out_tsk;
440         }
441
442         case PTRACE_SETFPREGS: {
443                 struct fps {
444                         unsigned long regs[32];
445                         unsigned long fsr;
446                         unsigned long flags;
447                         unsigned long extra;
448                         unsigned long fpqd;
449                         struct fq {
450                                 unsigned long *insnaddr;
451                                 unsigned long insn;
452                         } fpq[16];
453                 };
454                 struct fps __user *fps = (struct fps __user *) addr;
455                 int i;
456
457                 if (!access_ok(VERIFY_READ, fps, sizeof(struct fps))) {
458                         i = -EFAULT;
459                         pt_error_return(regs, -i);
460                         goto out_tsk;
461                 }
462                 copy_from_user(&child->thread.float_regs[0], &fps->regs[0], (32 * sizeof(unsigned long)));
463                 __get_user(child->thread.fsr, (&fps->fsr));
464                 __get_user(child->thread.fpqdepth, (&fps->fpqd));
465                 for(i = 0; i < 16; i++) {
466                         __get_user(child->thread.fpqueue[i].insn_addr,
467                                    (&fps->fpq[i].insnaddr));
468                         __get_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn));
469                 }
470                 pt_succ_return(regs, 0);
471                 goto out_tsk;
472         }
473
474         case PTRACE_READTEXT:
475         case PTRACE_READDATA: {
476                 int res = ptrace_readdata(child, addr,
477                                           (void __user *) addr2, data);
478
479                 if (res == data) {
480                         pt_succ_return(regs, 0);
481                         goto out_tsk;
482                 }
483                 /* Partial read is an IO failure */
484                 if (res >= 0)
485                         res = -EIO;
486                 pt_error_return(regs, -res);
487                 goto out_tsk;
488         }
489
490         case PTRACE_WRITETEXT:
491         case PTRACE_WRITEDATA: {
492                 int res = ptrace_writedata(child, (void __user *) addr2,
493                                            addr, data);
494
495                 if (res == data) {
496                         pt_succ_return(regs, 0);
497                         goto out_tsk;
498                 }
499                 /* Partial write is an IO failure */
500                 if (res >= 0)
501                         res = -EIO;
502                 pt_error_return(regs, -res);
503                 goto out_tsk;
504         }
505
506         case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
507                 addr = 1;
508
509         case PTRACE_CONT: { /* restart after signal. */
510                 if (!valid_signal(data)) {
511                         pt_error_return(regs, EIO);
512                         goto out_tsk;
513                 }
514
515                 if (request == PTRACE_SYSCALL)
516                         set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
517                 else
518                         clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
519
520                 child->exit_code = data;
521 #ifdef DEBUG_PTRACE
522                 printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n",
523                         child->comm, child->pid, child->exit_code,
524                         child->thread.kregs->pc,
525                         child->thread.kregs->npc);
526 #endif
527                 wake_up_process(child);
528                 pt_succ_return(regs, 0);
529                 goto out_tsk;
530         }
531
532 /*
533  * make the child exit.  Best I can do is send it a sigkill. 
534  * perhaps it should be put in the status that it wants to 
535  * exit.
536  */
537         case PTRACE_KILL: {
538                 if (child->exit_state == EXIT_ZOMBIE) { /* already dead */
539                         pt_succ_return(regs, 0);
540                         goto out_tsk;
541                 }
542                 wake_up_process(child);
543                 child->exit_code = SIGKILL;
544                 pt_succ_return(regs, 0);
545                 goto out_tsk;
546         }
547
548         case PTRACE_SUNDETACH: { /* detach a process that was attached. */
549                 int err = ptrace_detach(child, data);
550                 if (err) {
551                         pt_error_return(regs, EIO);
552                         goto out_tsk;
553                 }
554                 pt_succ_return(regs, 0);
555                 goto out_tsk;
556         }
557
558         /* PTRACE_DUMPCORE unsupported... */
559
560         default: {
561                 int err = ptrace_request(child, request, addr, data);
562                 if (err)
563                         pt_error_return(regs, -err);
564                 else
565                         pt_succ_return(regs, 0);
566                 goto out_tsk;
567         }
568         }
569 out_tsk:
570         if (child)
571                 put_task_struct(child);
572 out:
573         unlock_kernel();
574 }
575
576 asmlinkage void syscall_trace(void)
577 {
578 #ifdef DEBUG_PTRACE
579         printk("%s [%d]: syscall_trace\n", current->comm, current->pid);
580 #endif
581         if (!test_thread_flag(TIF_SYSCALL_TRACE))
582                 return;
583         if (!(current->ptrace & PT_PTRACED))
584                 return;
585         current->thread.flags ^= MAGIC_CONSTANT;
586         ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
587                                  ? 0x80 : 0));
588         /*
589          * this isn't the same as continuing with a signal, but it will do
590          * for normal use.  strace only continues with a signal if the
591          * stopping signal is not SIGTRAP.  -brl
592          */
593 #ifdef DEBUG_PTRACE
594         printk("%s [%d]: syscall_trace exit= %x\n", current->comm,
595                 current->pid, current->exit_code);
596 #endif
597         if (current->exit_code) {
598                 send_sig (current->exit_code, current, 1);
599                 current->exit_code = 0;
600         }
601 }