d935eb602ce6882aff22616b4f489b5c08de6c0a
[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
172         if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH)
173             || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) {
174                 if (ptrace_attach(child)) {
175                         pt_error_return(regs, EPERM);
176                         goto out_tsk;
177                 }
178                 pt_succ_return(regs, 0);
179                 goto out_tsk;
180         }
181
182         ret = ptrace_check_attach(child, request == PTRACE_KILL);
183         if (ret < 0) {
184                 pt_error_return(regs, -ret);
185                 goto out_tsk;
186         }
187
188         if (!(test_thread_flag(TIF_32BIT))      &&
189             ((request == PTRACE_READDATA64)             ||
190              (request == PTRACE_WRITEDATA64)            ||
191              (request == PTRACE_READTEXT64)             ||
192              (request == PTRACE_WRITETEXT64)            ||
193              (request == PTRACE_PEEKTEXT64)             ||
194              (request == PTRACE_POKETEXT64)             ||
195              (request == PTRACE_PEEKDATA64)             ||
196              (request == PTRACE_POKEDATA64))) {
197                 addr = regs->u_regs[UREG_G2];
198                 addr2 = regs->u_regs[UREG_G3];
199                 request -= 30; /* wheee... */
200         }
201
202         switch(request) {
203         case PTRACE_PEEKTEXT: /* read word at location addr. */ 
204         case PTRACE_PEEKDATA: {
205                 unsigned long tmp64;
206                 unsigned int tmp32;
207                 int res, copied;
208
209                 res = -EIO;
210                 if (test_thread_flag(TIF_32BIT)) {
211                         copied = access_process_vm(child, addr,
212                                                    &tmp32, sizeof(tmp32), 0);
213                         tmp64 = (unsigned long) tmp32;
214                         if (copied == sizeof(tmp32))
215                                 res = 0;
216                 } else {
217                         copied = access_process_vm(child, addr,
218                                                    &tmp64, sizeof(tmp64), 0);
219                         if (copied == sizeof(tmp64))
220                                 res = 0;
221                 }
222                 if (res < 0)
223                         pt_error_return(regs, -res);
224                 else
225                         pt_os_succ_return(regs, tmp64, (long *) data);
226                 goto flush_and_out;
227         }
228
229         case PTRACE_POKETEXT: /* write the word at location addr. */
230         case PTRACE_POKEDATA: {
231                 unsigned long tmp64;
232                 unsigned int tmp32;
233                 int copied, res = -EIO;
234
235                 if (test_thread_flag(TIF_32BIT)) {
236                         tmp32 = data;
237                         copied = access_process_vm(child, addr,
238                                                    &tmp32, sizeof(tmp32), 1);
239                         if (copied == sizeof(tmp32))
240                                 res = 0;
241                 } else {
242                         tmp64 = data;
243                         copied = access_process_vm(child, addr,
244                                                    &tmp64, sizeof(tmp64), 1);
245                         if (copied == sizeof(tmp64))
246                                 res = 0;
247                 }
248                 if (res < 0)
249                         pt_error_return(regs, -res);
250                 else
251                         pt_succ_return(regs, res);
252                 goto flush_and_out;
253         }
254
255         case PTRACE_GETREGS: {
256                 struct pt_regs32 *pregs = (struct pt_regs32 *) addr;
257                 struct pt_regs *cregs = child->thread_info->kregs;
258                 int rval;
259
260                 if (__put_user(tstate_to_psr(cregs->tstate), (&pregs->psr)) ||
261                     __put_user(cregs->tpc, (&pregs->pc)) ||
262                     __put_user(cregs->tnpc, (&pregs->npc)) ||
263                     __put_user(cregs->y, (&pregs->y))) {
264                         pt_error_return(regs, EFAULT);
265                         goto out_tsk;
266                 }
267                 for (rval = 1; rval < 16; rval++)
268                         if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) {
269                                 pt_error_return(regs, EFAULT);
270                                 goto out_tsk;
271                         }
272                 pt_succ_return(regs, 0);
273 #ifdef DEBUG_PTRACE
274                 printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]);
275 #endif
276                 goto out_tsk;
277         }
278
279         case PTRACE_GETREGS64: {
280                 struct pt_regs *pregs = (struct pt_regs *) addr;
281                 struct pt_regs *cregs = child->thread_info->kregs;
282                 unsigned long tpc = cregs->tpc;
283                 int rval;
284
285                 if ((child->thread_info->flags & _TIF_32BIT) != 0)
286                         tpc &= 0xffffffff;
287                 if (__put_user(cregs->tstate, (&pregs->tstate)) ||
288                     __put_user(tpc, (&pregs->tpc)) ||
289                     __put_user(cregs->tnpc, (&pregs->tnpc)) ||
290                     __put_user(cregs->y, (&pregs->y))) {
291                         pt_error_return(regs, EFAULT);
292                         goto out_tsk;
293                 }
294                 for (rval = 1; rval < 16; rval++)
295                         if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) {
296                                 pt_error_return(regs, EFAULT);
297                                 goto out_tsk;
298                         }
299                 pt_succ_return(regs, 0);
300 #ifdef DEBUG_PTRACE
301                 printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]);
302 #endif
303                 goto out_tsk;
304         }
305
306         case PTRACE_SETREGS: {
307                 struct pt_regs32 *pregs = (struct pt_regs32 *) addr;
308                 struct pt_regs *cregs = child->thread_info->kregs;
309                 unsigned int psr, pc, npc, y;
310                 int i;
311
312                 /* Must be careful, tracing process can only set certain
313                  * bits in the psr.
314                  */
315                 if (__get_user(psr, (&pregs->psr)) ||
316                     __get_user(pc, (&pregs->pc)) ||
317                     __get_user(npc, (&pregs->npc)) ||
318                     __get_user(y, (&pregs->y))) {
319                         pt_error_return(regs, EFAULT);
320                         goto out_tsk;
321                 }
322                 cregs->tstate &= ~(TSTATE_ICC);
323                 cregs->tstate |= psr_to_tstate_icc(psr);
324                 if (!((pc | npc) & 3)) {
325                         cregs->tpc = pc;
326                         cregs->tnpc = npc;
327                 }
328                 cregs->y = y;
329                 for (i = 1; i < 16; i++) {
330                         if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
331                                 pt_error_return(regs, EFAULT);
332                                 goto out_tsk;
333                         }
334                 }
335                 pt_succ_return(regs, 0);
336                 goto out_tsk;
337         }
338
339         case PTRACE_SETREGS64: {
340                 struct pt_regs *pregs = (struct pt_regs *) addr;
341                 struct pt_regs *cregs = child->thread_info->kregs;
342                 unsigned long tstate, tpc, tnpc, y;
343                 int i;
344
345                 /* Must be careful, tracing process can only set certain
346                  * bits in the psr.
347                  */
348                 if (__get_user(tstate, (&pregs->tstate)) ||
349                     __get_user(tpc, (&pregs->tpc)) ||
350                     __get_user(tnpc, (&pregs->tnpc)) ||
351                     __get_user(y, (&pregs->y))) {
352                         pt_error_return(regs, EFAULT);
353                         goto out_tsk;
354                 }
355                 if ((child->thread_info->flags & _TIF_32BIT) != 0) {
356                         tpc &= 0xffffffff;
357                         tnpc &= 0xffffffff;
358                 }
359                 tstate &= (TSTATE_ICC | TSTATE_XCC);
360                 cregs->tstate &= ~(TSTATE_ICC | TSTATE_XCC);
361                 cregs->tstate |= tstate;
362                 if (!((tpc | tnpc) & 3)) {
363                         cregs->tpc = tpc;
364                         cregs->tnpc = tnpc;
365                 }
366                 cregs->y = y;
367                 for (i = 1; i < 16; i++) {
368                         if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
369                                 pt_error_return(regs, EFAULT);
370                                 goto out_tsk;
371                         }
372                 }
373                 pt_succ_return(regs, 0);
374                 goto out_tsk;
375         }
376
377         case PTRACE_GETFPREGS: {
378                 struct fps {
379                         unsigned int regs[32];
380                         unsigned int fsr;
381                         unsigned int flags;
382                         unsigned int extra;
383                         unsigned int fpqd;
384                         struct fq {
385                                 unsigned int insnaddr;
386                                 unsigned int insn;
387                         } fpq[16];
388                 } *fps = (struct fps *) addr;
389                 unsigned long *fpregs = child->thread_info->fpregs;
390
391                 if (copy_to_user(&fps->regs[0], fpregs,
392                                  (32 * sizeof(unsigned int))) ||
393                     __put_user(child->thread_info->xfsr[0], (&fps->fsr)) ||
394                     __put_user(0, (&fps->fpqd)) ||
395                     __put_user(0, (&fps->flags)) ||
396                     __put_user(0, (&fps->extra)) ||
397                     clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) {
398                         pt_error_return(regs, EFAULT);
399                         goto out_tsk;
400                 }
401                 pt_succ_return(regs, 0);
402                 goto out_tsk;
403         }
404
405         case PTRACE_GETFPREGS64: {
406                 struct fps {
407                         unsigned int regs[64];
408                         unsigned long fsr;
409                 } *fps = (struct fps *) addr;
410                 unsigned long *fpregs = child->thread_info->fpregs;
411
412                 if (copy_to_user(&fps->regs[0], fpregs,
413                                  (64 * sizeof(unsigned int))) ||
414                     __put_user(child->thread_info->xfsr[0], (&fps->fsr))) {
415                         pt_error_return(regs, EFAULT);
416                         goto out_tsk;
417                 }
418                 pt_succ_return(regs, 0);
419                 goto out_tsk;
420         }
421
422         case PTRACE_SETFPREGS: {
423                 struct fps {
424                         unsigned int regs[32];
425                         unsigned int fsr;
426                         unsigned int flags;
427                         unsigned int extra;
428                         unsigned int fpqd;
429                         struct fq {
430                                 unsigned int insnaddr;
431                                 unsigned int insn;
432                         } fpq[16];
433                 } *fps = (struct fps *) addr;
434                 unsigned long *fpregs = child->thread_info->fpregs;
435                 unsigned fsr;
436
437                 if (copy_from_user(fpregs, &fps->regs[0],
438                                    (32 * sizeof(unsigned int))) ||
439                     __get_user(fsr, (&fps->fsr))) {
440                         pt_error_return(regs, EFAULT);
441                         goto out_tsk;
442                 }
443                 child->thread_info->xfsr[0] &= 0xffffffff00000000UL;
444                 child->thread_info->xfsr[0] |= fsr;
445                 if (!(child->thread_info->fpsaved[0] & FPRS_FEF))
446                         child->thread_info->gsr[0] = 0;
447                 child->thread_info->fpsaved[0] |= (FPRS_FEF | FPRS_DL);
448                 pt_succ_return(regs, 0);
449                 goto out_tsk;
450         }
451
452         case PTRACE_SETFPREGS64: {
453                 struct fps {
454                         unsigned int regs[64];
455                         unsigned long fsr;
456                 } *fps = (struct fps *) addr;
457                 unsigned long *fpregs = child->thread_info->fpregs;
458
459                 if (copy_from_user(fpregs, &fps->regs[0],
460                                    (64 * sizeof(unsigned int))) ||
461                     __get_user(child->thread_info->xfsr[0], (&fps->fsr))) {
462                         pt_error_return(regs, EFAULT);
463                         goto out_tsk;
464                 }
465                 if (!(child->thread_info->fpsaved[0] & FPRS_FEF))
466                         child->thread_info->gsr[0] = 0;
467                 child->thread_info->fpsaved[0] |= (FPRS_FEF | FPRS_DL | FPRS_DU);
468                 pt_succ_return(regs, 0);
469                 goto out_tsk;
470         }
471
472         case PTRACE_READTEXT:
473         case PTRACE_READDATA: {
474                 int res = ptrace_readdata(child, addr,
475                                           (void *)addr2, data);
476                 if (res == data) {
477                         pt_succ_return(regs, 0);
478                         goto flush_and_out;
479                 }
480                 if (res >= 0)
481                         res = -EIO;
482                 pt_error_return(regs, -res);
483                 goto flush_and_out;
484         }
485
486         case PTRACE_WRITETEXT:
487         case PTRACE_WRITEDATA: {
488                 int res = ptrace_writedata(child, (void *) addr2,
489                                            addr, 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         case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
500                 addr = 1;
501
502         case PTRACE_CONT: { /* restart after signal. */
503                 if (data > _NSIG) {
504                         pt_error_return(regs, EIO);
505                         goto out_tsk;
506                 }
507                 if (addr != 1) {
508                         unsigned long pc_mask = ~0UL;
509
510                         if ((child->thread_info->flags & _TIF_32BIT) != 0)
511                                 pc_mask = 0xffffffff;
512
513                         if (addr & 3) {
514                                 pt_error_return(regs, EINVAL);
515                                 goto out_tsk;
516                         }
517 #ifdef DEBUG_PTRACE
518                         printk ("Original: %016lx %016lx\n",
519                                 child->thread_info->kregs->tpc,
520                                 child->thread_info->kregs->tnpc);
521                         printk ("Continuing with %016lx %016lx\n", addr, addr+4);
522 #endif
523                         child->thread_info->kregs->tpc = (addr & pc_mask);
524                         child->thread_info->kregs->tnpc = ((addr + 4) & pc_mask);
525                 }
526
527                 if (request == PTRACE_SYSCALL) {
528                         set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
529                 } else {
530                         clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
531                 }
532
533                 child->exit_code = data;
534 #ifdef DEBUG_PTRACE
535                 printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n", child->comm,
536                         child->pid, child->exit_code,
537                         child->thread_info->kregs->tpc,
538                         child->thread_info->kregs->tnpc);
539                        
540 #endif
541                 wake_up_process(child);
542                 pt_succ_return(regs, 0);
543                 goto out_tsk;
544         }
545
546 /*
547  * make the child exit.  Best I can do is send it a sigkill. 
548  * perhaps it should be put in the status that it wants to 
549  * exit.
550  */
551         case PTRACE_KILL: {
552                 if (child->state == TASK_ZOMBIE) {      /* already dead */
553                         pt_succ_return(regs, 0);
554                         goto out_tsk;
555                 }
556                 child->exit_code = SIGKILL;
557                 wake_up_process(child);
558                 pt_succ_return(regs, 0);
559                 goto out_tsk;
560         }
561
562         case PTRACE_SUNDETACH: { /* detach a process that was attached. */
563                 int error = ptrace_detach(child, data);
564                 if (error) {
565                         pt_error_return(regs, EIO);
566                         goto out_tsk;
567                 }
568                 pt_succ_return(regs, 0);
569                 goto out_tsk;
570         }
571
572         /* PTRACE_DUMPCORE unsupported... */
573
574         default: {
575                 int err = ptrace_request(child, request, addr, data);
576                 if (err)
577                         pt_error_return(regs, -err);
578                 else
579                         pt_succ_return(regs, 0);
580                 goto out_tsk;
581         }
582         }
583 flush_and_out:
584         {
585                 unsigned long va;
586
587                 if (tlb_type == cheetah || tlb_type == cheetah_plus) {
588                         for (va = 0; va < (1 << 16); va += (1 << 5))
589                                 spitfire_put_dcache_tag(va, 0x0);
590                         /* No need to mess with I-cache on Cheetah. */
591                 } else {
592                         for (va =  0; va < L1DCACHE_SIZE; va += 32)
593                                 spitfire_put_dcache_tag(va, 0x0);
594                         if (request == PTRACE_PEEKTEXT ||
595                             request == PTRACE_POKETEXT ||
596                             request == PTRACE_READTEXT ||
597                             request == PTRACE_WRITETEXT) {
598                                 for (va =  0; va < (PAGE_SIZE << 1); va += 32)
599                                         spitfire_put_icache_tag(va, 0x0);
600                                 __asm__ __volatile__("flush %g6");
601                         }
602                 }
603         }
604 out_tsk:
605         if (child)
606                 put_task_struct(child);
607 out:
608         unlock_kernel();
609 }
610
611 asmlinkage void syscall_trace(void)
612 {
613 #ifdef DEBUG_PTRACE
614         printk("%s [%d]: syscall_trace\n", current->comm, current->pid);
615 #endif
616         if (!test_thread_flag(TIF_SYSCALL_TRACE))
617                 return;
618         if (!(current->ptrace & PT_PTRACED))
619                 return;
620         current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
621                                         ? 0x80 : 0);
622         current->state = TASK_STOPPED;
623         notify_parent(current, SIGCHLD);
624         schedule();
625
626         /*
627          * this isn't the same as continuing with a signal, but it will do
628          * for normal use.  strace only continues with a signal if the
629          * stopping signal is not SIGTRAP.  -brl
630          */
631 #ifdef DEBUG_PTRACE
632         printk("%s [%d]: syscall_trace exit= %x\n", current->comm,
633                 current->pid, current->exit_code);
634 #endif
635         if (current->exit_code) {
636                 send_sig (current->exit_code, current, 1);
637                 current->exit_code = 0;
638         }
639 }