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