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