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