Merge to Fedora kernel-2.6.18-1.2255_FC5-vs2.0.2.2-rc9 patched with stable patch...
[linux-2.6.git] / arch / powerpc / kernel / ptrace32.c
1 /*
2  * ptrace for 32-bit processes running on a 64-bit kernel.
3  *
4  *  PowerPC version
5  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
6  *
7  *  Derived from "arch/m68k/kernel/ptrace.c"
8  *  Copyright (C) 1994 by Hamish Macdonald
9  *  Taken from linux/kernel/ptrace.c and modified for M680x0.
10  *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
11  *
12  * Modified by Cort Dougan (cort@hq.fsmlabs.com)
13  * and Paul Mackerras (paulus@samba.org).
14  *
15  * This file is subject to the terms and conditions of the GNU General
16  * Public License.  See the file COPYING in the main directory of
17  * this archive for more details.
18  */
19
20 #include <linux/kernel.h>
21 #include <linux/sched.h>
22 #include <linux/mm.h>
23 #include <linux/smp.h>
24 #include <linux/smp_lock.h>
25 #include <linux/errno.h>
26 #include <linux/ptrace.h>
27 #include <linux/user.h>
28 #include <linux/security.h>
29 #include <linux/signal.h>
30
31 #include <asm/uaccess.h>
32 #include <asm/page.h>
33 #include <asm/pgtable.h>
34 #include <asm/system.h>
35
36 #include "ptrace-common.h"
37
38 /*
39  * does not yet catch signals sent when the child dies.
40  * in exit.c or in signal.c.
41  */
42
43 long compat_sys_ptrace(int request, int pid, unsigned long addr,
44                        unsigned long data)
45 {
46         struct task_struct *child;
47         int ret;
48
49         lock_kernel();
50         if (request == PTRACE_TRACEME) {
51                 ret = ptrace_traceme();
52                 goto out;
53         }
54
55         child = ptrace_get_task_struct(pid);
56         if (IS_ERR(child)) {
57                 ret = PTR_ERR(child);
58                 goto out;
59         }
60
61         if (request == PTRACE_ATTACH) {
62                 ret = ptrace_attach(child);
63                 goto out_tsk;
64         }
65
66         ret = ptrace_check_attach(child, request == PTRACE_KILL);
67         if (ret < 0)
68                 goto out_tsk;
69
70         switch (request) {
71         /* when I and D space are separate, these will need to be fixed. */
72         case PTRACE_PEEKTEXT: /* read word at location addr. */ 
73         case PTRACE_PEEKDATA: {
74                 unsigned int tmp;
75                 int copied;
76
77                 copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
78                 ret = -EIO;
79                 if (copied != sizeof(tmp))
80                         break;
81                 ret = put_user(tmp, (u32 __user *)data);
82                 break;
83         }
84
85         /*
86          * Read 4 bytes of the other process' storage
87          *  data is a pointer specifying where the user wants the
88          *      4 bytes copied into
89          *  addr is a pointer in the user's storage that contains an 8 byte
90          *      address in the other process of the 4 bytes that is to be read
91          * (this is run in a 32-bit process looking at a 64-bit process)
92          * when I and D space are separate, these will need to be fixed.
93          */
94         case PPC_PTRACE_PEEKTEXT_3264:
95         case PPC_PTRACE_PEEKDATA_3264: {
96                 u32 tmp;
97                 int copied;
98                 u32 __user * addrOthers;
99
100                 ret = -EIO;
101
102                 /* Get the addr in the other process that we want to read */
103                 if (get_user(addrOthers, (u32 __user * __user *)addr) != 0)
104                         break;
105
106                 copied = access_process_vm(child, (u64)addrOthers, &tmp,
107                                 sizeof(tmp), 0);
108                 if (copied != sizeof(tmp))
109                         break;
110                 ret = put_user(tmp, (u32 __user *)data);
111                 break;
112         }
113
114         /* Read a register (specified by ADDR) out of the "user area" */
115         case PTRACE_PEEKUSR: {
116                 int index;
117                 unsigned long tmp;
118
119                 ret = -EIO;
120                 /* convert to index and check */
121                 index = (unsigned long) addr >> 2;
122                 if ((addr & 3) || (index > PT_FPSCR32))
123                         break;
124
125                 if (index < PT_FPR0) {
126                         tmp = get_reg(child, index);
127                 } else {
128                         flush_fp_to_thread(child);
129                         /*
130                          * the user space code considers the floating point
131                          * to be an array of unsigned int (32 bits) - the
132                          * index passed in is based on this assumption.
133                          */
134                         tmp = ((unsigned int *)child->thread.fpr)[index - PT_FPR0];
135                 }
136                 ret = put_user((unsigned int)tmp, (u32 __user *)data);
137                 break;
138         }
139   
140         /*
141          * Read 4 bytes out of the other process' pt_regs area
142          *  data is a pointer specifying where the user wants the
143          *      4 bytes copied into
144          *  addr is the offset into the other process' pt_regs structure
145          *      that is to be read
146          * (this is run in a 32-bit process looking at a 64-bit process)
147          */
148         case PPC_PTRACE_PEEKUSR_3264: {
149                 u32 index;
150                 u32 reg32bits;
151                 u64 tmp;
152                 u32 numReg;
153                 u32 part;
154
155                 ret = -EIO;
156                 /* Determine which register the user wants */
157                 index = (u64)addr >> 2;
158                 numReg = index / 2;
159                 /* Determine which part of the register the user wants */
160                 if (index % 2)
161                         part = 1;  /* want the 2nd half of the register (right-most). */
162                 else
163                         part = 0;  /* want the 1st half of the register (left-most). */
164
165                 /* Validate the input - check to see if address is on the wrong boundary or beyond the end of the user area */
166                 if ((addr & 3) || numReg > PT_FPSCR)
167                         break;
168
169                 if (numReg >= PT_FPR0) {
170                         flush_fp_to_thread(child);
171                         tmp = ((unsigned long int *)child->thread.fpr)[numReg - PT_FPR0];
172                 } else { /* register within PT_REGS struct */
173                         tmp = get_reg(child, numReg);
174                 } 
175                 reg32bits = ((u32*)&tmp)[part];
176                 ret = put_user(reg32bits, (u32 __user *)data);
177                 break;
178         }
179
180         /* If I and D space are separate, this will have to be fixed. */
181         case PTRACE_POKETEXT: /* write the word at location addr. */
182         case PTRACE_POKEDATA: {
183                 unsigned int tmp;
184                 tmp = data;
185                 ret = 0;
186                 if (access_process_vm(child, addr, &tmp, sizeof(tmp), 1)
187                                 == sizeof(tmp))
188                         break;
189                 ret = -EIO;
190                 break;
191         }
192
193         /*
194          * Write 4 bytes into the other process' storage
195          *  data is the 4 bytes that the user wants written
196          *  addr is a pointer in the user's storage that contains an
197          *      8 byte address in the other process where the 4 bytes
198          *      that is to be written
199          * (this is run in a 32-bit process looking at a 64-bit process)
200          * when I and D space are separate, these will need to be fixed.
201          */
202         case PPC_PTRACE_POKETEXT_3264:
203         case PPC_PTRACE_POKEDATA_3264: {
204                 u32 tmp = data;
205                 u32 __user * addrOthers;
206
207                 /* Get the addr in the other process that we want to write into */
208                 ret = -EIO;
209                 if (get_user(addrOthers, (u32 __user * __user *)addr) != 0)
210                         break;
211                 ret = 0;
212                 if (access_process_vm(child, (u64)addrOthers, &tmp,
213                                         sizeof(tmp), 1) == sizeof(tmp))
214                         break;
215                 ret = -EIO;
216                 break;
217         }
218
219         /* write the word at location addr in the USER area */
220         case PTRACE_POKEUSR: {
221                 unsigned long index;
222
223                 ret = -EIO;
224                 /* convert to index and check */
225                 index = (unsigned long) addr >> 2;
226                 if ((addr & 3) || (index > PT_FPSCR32))
227                         break;
228
229                 if (index == PT_ORIG_R3)
230                         break;
231                 if (index < PT_FPR0) {
232                         ret = put_reg(child, index, data);
233                 } else {
234                         flush_fp_to_thread(child);
235                         /*
236                          * the user space code considers the floating point
237                          * to be an array of unsigned int (32 bits) - the
238                          * index passed in is based on this assumption.
239                          */
240                         ((unsigned int *)child->thread.fpr)[index - PT_FPR0] = data;
241                         ret = 0;
242                 }
243                 break;
244         }
245
246         /*
247          * Write 4 bytes into the other process' pt_regs area
248          *  data is the 4 bytes that the user wants written
249          *  addr is the offset into the other process' pt_regs structure
250          *      that is to be written into
251          * (this is run in a 32-bit process looking at a 64-bit process)
252          */
253         case PPC_PTRACE_POKEUSR_3264: {
254                 u32 index;
255                 u32 numReg;
256
257                 ret = -EIO;
258                 /* Determine which register the user wants */
259                 index = (u64)addr >> 2;
260                 numReg = index / 2;
261                 /*
262                  * Validate the input - check to see if address is on the
263                  * wrong boundary or beyond the end of the user area
264                  */
265                 if ((addr & 3) || (numReg > PT_FPSCR))
266                         break;
267                 /* Insure it is a register we let them change */
268                 if ((numReg == PT_ORIG_R3)
269                                 || ((numReg > PT_CCR) && (numReg < PT_FPR0)))
270                         break;
271                 if (numReg >= PT_FPR0) {
272                         flush_fp_to_thread(child);
273                 }
274                 if (numReg == PT_MSR)
275                         data = (data & MSR_DEBUGCHANGE)
276                                 | (child->thread.regs->msr & ~MSR_DEBUGCHANGE);
277                 ((u32*)child->thread.regs)[index] = data;
278                 ret = 0;
279                 break;
280         }
281
282         case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
283         case PTRACE_CONT: { /* restart after signal. */
284                 ret = -EIO;
285                 if (!valid_signal(data))
286                         break;
287                 if (request == PTRACE_SYSCALL)
288                         set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
289                 else
290                         clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
291                 child->exit_code = data;
292                 /* make sure the single step bit is not set. */
293                 clear_single_step(child);
294                 wake_up_process(child);
295                 ret = 0;
296                 break;
297         }
298
299         /*
300          * make the child exit.  Best I can do is send it a sigkill.
301          * perhaps it should be put in the status that it wants to
302          * exit.
303          */
304         case PTRACE_KILL: {
305                 ret = 0;
306                 if (child->exit_state == EXIT_ZOMBIE)   /* already dead */
307                         break;
308                 child->exit_code = SIGKILL;
309                 /* make sure the single step bit is not set. */
310                 clear_single_step(child);
311                 wake_up_process(child);
312                 break;
313         }
314
315         case PTRACE_SINGLESTEP: {  /* set the trap flag. */
316                 ret = -EIO;
317                 if (!valid_signal(data))
318                         break;
319                 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
320                 set_single_step(child);
321                 child->exit_code = data;
322                 /* give it a chance to run. */
323                 wake_up_process(child);
324                 ret = 0;
325                 break;
326         }
327
328         case PTRACE_GET_DEBUGREG: {
329                 ret = -EINVAL;
330                 /* We only support one DABR and no IABRS at the moment */
331                 if (addr > 0)
332                         break;
333                 ret = put_user(child->thread.dabr, (u32 __user *)data);
334                 break;
335         }
336
337         case PTRACE_SET_DEBUGREG:
338                 ret = ptrace_set_debugreg(child, addr, data);
339                 break;
340
341         case PTRACE_DETACH:
342                 ret = ptrace_detach(child, data);
343                 break;
344
345         case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
346                 int i;
347                 unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
348                 unsigned int __user *tmp = (unsigned int __user *)addr;
349
350                 for (i = 0; i < 32; i++) {
351                         ret = put_user(*reg, tmp);
352                         if (ret)
353                                 break;
354                         reg++;
355                         tmp++;
356                 }
357                 break;
358         }
359
360         case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
361                 int i;
362                 unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
363                 unsigned int __user *tmp = (unsigned int __user *)addr;
364
365                 for (i = 0; i < 32; i++) {
366                         ret = get_user(*reg, tmp);
367                         if (ret)
368                                 break;
369                         reg++;
370                         tmp++;
371                 }
372                 break;
373         }
374
375         case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
376                 int i;
377                 unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
378                 unsigned int __user *tmp = (unsigned int __user *)addr;
379
380                 flush_fp_to_thread(child);
381
382                 for (i = 0; i < 32; i++) {
383                         ret = put_user(*reg, tmp);
384                         if (ret)
385                                 break;
386                         reg++;
387                         tmp++;
388                 }
389                 break;
390         }
391
392         case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
393                 int i;
394                 unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
395                 unsigned int __user *tmp = (unsigned int __user *)addr;
396
397                 flush_fp_to_thread(child);
398
399                 for (i = 0; i < 32; i++) {
400                         ret = get_user(*reg, tmp);
401                         if (ret)
402                                 break;
403                         reg++;
404                         tmp++;
405                 }
406                 break;
407         }
408
409         case PTRACE_GETEVENTMSG:
410                 ret = put_user(child->ptrace_message, (unsigned int __user *) data);
411                 break;
412
413 #ifdef CONFIG_ALTIVEC
414         case PTRACE_GETVRREGS:
415                 /* Get the child altivec register state. */
416                 flush_altivec_to_thread(child);
417                 ret = get_vrregs((unsigned long __user *)data, child);
418                 break;
419
420         case PTRACE_SETVRREGS:
421                 /* Set the child altivec register state. */
422                 flush_altivec_to_thread(child);
423                 ret = set_vrregs(child, (unsigned long __user *)data);
424                 break;
425 #endif
426
427         default:
428                 ret = ptrace_request(child, request, addr, data);
429                 break;
430         }
431 out_tsk:
432         put_task_struct(child);
433 out:
434         unlock_kernel();
435         return ret;
436 }