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