fedora core 6 1.2949 + vserver 2.2.0
[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 #include <linux/vs_base.h>
23
24 #include <asm/pgtable.h>
25 #include <asm/system.h>
26 #include <asm/uaccess.h>
27
28 #define MAGIC_CONSTANT 0x80000000
29
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->psr |= PSR_C;
40         regs->pc = regs->npc;
41         regs->npc += 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->psr &= ~PSR_C;
48         regs->pc = regs->npc;
49         regs->npc += 4;
50 }
51
52 static void
53 pt_succ_return_linux(struct pt_regs *regs, unsigned long value, long __user *addr)
54 {
55         if (put_user(value, addr)) {
56                 pt_error_return(regs, EFAULT);
57                 return;
58         }
59         regs->u_regs[UREG_I0] = 0;
60         regs->psr &= ~PSR_C;
61         regs->pc = regs->npc;
62         regs->npc += 4;
63 }
64
65 static void
66 pt_os_succ_return (struct pt_regs *regs, unsigned long val, long __user *addr)
67 {
68         if (current->personality == PER_SUNOS)
69                 pt_succ_return (regs, val);
70         else
71                 pt_succ_return_linux (regs, val, addr);
72 }
73
74 /* Fuck me gently with a chainsaw... */
75 static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset,
76                                    struct task_struct *tsk, long __user *addr)
77 {
78         struct pt_regs *cregs = tsk->thread.kregs;
79         struct thread_info *t = task_thread_info(tsk);
80         int v;
81         
82         if(offset >= 1024)
83                 offset -= 1024; /* whee... */
84         if(offset & ((sizeof(unsigned long) - 1))) {
85                 pt_error_return(regs, EIO);
86                 return;
87         }
88         if(offset >= 16 && offset < 784) {
89                 offset -= 16; offset >>= 2;
90                 pt_os_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset), addr);
91                 return;
92         }
93         if(offset >= 784 && offset < 832) {
94                 offset -= 784; offset >>= 2;
95                 pt_os_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset), addr);
96                 return;
97         }
98         switch(offset) {
99         case 0:
100                 v = t->ksp;
101                 break;
102         case 4:
103                 v = t->kpc;
104                 break;
105         case 8:
106                 v = t->kpsr;
107                 break;
108         case 12:
109                 v = t->uwinmask;
110                 break;
111         case 832:
112                 v = t->w_saved;
113                 break;
114         case 896:
115                 v = cregs->u_regs[UREG_I0];
116                 break;
117         case 900:
118                 v = cregs->u_regs[UREG_I1];
119                 break;
120         case 904:
121                 v = cregs->u_regs[UREG_I2];
122                 break;
123         case 908:
124                 v = cregs->u_regs[UREG_I3];
125                 break;
126         case 912:
127                 v = cregs->u_regs[UREG_I4];
128                 break;
129         case 916:
130                 v = cregs->u_regs[UREG_I5];
131                 break;
132         case 920:
133                 v = cregs->u_regs[UREG_I6];
134                 break;
135         case 924:
136                 if(tsk->thread.flags & MAGIC_CONSTANT)
137                         v = cregs->u_regs[UREG_G1];
138                 else
139                         v = 0;
140                 break;
141         case 940:
142                 v = cregs->u_regs[UREG_I0];
143                 break;
144         case 944:
145                 v = cregs->u_regs[UREG_I1];
146                 break;
147
148         case 948:
149                 /* Isn't binary compatibility _fun_??? */
150                 if(cregs->psr & PSR_C)
151                         v = cregs->u_regs[UREG_I0] << 24;
152                 else
153                         v = 0;
154                 break;
155
156                 /* Rest of them are completely unsupported. */
157         default:
158                 printk("%s [%d]: Wants to read user offset %ld\n",
159                        current->comm, current->pid, offset);
160                 pt_error_return(regs, EIO);
161                 return;
162         }
163         if (current->personality == PER_SUNOS)
164                 pt_succ_return (regs, v);
165         else
166                 pt_succ_return_linux (regs, v, addr);
167         return;
168 }
169
170 static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset,
171                                     struct task_struct *tsk)
172 {
173         struct pt_regs *cregs = tsk->thread.kregs;
174         struct thread_info *t = task_thread_info(tsk);
175         unsigned long value = regs->u_regs[UREG_I3];
176
177         if(offset >= 1024)
178                 offset -= 1024; /* whee... */
179         if(offset & ((sizeof(unsigned long) - 1)))
180                 goto failure;
181         if(offset >= 16 && offset < 784) {
182                 offset -= 16; offset >>= 2;
183                 *(((unsigned long *)(&t->reg_window[0]))+offset) = value;
184                 goto success;
185         }
186         if(offset >= 784 && offset < 832) {
187                 offset -= 784; offset >>= 2;
188                 *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value;
189                 goto success;
190         }
191         switch(offset) {
192         case 896:
193                 cregs->u_regs[UREG_I0] = value;
194                 break;
195         case 900:
196                 cregs->u_regs[UREG_I1] = value;
197                 break;
198         case 904:
199                 cregs->u_regs[UREG_I2] = value;
200                 break;
201         case 908:
202                 cregs->u_regs[UREG_I3] = value;
203                 break;
204         case 912:
205                 cregs->u_regs[UREG_I4] = value;
206                 break;
207         case 916:
208                 cregs->u_regs[UREG_I5] = value;
209                 break;
210         case 920:
211                 cregs->u_regs[UREG_I6] = value;
212                 break;
213         case 924:
214                 cregs->u_regs[UREG_I7] = value;
215                 break;
216         case 940:
217                 cregs->u_regs[UREG_I0] = value;
218                 break;
219         case 944:
220                 cregs->u_regs[UREG_I1] = value;
221                 break;
222
223                 /* Rest of them are completely unsupported or "no-touch". */
224         default:
225                 printk("%s [%d]: Wants to write user offset %ld\n",
226                        current->comm, current->pid, offset);
227                 goto failure;
228         }
229 success:
230         pt_succ_return(regs, 0);
231         return;
232 failure:
233         pt_error_return(regs, EIO);
234         return;
235 }
236
237 /* #define ALLOW_INIT_TRACING */
238 /* #define DEBUG_PTRACE */
239
240 #ifdef DEBUG_PTRACE
241 char *pt_rq [] = {
242         /* 0  */ "TRACEME", "PEEKTEXT", "PEEKDATA", "PEEKUSR",
243         /* 4  */ "POKETEXT", "POKEDATA", "POKEUSR", "CONT",
244         /* 8  */ "KILL", "SINGLESTEP", "SUNATTACH", "SUNDETACH",
245         /* 12 */ "GETREGS", "SETREGS", "GETFPREGS", "SETFPREGS",
246         /* 16 */ "READDATA", "WRITEDATA", "READTEXT", "WRITETEXT",
247         /* 20 */ "GETFPAREGS", "SETFPAREGS", "unknown", "unknown",
248         /* 24 */ "SYSCALL", ""
249 };
250 #endif
251
252 /*
253  * Called by kernel/ptrace.c when detaching..
254  *
255  * Make sure single step bits etc are not set.
256  */
257 void ptrace_disable(struct task_struct *child)
258 {
259         /* nothing to do */
260 }
261
262 asmlinkage void do_ptrace(struct pt_regs *regs)
263 {
264         unsigned long request = regs->u_regs[UREG_I0];
265         unsigned long pid = regs->u_regs[UREG_I1];
266         unsigned long addr = regs->u_regs[UREG_I2];
267         unsigned long data = regs->u_regs[UREG_I3];
268         unsigned long addr2 = regs->u_regs[UREG_I4];
269         struct task_struct *child;
270         int ret;
271
272         lock_kernel();
273 #ifdef DEBUG_PTRACE
274         {
275                 char *s;
276
277                 if ((request >= 0) && (request <= 24))
278                         s = pt_rq [request];
279                 else
280                         s = "unknown";
281
282                 if (request == PTRACE_POKEDATA && data == 0x91d02001){
283                         printk ("do_ptrace: breakpoint pid=%d, addr=%08lx addr2=%08lx\n",
284                                 pid, addr, addr2);
285                 } else 
286                         printk("do_ptrace: rq=%s(%d) pid=%d addr=%08lx data=%08lx addr2=%08lx\n",
287                                s, (int) request, (int) pid, addr, data, addr2);
288         }
289 #endif
290
291         if (request == PTRACE_TRACEME) {
292                 ret = ptrace_traceme();
293                 if (ret < 0)
294                         pt_error_return(regs, -ret);
295                 else
296                         pt_succ_return(regs, 0);
297                 goto out;
298         }
299
300         child = ptrace_get_task_struct(pid);
301         if (IS_ERR(child)) {
302                 ret = PTR_ERR(child);
303                 pt_error_return(regs, -ret);
304                 goto out;
305         }
306         if (!vx_check(vx_task_xid(child), VS_WATCH_P|VS_IDENT)) {
307                 pt_error_return(regs, ESRCH);
308                 goto out_tsk;
309         }
310
311         if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH)
312             || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) {
313                 if (ptrace_attach(child)) {
314                         pt_error_return(regs, EPERM);
315                         goto out_tsk;
316                 }
317                 pt_succ_return(regs, 0);
318                 goto out_tsk;
319         }
320
321         ret = ptrace_check_attach(child, request == PTRACE_KILL);
322         if (ret < 0) {
323                 pt_error_return(regs, -ret);
324                 goto out_tsk;
325         }
326
327         switch(request) {
328         case PTRACE_PEEKTEXT: /* read word at location addr. */ 
329         case PTRACE_PEEKDATA: {
330                 unsigned long tmp;
331
332                 if (access_process_vm(child, addr,
333                                       &tmp, sizeof(tmp), 0) == sizeof(tmp))
334                         pt_os_succ_return(regs, tmp, (long __user *)data);
335                 else
336                         pt_error_return(regs, EIO);
337                 goto out_tsk;
338         }
339
340         case PTRACE_PEEKUSR:
341                 read_sunos_user(regs, addr, child, (long __user *) data);
342                 goto out_tsk;
343
344         case PTRACE_POKEUSR:
345                 write_sunos_user(regs, addr, child);
346                 goto out_tsk;
347
348         case PTRACE_POKETEXT: /* write the word at location addr. */
349         case PTRACE_POKEDATA: {
350                 if (access_process_vm(child, addr,
351                                       &data, sizeof(data), 1) == sizeof(data))
352                         pt_succ_return(regs, 0);
353                 else
354                         pt_error_return(regs, EIO);
355                 goto out_tsk;
356         }
357
358         case PTRACE_GETREGS: {
359                 struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
360                 struct pt_regs *cregs = child->thread.kregs;
361                 int rval;
362
363                 if (!access_ok(VERIFY_WRITE, pregs, sizeof(struct pt_regs))) {
364                         rval = -EFAULT;
365                         pt_error_return(regs, -rval);
366                         goto out_tsk;
367                 }
368                 __put_user(cregs->psr, (&pregs->psr));
369                 __put_user(cregs->pc, (&pregs->pc));
370                 __put_user(cregs->npc, (&pregs->npc));
371                 __put_user(cregs->y, (&pregs->y));
372                 for(rval = 1; rval < 16; rval++)
373                         __put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]));
374                 pt_succ_return(regs, 0);
375 #ifdef DEBUG_PTRACE
376                 printk ("PC=%x nPC=%x o7=%x\n", cregs->pc, cregs->npc, cregs->u_regs [15]);
377 #endif
378                 goto out_tsk;
379         }
380
381         case PTRACE_SETREGS: {
382                 struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
383                 struct pt_regs *cregs = child->thread.kregs;
384                 unsigned long psr, pc, npc, y;
385                 int i;
386
387                 /* Must be careful, tracing process can only set certain
388                  * bits in the psr.
389                  */
390                 if (!access_ok(VERIFY_READ, pregs, sizeof(struct pt_regs))) {
391                         pt_error_return(regs, EFAULT);
392                         goto out_tsk;
393                 }
394                 __get_user(psr, (&pregs->psr));
395                 __get_user(pc, (&pregs->pc));
396                 __get_user(npc, (&pregs->npc));
397                 __get_user(y, (&pregs->y));
398                 psr &= PSR_ICC;
399                 cregs->psr &= ~PSR_ICC;
400                 cregs->psr |= psr;
401                 if (!((pc | npc) & 3)) {
402                         cregs->pc = pc;
403                         cregs->npc =npc;
404                 }
405                 cregs->y = y;
406                 for(i = 1; i < 16; i++)
407                         __get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]));
408                 pt_succ_return(regs, 0);
409                 goto out_tsk;
410         }
411
412         case PTRACE_GETFPREGS: {
413                 struct fps {
414                         unsigned long regs[32];
415                         unsigned long fsr;
416                         unsigned long flags;
417                         unsigned long extra;
418                         unsigned long fpqd;
419                         struct fq {
420                                 unsigned long *insnaddr;
421                                 unsigned long insn;
422                         } fpq[16];
423                 };
424                 struct fps __user *fps = (struct fps __user *) addr;
425                 int i;
426
427                 if (!access_ok(VERIFY_WRITE, fps, sizeof(struct fps))) {
428                         i = -EFAULT;
429                         pt_error_return(regs, -i);
430                         goto out_tsk;
431                 }
432                 for(i = 0; i < 32; i++)
433                         __put_user(child->thread.float_regs[i], (&fps->regs[i]));
434                 __put_user(child->thread.fsr, (&fps->fsr));
435                 __put_user(child->thread.fpqdepth, (&fps->fpqd));
436                 __put_user(0, (&fps->flags));
437                 __put_user(0, (&fps->extra));
438                 for(i = 0; i < 16; i++) {
439                         __put_user(child->thread.fpqueue[i].insn_addr,
440                                    (&fps->fpq[i].insnaddr));
441                         __put_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn));
442                 }
443                 pt_succ_return(regs, 0);
444                 goto out_tsk;
445         }
446
447         case PTRACE_SETFPREGS: {
448                 struct fps {
449                         unsigned long regs[32];
450                         unsigned long fsr;
451                         unsigned long flags;
452                         unsigned long extra;
453                         unsigned long fpqd;
454                         struct fq {
455                                 unsigned long *insnaddr;
456                                 unsigned long insn;
457                         } fpq[16];
458                 };
459                 struct fps __user *fps = (struct fps __user *) addr;
460                 int i;
461
462                 if (!access_ok(VERIFY_READ, fps, sizeof(struct fps))) {
463                         i = -EFAULT;
464                         pt_error_return(regs, -i);
465                         goto out_tsk;
466                 }
467                 copy_from_user(&child->thread.float_regs[0], &fps->regs[0], (32 * sizeof(unsigned long)));
468                 __get_user(child->thread.fsr, (&fps->fsr));
469                 __get_user(child->thread.fpqdepth, (&fps->fpqd));
470                 for(i = 0; i < 16; i++) {
471                         __get_user(child->thread.fpqueue[i].insn_addr,
472                                    (&fps->fpq[i].insnaddr));
473                         __get_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn));
474                 }
475                 pt_succ_return(regs, 0);
476                 goto out_tsk;
477         }
478
479         case PTRACE_READTEXT:
480         case PTRACE_READDATA: {
481                 int res = ptrace_readdata(child, addr,
482                                           (void __user *) addr2, data);
483
484                 if (res == data) {
485                         pt_succ_return(regs, 0);
486                         goto out_tsk;
487                 }
488                 /* Partial read is an IO failure */
489                 if (res >= 0)
490                         res = -EIO;
491                 pt_error_return(regs, -res);
492                 goto out_tsk;
493         }
494
495         case PTRACE_WRITETEXT:
496         case PTRACE_WRITEDATA: {
497                 int res = ptrace_writedata(child, (void __user *) addr2,
498                                            addr, data);
499
500                 if (res == data) {
501                         pt_succ_return(regs, 0);
502                         goto out_tsk;
503                 }
504                 /* Partial write is an IO failure */
505                 if (res >= 0)
506                         res = -EIO;
507                 pt_error_return(regs, -res);
508                 goto out_tsk;
509         }
510
511         case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
512                 addr = 1;
513
514         case PTRACE_CONT: { /* restart after signal. */
515                 if (!valid_signal(data)) {
516                         pt_error_return(regs, EIO);
517                         goto out_tsk;
518                 }
519
520                 if (request == PTRACE_SYSCALL)
521                         set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
522                 else
523                         clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
524
525                 child->exit_code = data;
526 #ifdef DEBUG_PTRACE
527                 printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n",
528                         child->comm, child->pid, child->exit_code,
529                         child->thread.kregs->pc,
530                         child->thread.kregs->npc);
531 #endif
532                 wake_up_process(child);
533                 pt_succ_return(regs, 0);
534                 goto out_tsk;
535         }
536
537 /*
538  * make the child exit.  Best I can do is send it a sigkill. 
539  * perhaps it should be put in the status that it wants to 
540  * exit.
541  */
542         case PTRACE_KILL: {
543                 if (child->exit_state == EXIT_ZOMBIE) { /* already dead */
544                         pt_succ_return(regs, 0);
545                         goto out_tsk;
546                 }
547                 wake_up_process(child);
548                 child->exit_code = SIGKILL;
549                 pt_succ_return(regs, 0);
550                 goto out_tsk;
551         }
552
553         case PTRACE_SUNDETACH: { /* detach a process that was attached. */
554                 int err = ptrace_detach(child, data);
555                 if (err) {
556                         pt_error_return(regs, EIO);
557                         goto out_tsk;
558                 }
559                 pt_succ_return(regs, 0);
560                 goto out_tsk;
561         }
562
563         /* PTRACE_DUMPCORE unsupported... */
564
565         default: {
566                 int err = ptrace_request(child, request, addr, data);
567                 if (err)
568                         pt_error_return(regs, -err);
569                 else
570                         pt_succ_return(regs, 0);
571                 goto out_tsk;
572         }
573         }
574 out_tsk:
575         if (child)
576                 put_task_struct(child);
577 out:
578         unlock_kernel();
579 }
580
581 asmlinkage void syscall_trace(void)
582 {
583 #ifdef DEBUG_PTRACE
584         printk("%s [%d]: syscall_trace\n", current->comm, current->pid);
585 #endif
586         if (!test_thread_flag(TIF_SYSCALL_TRACE))
587                 return;
588         if (!(current->ptrace & PT_PTRACED))
589                 return;
590         current->thread.flags ^= MAGIC_CONSTANT;
591         ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
592                                  ? 0x80 : 0));
593         /*
594          * this isn't the same as continuing with a signal, but it will do
595          * for normal use.  strace only continues with a signal if the
596          * stopping signal is not SIGTRAP.  -brl
597          */
598 #ifdef DEBUG_PTRACE
599         printk("%s [%d]: syscall_trace exit= %x\n", current->comm,
600                 current->pid, current->exit_code);
601 #endif
602         if (current->exit_code) {
603                 send_sig (current->exit_code, current, 1);
604                 current->exit_code = 0;
605         }
606 }