[PATCH] use ptrace_get_task_struct in various places
[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 = tsk->thread_info;
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 = tsk->thread_info;
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
303         if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH)
304             || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) {
305                 if (ptrace_attach(child)) {
306                         pt_error_return(regs, EPERM);
307                         goto out_tsk;
308                 }
309                 pt_succ_return(regs, 0);
310                 goto out_tsk;
311         }
312
313         ret = ptrace_check_attach(child, request == PTRACE_KILL);
314         if (ret < 0) {
315                 pt_error_return(regs, -ret);
316                 goto out_tsk;
317         }
318
319         switch(request) {
320         case PTRACE_PEEKTEXT: /* read word at location addr. */ 
321         case PTRACE_PEEKDATA: {
322                 unsigned long tmp;
323
324                 if (access_process_vm(child, addr,
325                                       &tmp, sizeof(tmp), 0) == sizeof(tmp))
326                         pt_os_succ_return(regs, tmp, (long __user *)data);
327                 else
328                         pt_error_return(regs, EIO);
329                 goto out_tsk;
330         }
331
332         case PTRACE_PEEKUSR:
333                 read_sunos_user(regs, addr, child, (long __user *) data);
334                 goto out_tsk;
335
336         case PTRACE_POKEUSR:
337                 write_sunos_user(regs, addr, child);
338                 goto out_tsk;
339
340         case PTRACE_POKETEXT: /* write the word at location addr. */
341         case PTRACE_POKEDATA: {
342                 if (access_process_vm(child, addr,
343                                       &data, sizeof(data), 1) == sizeof(data))
344                         pt_succ_return(regs, 0);
345                 else
346                         pt_error_return(regs, EIO);
347                 goto out_tsk;
348         }
349
350         case PTRACE_GETREGS: {
351                 struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
352                 struct pt_regs *cregs = child->thread.kregs;
353                 int rval;
354
355                 if (!access_ok(VERIFY_WRITE, pregs, sizeof(struct pt_regs))) {
356                         rval = -EFAULT;
357                         pt_error_return(regs, -rval);
358                         goto out_tsk;
359                 }
360                 __put_user(cregs->psr, (&pregs->psr));
361                 __put_user(cregs->pc, (&pregs->pc));
362                 __put_user(cregs->npc, (&pregs->npc));
363                 __put_user(cregs->y, (&pregs->y));
364                 for(rval = 1; rval < 16; rval++)
365                         __put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]));
366                 pt_succ_return(regs, 0);
367 #ifdef DEBUG_PTRACE
368                 printk ("PC=%x nPC=%x o7=%x\n", cregs->pc, cregs->npc, cregs->u_regs [15]);
369 #endif
370                 goto out_tsk;
371         }
372
373         case PTRACE_SETREGS: {
374                 struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
375                 struct pt_regs *cregs = child->thread.kregs;
376                 unsigned long psr, pc, npc, y;
377                 int i;
378
379                 /* Must be careful, tracing process can only set certain
380                  * bits in the psr.
381                  */
382                 if (!access_ok(VERIFY_READ, pregs, sizeof(struct pt_regs))) {
383                         pt_error_return(regs, EFAULT);
384                         goto out_tsk;
385                 }
386                 __get_user(psr, (&pregs->psr));
387                 __get_user(pc, (&pregs->pc));
388                 __get_user(npc, (&pregs->npc));
389                 __get_user(y, (&pregs->y));
390                 psr &= PSR_ICC;
391                 cregs->psr &= ~PSR_ICC;
392                 cregs->psr |= psr;
393                 if (!((pc | npc) & 3)) {
394                         cregs->pc = pc;
395                         cregs->npc =npc;
396                 }
397                 cregs->y = y;
398                 for(i = 1; i < 16; i++)
399                         __get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]));
400                 pt_succ_return(regs, 0);
401                 goto out_tsk;
402         }
403
404         case PTRACE_GETFPREGS: {
405                 struct fps {
406                         unsigned long regs[32];
407                         unsigned long fsr;
408                         unsigned long flags;
409                         unsigned long extra;
410                         unsigned long fpqd;
411                         struct fq {
412                                 unsigned long *insnaddr;
413                                 unsigned long insn;
414                         } fpq[16];
415                 };
416                 struct fps __user *fps = (struct fps __user *) addr;
417                 int i;
418
419                 if (!access_ok(VERIFY_WRITE, fps, sizeof(struct fps))) {
420                         i = -EFAULT;
421                         pt_error_return(regs, -i);
422                         goto out_tsk;
423                 }
424                 for(i = 0; i < 32; i++)
425                         __put_user(child->thread.float_regs[i], (&fps->regs[i]));
426                 __put_user(child->thread.fsr, (&fps->fsr));
427                 __put_user(child->thread.fpqdepth, (&fps->fpqd));
428                 __put_user(0, (&fps->flags));
429                 __put_user(0, (&fps->extra));
430                 for(i = 0; i < 16; i++) {
431                         __put_user(child->thread.fpqueue[i].insn_addr,
432                                    (&fps->fpq[i].insnaddr));
433                         __put_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn));
434                 }
435                 pt_succ_return(regs, 0);
436                 goto out_tsk;
437         }
438
439         case PTRACE_SETFPREGS: {
440                 struct fps {
441                         unsigned long regs[32];
442                         unsigned long fsr;
443                         unsigned long flags;
444                         unsigned long extra;
445                         unsigned long fpqd;
446                         struct fq {
447                                 unsigned long *insnaddr;
448                                 unsigned long insn;
449                         } fpq[16];
450                 };
451                 struct fps __user *fps = (struct fps __user *) addr;
452                 int i;
453
454                 if (!access_ok(VERIFY_READ, fps, sizeof(struct fps))) {
455                         i = -EFAULT;
456                         pt_error_return(regs, -i);
457                         goto out_tsk;
458                 }
459                 copy_from_user(&child->thread.float_regs[0], &fps->regs[0], (32 * sizeof(unsigned long)));
460                 __get_user(child->thread.fsr, (&fps->fsr));
461                 __get_user(child->thread.fpqdepth, (&fps->fpqd));
462                 for(i = 0; i < 16; i++) {
463                         __get_user(child->thread.fpqueue[i].insn_addr,
464                                    (&fps->fpq[i].insnaddr));
465                         __get_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn));
466                 }
467                 pt_succ_return(regs, 0);
468                 goto out_tsk;
469         }
470
471         case PTRACE_READTEXT:
472         case PTRACE_READDATA: {
473                 int res = ptrace_readdata(child, addr,
474                                           (void __user *) addr2, data);
475
476                 if (res == data) {
477                         pt_succ_return(regs, 0);
478                         goto out_tsk;
479                 }
480                 /* Partial read is an IO failure */
481                 if (res >= 0)
482                         res = -EIO;
483                 pt_error_return(regs, -res);
484                 goto out_tsk;
485         }
486
487         case PTRACE_WRITETEXT:
488         case PTRACE_WRITEDATA: {
489                 int res = ptrace_writedata(child, (void __user *) addr2,
490                                            addr, data);
491
492                 if (res == data) {
493                         pt_succ_return(regs, 0);
494                         goto out_tsk;
495                 }
496                 /* Partial write is an IO failure */
497                 if (res >= 0)
498                         res = -EIO;
499                 pt_error_return(regs, -res);
500                 goto out_tsk;
501         }
502
503         case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
504                 addr = 1;
505
506         case PTRACE_CONT: { /* restart after signal. */
507                 if (!valid_signal(data)) {
508                         pt_error_return(regs, EIO);
509                         goto out_tsk;
510                 }
511
512                 if (request == PTRACE_SYSCALL)
513                         set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
514                 else
515                         clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
516
517                 child->exit_code = data;
518 #ifdef DEBUG_PTRACE
519                 printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n",
520                         child->comm, child->pid, child->exit_code,
521                         child->thread.kregs->pc,
522                         child->thread.kregs->npc);
523 #endif
524                 wake_up_process(child);
525                 pt_succ_return(regs, 0);
526                 goto out_tsk;
527         }
528
529 /*
530  * make the child exit.  Best I can do is send it a sigkill. 
531  * perhaps it should be put in the status that it wants to 
532  * exit.
533  */
534         case PTRACE_KILL: {
535                 if (child->exit_state == EXIT_ZOMBIE) { /* already dead */
536                         pt_succ_return(regs, 0);
537                         goto out_tsk;
538                 }
539                 wake_up_process(child);
540                 child->exit_code = SIGKILL;
541                 pt_succ_return(regs, 0);
542                 goto out_tsk;
543         }
544
545         case PTRACE_SUNDETACH: { /* detach a process that was attached. */
546                 int err = ptrace_detach(child, data);
547                 if (err) {
548                         pt_error_return(regs, EIO);
549                         goto out_tsk;
550                 }
551                 pt_succ_return(regs, 0);
552                 goto out_tsk;
553         }
554
555         /* PTRACE_DUMPCORE unsupported... */
556
557         default: {
558                 int err = ptrace_request(child, request, addr, data);
559                 if (err)
560                         pt_error_return(regs, -err);
561                 else
562                         pt_succ_return(regs, 0);
563                 goto out_tsk;
564         }
565         }
566 out_tsk:
567         if (child)
568                 put_task_struct(child);
569 out:
570         unlock_kernel();
571 }
572
573 asmlinkage void syscall_trace(void)
574 {
575 #ifdef DEBUG_PTRACE
576         printk("%s [%d]: syscall_trace\n", current->comm, current->pid);
577 #endif
578         if (!test_thread_flag(TIF_SYSCALL_TRACE))
579                 return;
580         if (!(current->ptrace & PT_PTRACED))
581                 return;
582         current->thread.flags ^= MAGIC_CONSTANT;
583         ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
584                                  ? 0x80 : 0));
585         /*
586          * this isn't the same as continuing with a signal, but it will do
587          * for normal use.  strace only continues with a signal if the
588          * stopping signal is not SIGTRAP.  -brl
589          */
590 #ifdef DEBUG_PTRACE
591         printk("%s [%d]: syscall_trace exit= %x\n", current->comm,
592                 current->pid, current->exit_code);
593 #endif
594         if (current->exit_code) {
595                 send_sig (current->exit_code, current, 1);
596                 current->exit_code = 0;
597         }
598 }