vserver 2.0 rc7
[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 #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         if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) {
326                 pt_error_return(regs, ESRCH);
327                 goto out_tsk;
328         }
329
330         if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH)
331             || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) {
332                 if (ptrace_attach(child)) {
333                         pt_error_return(regs, EPERM);
334                         goto out_tsk;
335                 }
336                 pt_succ_return(regs, 0);
337                 goto out_tsk;
338         }
339
340         ret = ptrace_check_attach(child, request == PTRACE_KILL);
341         if (ret < 0) {
342                 pt_error_return(regs, -ret);
343                 goto out_tsk;
344         }
345
346         switch(request) {
347         case PTRACE_PEEKTEXT: /* read word at location addr. */ 
348         case PTRACE_PEEKDATA: {
349                 unsigned long tmp;
350
351                 if (access_process_vm(child, addr,
352                                       &tmp, sizeof(tmp), 0) == sizeof(tmp))
353                         pt_os_succ_return(regs, tmp, (long __user *)data);
354                 else
355                         pt_error_return(regs, EIO);
356                 goto out_tsk;
357         }
358
359         case PTRACE_PEEKUSR:
360                 read_sunos_user(regs, addr, child, (long __user *) data);
361                 goto out_tsk;
362
363         case PTRACE_POKEUSR:
364                 write_sunos_user(regs, addr, child);
365                 goto out_tsk;
366
367         case PTRACE_POKETEXT: /* write the word at location addr. */
368         case PTRACE_POKEDATA: {
369                 if (access_process_vm(child, addr,
370                                       &data, sizeof(data), 1) == sizeof(data))
371                         pt_succ_return(regs, 0);
372                 else
373                         pt_error_return(regs, EIO);
374                 goto out_tsk;
375         }
376
377         case PTRACE_GETREGS: {
378                 struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
379                 struct pt_regs *cregs = child->thread.kregs;
380                 int rval;
381
382                 if (!access_ok(VERIFY_WRITE, pregs, sizeof(struct pt_regs))) {
383                         rval = -EFAULT;
384                         pt_error_return(regs, -rval);
385                         goto out_tsk;
386                 }
387                 __put_user(cregs->psr, (&pregs->psr));
388                 __put_user(cregs->pc, (&pregs->pc));
389                 __put_user(cregs->npc, (&pregs->npc));
390                 __put_user(cregs->y, (&pregs->y));
391                 for(rval = 1; rval < 16; rval++)
392                         __put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]));
393                 pt_succ_return(regs, 0);
394 #ifdef DEBUG_PTRACE
395                 printk ("PC=%x nPC=%x o7=%x\n", cregs->pc, cregs->npc, cregs->u_regs [15]);
396 #endif
397                 goto out_tsk;
398         }
399
400         case PTRACE_SETREGS: {
401                 struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
402                 struct pt_regs *cregs = child->thread.kregs;
403                 unsigned long psr, pc, npc, y;
404                 int i;
405
406                 /* Must be careful, tracing process can only set certain
407                  * bits in the psr.
408                  */
409                 if (!access_ok(VERIFY_READ, pregs, sizeof(struct pt_regs))) {
410                         pt_error_return(regs, EFAULT);
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                 if (!access_ok(VERIFY_WRITE, fps, sizeof(struct fps))) {
447                         i = -EFAULT;
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                 if (!access_ok(VERIFY_READ, fps, sizeof(struct fps))) {
482                         i = -EFAULT;
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 (!valid_signal(data)) {
535                         pt_error_return(regs, EIO);
536                         goto out_tsk;
537                 }
538
539                 if (request == PTRACE_SYSCALL)
540                         set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
541                 else
542                         clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
543
544                 child->exit_code = data;
545 #ifdef DEBUG_PTRACE
546                 printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n",
547                         child->comm, child->pid, child->exit_code,
548                         child->thread.kregs->pc,
549                         child->thread.kregs->npc);
550 #endif
551                 wake_up_process(child);
552                 pt_succ_return(regs, 0);
553                 goto out_tsk;
554         }
555
556 /*
557  * make the child exit.  Best I can do is send it a sigkill. 
558  * perhaps it should be put in the status that it wants to 
559  * exit.
560  */
561         case PTRACE_KILL: {
562                 if (child->exit_state == EXIT_ZOMBIE) { /* already dead */
563                         pt_succ_return(regs, 0);
564                         goto out_tsk;
565                 }
566                 wake_up_process(child);
567                 child->exit_code = SIGKILL;
568                 pt_succ_return(regs, 0);
569                 goto out_tsk;
570         }
571
572         case PTRACE_SUNDETACH: { /* detach a process that was attached. */
573                 int err = ptrace_detach(child, data);
574                 if (err) {
575                         pt_error_return(regs, EIO);
576                         goto out_tsk;
577                 }
578                 pt_succ_return(regs, 0);
579                 goto out_tsk;
580         }
581
582         /* PTRACE_DUMPCORE unsupported... */
583
584         default: {
585                 int err = ptrace_request(child, request, addr, data);
586                 if (err)
587                         pt_error_return(regs, -err);
588                 else
589                         pt_succ_return(regs, 0);
590                 goto out_tsk;
591         }
592         }
593 out_tsk:
594         if (child)
595                 put_task_struct(child);
596 out:
597         unlock_kernel();
598 }
599
600 asmlinkage void syscall_trace(void)
601 {
602 #ifdef DEBUG_PTRACE
603         printk("%s [%d]: syscall_trace\n", current->comm, current->pid);
604 #endif
605         if (!test_thread_flag(TIF_SYSCALL_TRACE))
606                 return;
607         if (!(current->ptrace & PT_PTRACED))
608                 return;
609         current->thread.flags ^= MAGIC_CONSTANT;
610         ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
611                                  ? 0x80 : 0));
612         /*
613          * this isn't the same as continuing with a signal, but it will do
614          * for normal use.  strace only continues with a signal if the
615          * stopping signal is not SIGTRAP.  -brl
616          */
617 #ifdef DEBUG_PTRACE
618         printk("%s [%d]: syscall_trace exit= %x\n", current->comm,
619                 current->pid, current->exit_code);
620 #endif
621         if (current->exit_code) {
622                 send_sig (current->exit_code, current, 1);
623                 current->exit_code = 0;
624         }
625 }