patch-2.6.6-vs1.9.0
[linux-2.6.git] / arch / parisc / kernel / ptrace.c
1 /*
2  * Kernel support for the ptrace() and syscall tracing interfaces.
3  *
4  * Copyright (C) 2000 Hewlett-Packard Co, Linuxcare Inc.
5  * Copyright (C) 2000 Matthew Wilcox <matthew@wil.cx>
6  * Copyright (C) 2000 David Huggins-Daines <dhd@debian.org>
7  */
8
9 #include <linux/kernel.h>
10 #include <linux/sched.h>
11 #include <linux/mm.h>
12 #include <linux/smp.h>
13 #include <linux/smp_lock.h>
14 #include <linux/errno.h>
15 #include <linux/ptrace.h>
16 #include <linux/user.h>
17 #include <linux/personality.h>
18 #include <linux/security.h>
19 #include <linux/compat.h>
20
21 #include <asm/uaccess.h>
22 #include <asm/pgtable.h>
23 #include <asm/system.h>
24 #include <asm/processor.h>
25 #include <asm/offsets.h>
26
27 /* PSW bits we allow the debugger to modify */
28 #define USER_PSW_BITS   (PSW_N | PSW_V | PSW_CB)
29
30 #undef DEBUG_PTRACE
31
32 #ifdef DEBUG_PTRACE
33 #define DBG(x)  printk x
34 #else
35 #define DBG(x)
36 #endif
37
38 #ifdef __LP64__
39
40 /* This function is needed to translate 32 bit pt_regs offsets in to
41  * 64 bit pt_regs offsets.  For example, a 32 bit gdb under a 64 bit kernel
42  * will request offset 12 if it wants gr3, but the lower 32 bits of
43  * the 64 bit kernels view of gr3 will be at offset 28 (3*8 + 4).
44  * This code relies on a 32 bit pt_regs being comprised of 32 bit values
45  * except for the fp registers which (a) are 64 bits, and (b) follow
46  * the gr registers at the start of pt_regs.  The 32 bit pt_regs should
47  * be half the size of the 64 bit pt_regs, plus 32*4 to allow for fr[]
48  * being 64 bit in both cases.
49  */
50
51 static long translate_usr_offset(long offset)
52 {
53         if (offset < 0)
54                 return -1;
55         else if (offset <= 32*4)        /* gr[0..31] */
56                 return offset * 2 + 4;
57         else if (offset <= 32*4+32*8)   /* gr[0..31] + fr[0..31] */
58                 return offset + 32*4;
59         else if (offset < sizeof(struct pt_regs)/2 + 32*4)
60                 return offset * 2 + 4 - 32*8;
61         else
62                 return -1;
63 }
64 #endif
65
66 /*
67  * Called by kernel/ptrace.c when detaching..
68  *
69  * Make sure single step bits etc are not set.
70  */
71 void ptrace_disable(struct task_struct *child)
72 {
73         /* make sure the trap bits are not set */
74         pa_psw(child)->r = 0;
75         pa_psw(child)->t = 0;
76         pa_psw(child)->h = 0;
77         pa_psw(child)->l = 0;
78 }
79
80 long sys_ptrace(long request, pid_t pid, long addr, long data)
81 {
82         struct task_struct *child;
83         long ret;
84 #ifdef DEBUG_PTRACE
85         long oaddr=addr, odata=data;
86 #endif
87
88         lock_kernel();
89         ret = -EPERM;
90         if (request == PTRACE_TRACEME) {
91                 /* are we already being traced? */
92                 if (current->ptrace & PT_PTRACED)
93                         goto out;
94
95                 ret = security_ptrace(current->parent, current);
96                 if (ret) 
97                         goto out;
98
99                 /* set the ptrace bit in the process flags. */
100                 current->ptrace |= PT_PTRACED;
101                 ret = 0;
102                 goto out;
103         }
104
105         ret = -ESRCH;
106         read_lock(&tasklist_lock);
107         child = find_task_by_pid(pid);
108         if (child)
109                 get_task_struct(child);
110         read_unlock(&tasklist_lock);
111         if (!child)
112                 goto out;
113         if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT))
114                 goto out_tsk;
115
116         ret = -EPERM;
117         if (pid == 1)           /* no messing around with init! */
118                 goto out_tsk;
119
120         if (request == PTRACE_ATTACH) {
121                 ret = ptrace_attach(child);
122                 goto out_tsk;
123         }
124
125         ret = ptrace_check_attach(child, request == PTRACE_KILL);
126         if (ret < 0)
127                 goto out_tsk;
128
129         switch (request) {
130         case PTRACE_PEEKTEXT: /* read word at location addr. */ 
131         case PTRACE_PEEKDATA: {
132                 int copied;
133
134 #ifdef __LP64__
135                 if (is_compat_task(child)) {
136                         unsigned int tmp;
137
138                         addr &= 0xffffffffL;
139                         copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
140                         ret = -EIO;
141                         if (copied != sizeof(tmp))
142                                 goto out_tsk;
143                         ret = put_user(tmp,(unsigned int *) data);
144                         DBG(("sys_ptrace(PEEK%s, %d, %lx, %lx) returning %ld, data %x\n",
145                                 request == PTRACE_PEEKTEXT ? "TEXT" : "DATA",
146                                 pid, oaddr, odata, ret, tmp));
147                 }
148                 else
149 #endif
150                 {
151                         unsigned long tmp;
152
153                         copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
154                         ret = -EIO;
155                         if (copied != sizeof(tmp))
156                                 goto out_tsk;
157                         ret = put_user(tmp,(unsigned long *) data);
158                 }
159                 goto out_tsk;
160         }
161
162         /* when I and D space are separate, this will have to be fixed. */
163         case PTRACE_POKETEXT: /* write the word at location addr. */
164         case PTRACE_POKEDATA:
165                 ret = 0;
166 #ifdef __LP64__
167                 if (is_compat_task(child)) {
168                         unsigned int tmp = (unsigned int)data;
169                         DBG(("sys_ptrace(POKE%s, %d, %lx, %lx)\n",
170                                 request == PTRACE_POKETEXT ? "TEXT" : "DATA",
171                                 pid, oaddr, odata));
172                         addr &= 0xffffffffL;
173                         if (access_process_vm(child, addr, &tmp, sizeof(tmp), 1) == sizeof(tmp))
174                                 goto out_tsk;
175                 }
176                 else
177 #endif
178                 {
179                         if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
180                                 goto out_tsk;
181                 }
182                 ret = -EIO;
183                 goto out_tsk;
184
185         /* Read the word at location addr in the USER area.  For ptraced
186            processes, the kernel saves all regs on a syscall. */
187         case PTRACE_PEEKUSR: {
188                 ret = -EIO;
189 #ifdef __LP64__
190                 if (is_compat_task(child)) {
191                         unsigned int tmp;
192
193                         if (addr & (sizeof(int)-1))
194                                 goto out_tsk;
195                         if ((addr = translate_usr_offset(addr)) < 0)
196                                 goto out_tsk;
197
198                         tmp = *(unsigned int *) ((char *) task_regs(child) + addr);
199                         ret = put_user(tmp, (unsigned int *) data);
200                         DBG(("sys_ptrace(PEEKUSR, %d, %lx, %lx) returning %ld, addr %lx, data %x\n",
201                                 pid, oaddr, odata, ret, addr, tmp));
202                 }
203                 else
204 #endif
205                 {
206                         unsigned long tmp;
207
208                         if ((addr & (sizeof(long)-1)) || (unsigned long) addr >= sizeof(struct pt_regs))
209                                 goto out_tsk;
210                         tmp = *(unsigned long *) ((char *) task_regs(child) + addr);
211                         ret = put_user(tmp, (unsigned long *) data);
212                 }
213                 goto out_tsk;
214         }
215
216         /* Write the word at location addr in the USER area.  This will need
217            to change when the kernel no longer saves all regs on a syscall.
218            FIXME.  There is a problem at the moment in that r3-r18 are only
219            saved if the process is ptraced on syscall entry, and even then
220            those values are overwritten by actual register values on syscall
221            exit. */
222         case PTRACE_POKEUSR:
223                 ret = -EIO;
224                 /* Some register values written here may be ignored in
225                  * entry.S:syscall_restore_rfi; e.g. iaoq is written with
226                  * r31/r31+4, and not with the values in pt_regs.
227                  */
228                  /* PT_PSW=0, so this is valid for 32 bit processes under 64
229                  * bit kernels.
230                  */
231                 if (addr == PT_PSW) {
232                         /* PT_PSW=0, so this is valid for 32 bit processes
233                          * under 64 bit kernels.
234                          *
235                          * Allow writing to Nullify, Divide-step-correction,
236                          * and carry/borrow bits.
237                          * BEWARE, if you set N, and then single step, it won't
238                          * stop on the nullified instruction.
239                          */
240                         DBG(("sys_ptrace(POKEUSR, %d, %lx, %lx)\n",
241                                 pid, oaddr, odata));
242                         data &= USER_PSW_BITS;
243                         task_regs(child)->gr[0] &= ~USER_PSW_BITS;
244                         task_regs(child)->gr[0] |= data;
245                         ret = 0;
246                         goto out_tsk;
247                 }
248 #ifdef __LP64__
249                 if (is_compat_task(child)) {
250                         if (addr & (sizeof(int)-1))
251                                 goto out_tsk;
252                         if ((addr = translate_usr_offset(addr)) < 0)
253                                 goto out_tsk;
254                         DBG(("sys_ptrace(POKEUSR, %d, %lx, %lx) addr %lx\n",
255                                 pid, oaddr, odata, addr));
256                         if (addr >= PT_FR0 && addr <= PT_FR31) {
257                                 /* Special case, fp regs are 64 bits anyway */
258                                 *(unsigned int *) ((char *) task_regs(child) + addr) = data;
259                                 ret = 0;
260                         }
261                         else if ((addr >= PT_GR1+4 && addr <= PT_GR31+4) ||
262                                         addr == PT_IAOQ0+4 || addr == PT_IAOQ1+4 ||
263                                         addr == PT_SAR+4) {
264                                 /* Zero the top 32 bits */
265                                 *(unsigned int *) ((char *) task_regs(child) + addr - 4) = 0;
266                                 *(unsigned int *) ((char *) task_regs(child) + addr) = data;
267                                 ret = 0;
268                         }
269                         goto out_tsk;
270                 }
271                 else
272 #endif
273                 {
274                         if ((addr & (sizeof(long)-1)) || (unsigned long) addr >= sizeof(struct pt_regs))
275                                 goto out_tsk;
276                         if ((addr >= PT_GR1 && addr <= PT_GR31) ||
277                                         addr == PT_IAOQ0 || addr == PT_IAOQ1 ||
278                                         (addr >= PT_FR0 && addr <= PT_FR31) ||
279                                         addr == PT_SAR) {
280                                 *(unsigned long *) ((char *) task_regs(child) + addr) = data;
281                                 ret = 0;
282                         }
283                         goto out_tsk;
284                 }
285
286         case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
287         case PTRACE_CONT:
288                 ret = -EIO;
289                 DBG(("sys_ptrace(%s)\n",
290                         request == PTRACE_SYSCALL ? "SYSCALL" : "CONT"));
291                 if ((unsigned long) data > _NSIG)
292                         goto out_tsk;
293                 child->ptrace &= ~(PT_SINGLESTEP|PT_BLOCKSTEP);
294                 if (request == PTRACE_SYSCALL) {
295                         set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
296                 } else {
297                         clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
298                 }               
299                 child->exit_code = data;
300                 goto out_wake_notrap;
301
302         case PTRACE_KILL:
303                 /*
304                  * make the child exit.  Best I can do is send it a
305                  * sigkill.  perhaps it should be put in the status
306                  * that it wants to exit.
307                  */
308                 DBG(("sys_ptrace(KILL)\n"));
309                 if (child->state == TASK_ZOMBIE)        /* already dead */
310                         goto out_tsk;
311                 child->exit_code = SIGKILL;
312                 goto out_wake_notrap;
313
314         case PTRACE_SINGLEBLOCK:
315                 DBG(("sys_ptrace(SINGLEBLOCK)\n"));
316                 ret = -EIO;
317                 if ((unsigned long) data > _NSIG)
318                         goto out_tsk;
319                 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
320                 child->ptrace &= ~PT_SINGLESTEP;
321                 child->ptrace |= PT_BLOCKSTEP;
322                 child->exit_code = data;
323
324                 /* Enable taken branch trap. */
325                 pa_psw(child)->r = 0;
326                 pa_psw(child)->t = 1;
327                 pa_psw(child)->h = 0;
328                 pa_psw(child)->l = 0;
329                 goto out_wake;
330
331         case PTRACE_SINGLESTEP:
332                 DBG(("sys_ptrace(SINGLESTEP)\n"));
333                 ret = -EIO;
334                 if ((unsigned long) data > _NSIG)
335                         goto out_tsk;
336                 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
337                 child->ptrace &= ~PT_BLOCKSTEP;
338                 child->ptrace |= PT_SINGLESTEP;
339                 child->exit_code = data;
340
341                 if (pa_psw(child)->n) {
342                         struct siginfo si;
343
344                         /* Nullified, just crank over the queue. */
345                         task_regs(child)->iaoq[0] = task_regs(child)->iaoq[1];
346                         task_regs(child)->iasq[0] = task_regs(child)->iasq[1];
347                         task_regs(child)->iaoq[1] = task_regs(child)->iaoq[0] + 4;
348                         pa_psw(child)->n = 0;
349                         pa_psw(child)->x = 0;
350                         pa_psw(child)->y = 0;
351                         pa_psw(child)->z = 0;
352                         pa_psw(child)->b = 0;
353                         ptrace_disable(child);
354                         /* Don't wake up the child, but let the
355                            parent know something happened. */
356                         si.si_code = TRAP_TRACE;
357                         si.si_addr = (void *) (task_regs(child)->iaoq[0] & ~3);
358                         si.si_signo = SIGTRAP;
359                         si.si_errno = 0;
360                         force_sig_info(SIGTRAP, &si, child);
361                         //notify_parent(child, SIGCHLD);
362                         //ret = 0;
363                         goto out_wake;
364                 }
365
366                 /* Enable recovery counter traps.  The recovery counter
367                  * itself will be set to zero on a task switch.  If the
368                  * task is suspended on a syscall then the syscall return
369                  * path will overwrite the recovery counter with a suitable
370                  * value such that it traps once back in user space.  We
371                  * disable interrupts in the childs PSW here also, to avoid
372                  * interrupts while the recovery counter is decrementing.
373                  */
374                 pa_psw(child)->r = 1;
375                 pa_psw(child)->t = 0;
376                 pa_psw(child)->h = 0;
377                 pa_psw(child)->l = 0;
378                 /* give it a chance to run. */
379                 goto out_wake;
380
381         case PTRACE_DETACH:
382                 ret = ptrace_detach(child, data);
383                 goto out_tsk;
384
385         default:
386                 ret = ptrace_request(child, request, addr, data);
387                 goto out_tsk;
388         }
389
390 out_wake_notrap:
391         ptrace_disable(child);
392 out_wake:
393         wake_up_process(child);
394         ret = 0;
395 out_tsk:
396         put_task_struct(child);
397 out:
398         unlock_kernel();
399         DBG(("sys_ptrace(%ld, %d, %lx, %lx) returning %ld\n",
400                 request, pid, oaddr, odata, ret));
401         return ret;
402 }
403
404 void syscall_trace(void)
405 {
406         if (!test_thread_flag(TIF_SYSCALL_TRACE))
407                 return;
408         if (!(current->ptrace & PT_PTRACED))
409                 return;
410         current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
411                                         ? 0x80 : 0);
412         current->state = TASK_STOPPED;
413         notify_parent(current, SIGCHLD);
414         schedule();
415         /*
416          * this isn't the same as continuing with a signal, but it will do
417          * for normal use.  strace only continues with a signal if the
418          * stopping signal is not SIGTRAP.  -brl
419          */
420         if (current->exit_code) {
421                 send_sig(current->exit_code, current, 1);
422                 current->exit_code = 0;
423         }
424 }