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