Merge master.kernel.org:/home/rmk/linux-2.6-arm
[linux-2.6] / arch / mips / kernel / ptrace32.c
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 1992 Ross Biro
7  * Copyright (C) Linus Torvalds
8  * Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle
9  * Copyright (C) 1996 David S. Miller
10  * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
11  * Copyright (C) 1999 MIPS Technologies, Inc.
12  * Copyright (C) 2000 Ulf Carlsson
13  *
14  * At this time Linux/MIPS64 only supports syscall tracing, even for 32-bit
15  * binaries.
16  */
17 #include <linux/compiler.h>
18 #include <linux/kernel.h>
19 #include <linux/sched.h>
20 #include <linux/mm.h>
21 #include <linux/errno.h>
22 #include <linux/ptrace.h>
23 #include <linux/smp.h>
24 #include <linux/smp_lock.h>
25 #include <linux/user.h>
26 #include <linux/security.h>
27
28 #include <asm/cpu.h>
29 #include <asm/dsp.h>
30 #include <asm/fpu.h>
31 #include <asm/mipsregs.h>
32 #include <asm/mipsmtregs.h>
33 #include <asm/pgtable.h>
34 #include <asm/page.h>
35 #include <asm/system.h>
36 #include <asm/uaccess.h>
37 #include <asm/bootinfo.h>
38
39 int ptrace_getregs (struct task_struct *child, __s64 __user *data);
40 int ptrace_setregs (struct task_struct *child, __s64 __user *data);
41
42 int ptrace_getfpregs (struct task_struct *child, __u32 __user *data);
43 int ptrace_setfpregs (struct task_struct *child, __u32 __user *data);
44
45 /*
46  * Tracing a 32-bit process with a 64-bit strace and vice versa will not
47  * work.  I don't know how to fix this.
48  */
49 asmlinkage int sys32_ptrace(int request, int pid, int addr, int data)
50 {
51         struct task_struct *child;
52         int ret;
53
54 #if 0
55         printk("ptrace(r=%d,pid=%d,addr=%08lx,data=%08lx)\n",
56                (int) request, (int) pid, (unsigned long) addr,
57                (unsigned long) data);
58 #endif
59         lock_kernel();
60         if (request == PTRACE_TRACEME) {
61                 ret = ptrace_traceme();
62                 goto out;
63         }
64
65         child = ptrace_get_task_struct(pid);
66         if (IS_ERR(child)) {
67                 ret = PTR_ERR(child);
68                 goto out;
69         }
70
71         if (request == PTRACE_ATTACH) {
72                 ret = ptrace_attach(child);
73                 goto out_tsk;
74         }
75
76         ret = ptrace_check_attach(child, request == PTRACE_KILL);
77         if (ret < 0)
78                 goto out_tsk;
79
80         switch (request) {
81         /* when I and D space are separate, these will need to be fixed. */
82         case PTRACE_PEEKTEXT: /* read word at location addr. */
83         case PTRACE_PEEKDATA: {
84                 unsigned int tmp;
85                 int copied;
86
87                 copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
88                 ret = -EIO;
89                 if (copied != sizeof(tmp))
90                         break;
91                 ret = put_user(tmp, (unsigned int *) (unsigned long) data);
92                 break;
93         }
94
95         /*
96          * Read 4 bytes of the other process' storage
97          *  data is a pointer specifying where the user wants the
98          *      4 bytes copied into
99          *  addr is a pointer in the user's storage that contains an 8 byte
100          *      address in the other process of the 4 bytes that is to be read
101          * (this is run in a 32-bit process looking at a 64-bit process)
102          * when I and D space are separate, these will need to be fixed.
103          */
104         case PTRACE_PEEKTEXT_3264:
105         case PTRACE_PEEKDATA_3264: {
106                 u32 tmp;
107                 int copied;
108                 u32 __user * addrOthers;
109
110                 ret = -EIO;
111
112                 /* Get the addr in the other process that we want to read */
113                 if (get_user(addrOthers, (u32 __user * __user *) (unsigned long) addr) != 0)
114                         break;
115
116                 copied = access_process_vm(child, (u64)addrOthers, &tmp,
117                                 sizeof(tmp), 0);
118                 if (copied != sizeof(tmp))
119                         break;
120                 ret = put_user(tmp, (u32 __user *) (unsigned long) data);
121                 break;
122         }
123
124         /* Read the word at location addr in the USER area. */
125         case PTRACE_PEEKUSR: {
126                 struct pt_regs *regs;
127                 unsigned int tmp;
128
129                 regs = task_pt_regs(child);
130                 ret = 0;  /* Default return value. */
131
132                 switch (addr) {
133                 case 0 ... 31:
134                         tmp = regs->regs[addr];
135                         break;
136                 case FPR_BASE ... FPR_BASE + 31:
137                         if (tsk_used_math(child)) {
138                                 fpureg_t *fregs = get_fpu_regs(child);
139
140                                 /*
141                                  * The odd registers are actually the high
142                                  * order bits of the values stored in the even
143                                  * registers - unless we're using r2k_switch.S.
144                                  */
145                                 if (addr & 1)
146                                         tmp = (unsigned long) (fregs[((addr & ~1) - 32)] >> 32);
147                                 else
148                                         tmp = (unsigned long) (fregs[(addr - 32)] & 0xffffffff);
149                         } else {
150                                 tmp = -1;       /* FP not yet used  */
151                         }
152                         break;
153                 case PC:
154                         tmp = regs->cp0_epc;
155                         break;
156                 case CAUSE:
157                         tmp = regs->cp0_cause;
158                         break;
159                 case BADVADDR:
160                         tmp = regs->cp0_badvaddr;
161                         break;
162                 case MMHI:
163                         tmp = regs->hi;
164                         break;
165                 case MMLO:
166                         tmp = regs->lo;
167                         break;
168                 case FPC_CSR:
169                         if (cpu_has_fpu)
170                                 tmp = child->thread.fpu.hard.fcr31;
171                         else
172                                 tmp = child->thread.fpu.soft.fcr31;
173                         break;
174                 case FPC_EIR: { /* implementation / version register */
175                         unsigned int flags;
176
177                         if (!cpu_has_fpu)
178                                 break;
179
180                         preempt_disable();
181                         if (cpu_has_mipsmt) {
182                                 unsigned int vpflags = dvpe();
183                                 flags = read_c0_status();
184                                 __enable_fpu();
185                                 __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
186                                 write_c0_status(flags);
187                                 evpe(vpflags);
188                         } else {
189                                 flags = read_c0_status();
190                                 __enable_fpu();
191                                 __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
192                                 write_c0_status(flags);
193                         }
194                         preempt_enable();
195                         break;
196                 }
197                 case DSP_BASE ... DSP_BASE + 5:
198                         if (!cpu_has_dsp) {
199                                 tmp = 0;
200                                 ret = -EIO;
201                                 goto out_tsk;
202                         }
203                         dspreg_t *dregs = __get_dsp_regs(child);
204                         tmp = (unsigned long) (dregs[addr - DSP_BASE]);
205                         break;
206                 case DSP_CONTROL:
207                         if (!cpu_has_dsp) {
208                                 tmp = 0;
209                                 ret = -EIO;
210                                 goto out_tsk;
211                         }
212                         tmp = child->thread.dsp.dspcontrol;
213                         break;
214                 default:
215                         tmp = 0;
216                         ret = -EIO;
217                         goto out_tsk;
218                 }
219                 ret = put_user(tmp, (unsigned *) (unsigned long) data);
220                 break;
221         }
222
223         /* when I and D space are separate, this will have to be fixed. */
224         case PTRACE_POKETEXT: /* write the word at location addr. */
225         case PTRACE_POKEDATA:
226                 ret = 0;
227                 if (access_process_vm(child, addr, &data, sizeof(data), 1)
228                     == sizeof(data))
229                         break;
230                 ret = -EIO;
231                 break;
232
233         /*
234          * Write 4 bytes into the other process' storage
235          *  data is the 4 bytes that the user wants written
236          *  addr is a pointer in the user's storage that contains an
237          *      8 byte address in the other process where the 4 bytes
238          *      that is to be written
239          * (this is run in a 32-bit process looking at a 64-bit process)
240          * when I and D space are separate, these will need to be fixed.
241          */
242         case PTRACE_POKETEXT_3264:
243         case PTRACE_POKEDATA_3264: {
244                 u32 __user * addrOthers;
245
246                 /* Get the addr in the other process that we want to write into */
247                 ret = -EIO;
248                 if (get_user(addrOthers, (u32 __user * __user *) (unsigned long) addr) != 0)
249                         break;
250                 ret = 0;
251                 if (access_process_vm(child, (u64)addrOthers, &data,
252                                         sizeof(data), 1) == sizeof(data))
253                         break;
254                 ret = -EIO;
255                 break;
256         }
257
258         case PTRACE_POKEUSR: {
259                 struct pt_regs *regs;
260                 ret = 0;
261                 regs = task_pt_regs(child);
262
263                 switch (addr) {
264                 case 0 ... 31:
265                         regs->regs[addr] = data;
266                         break;
267                 case FPR_BASE ... FPR_BASE + 31: {
268                         fpureg_t *fregs = get_fpu_regs(child);
269
270                         if (!tsk_used_math(child)) {
271                                 /* FP not yet used  */
272                                 memset(&child->thread.fpu.hard, ~0,
273                                        sizeof(child->thread.fpu.hard));
274                                 child->thread.fpu.hard.fcr31 = 0;
275                         }
276                         /*
277                          * The odd registers are actually the high order bits
278                          * of the values stored in the even registers - unless
279                          * we're using r2k_switch.S.
280                          */
281                         if (addr & 1) {
282                                 fregs[(addr & ~1) - FPR_BASE] &= 0xffffffff;
283                                 fregs[(addr & ~1) - FPR_BASE] |= ((unsigned long long) data) << 32;
284                         } else {
285                                 fregs[addr - FPR_BASE] &= ~0xffffffffLL;
286                                 /* Must cast, lest sign extension fill upper
287                                    bits!  */
288                                 fregs[addr - FPR_BASE] |= (unsigned int)data;
289                         }
290                         break;
291                 }
292                 case PC:
293                         regs->cp0_epc = data;
294                         break;
295                 case MMHI:
296                         regs->hi = data;
297                         break;
298                 case MMLO:
299                         regs->lo = data;
300                         break;
301                 case FPC_CSR:
302                         if (cpu_has_fpu)
303                                 child->thread.fpu.hard.fcr31 = data;
304                         else
305                                 child->thread.fpu.soft.fcr31 = data;
306                         break;
307                 case DSP_BASE ... DSP_BASE + 5:
308                         if (!cpu_has_dsp) {
309                                 ret = -EIO;
310                                 break;
311                         }
312
313                         dspreg_t *dregs = __get_dsp_regs(child);
314                         dregs[addr - DSP_BASE] = data;
315                         break;
316                 case DSP_CONTROL:
317                         if (!cpu_has_dsp) {
318                                 ret = -EIO;
319                                 break;
320                         }
321                         child->thread.dsp.dspcontrol = data;
322                         break;
323                 default:
324                         /* The rest are not allowed. */
325                         ret = -EIO;
326                         break;
327                 }
328                 break;
329                 }
330
331         case PTRACE_GETREGS:
332                 ret = ptrace_getregs (child, (__u64 __user *) (__u64) data);
333                 break;
334
335         case PTRACE_SETREGS:
336                 ret = ptrace_setregs (child, (__u64 __user *) (__u64) data);
337                 break;
338
339         case PTRACE_GETFPREGS:
340                 ret = ptrace_getfpregs (child, (__u32 __user *) (__u64) data);
341                 break;
342
343         case PTRACE_SETFPREGS:
344                 ret = ptrace_setfpregs (child, (__u32 __user *) (__u64) data);
345                 break;
346
347         case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
348         case PTRACE_CONT: { /* restart after signal. */
349                 ret = -EIO;
350                 if (!valid_signal(data))
351                         break;
352                 if (request == PTRACE_SYSCALL) {
353                         set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
354                 }
355                 else {
356                         clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
357                 }
358                 child->exit_code = data;
359                 wake_up_process(child);
360                 ret = 0;
361                 break;
362         }
363
364         /*
365          * make the child exit.  Best I can do is send it a sigkill.
366          * perhaps it should be put in the status that it wants to
367          * exit.
368          */
369         case PTRACE_KILL:
370                 ret = 0;
371                 if (child->exit_state == EXIT_ZOMBIE)   /* already dead */
372                         break;
373                 child->exit_code = SIGKILL;
374                 wake_up_process(child);
375                 break;
376
377         case PTRACE_GET_THREAD_AREA:
378                 ret = put_user(task_thread_info(child)->tp_value,
379                                 (unsigned int __user *) (unsigned long) data);
380                 break;
381
382         case PTRACE_DETACH: /* detach a process that was attached. */
383                 ret = ptrace_detach(child, data);
384                 break;
385
386         case PTRACE_GETEVENTMSG:
387                 ret = put_user(child->ptrace_message,
388                                (unsigned int __user *) (unsigned long) data);
389                 break;
390
391         case PTRACE_GET_THREAD_AREA_3264:
392                 ret = put_user(task_thread_info(child)->tp_value,
393                                 (unsigned long __user *) (unsigned long) data);
394                 break;
395
396         default:
397                 ret = ptrace_request(child, request, addr, data);
398                 break;
399         }
400
401 out_tsk:
402         put_task_struct(child);
403 out:
404         unlock_kernel();
405         return ret;
406 }