diff options
Diffstat (limited to 'arch/mips/kernel/ptrace32.c')
-rw-r--r-- | arch/mips/kernel/ptrace32.c | 150 |
1 files changed, 145 insertions, 5 deletions
diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index eee207969c21..9a9b04972132 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c | |||
@@ -24,17 +24,24 @@ | |||
24 | #include <linux/smp_lock.h> | 24 | #include <linux/smp_lock.h> |
25 | #include <linux/user.h> | 25 | #include <linux/user.h> |
26 | #include <linux/security.h> | 26 | #include <linux/security.h> |
27 | #include <linux/signal.h> | ||
28 | 27 | ||
29 | #include <asm/cpu.h> | 28 | #include <asm/cpu.h> |
29 | #include <asm/dsp.h> | ||
30 | #include <asm/fpu.h> | 30 | #include <asm/fpu.h> |
31 | #include <asm/mipsregs.h> | 31 | #include <asm/mipsregs.h> |
32 | #include <asm/mipsmtregs.h> | ||
32 | #include <asm/pgtable.h> | 33 | #include <asm/pgtable.h> |
33 | #include <asm/page.h> | 34 | #include <asm/page.h> |
34 | #include <asm/system.h> | 35 | #include <asm/system.h> |
35 | #include <asm/uaccess.h> | 36 | #include <asm/uaccess.h> |
36 | #include <asm/bootinfo.h> | 37 | #include <asm/bootinfo.h> |
37 | 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 | |||
38 | /* | 45 | /* |
39 | * Tracing a 32-bit process with a 64-bit strace and vice versa will not | 46 | * Tracing a 32-bit process with a 64-bit strace and vice versa will not |
40 | * work. I don't know how to fix this. | 47 | * work. I don't know how to fix this. |
@@ -99,6 +106,35 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) | |||
99 | break; | 106 | break; |
100 | } | 107 | } |
101 | 108 | ||
109 | /* | ||
110 | * Read 4 bytes of the other process' storage | ||
111 | * data is a pointer specifying where the user wants the | ||
112 | * 4 bytes copied into | ||
113 | * addr is a pointer in the user's storage that contains an 8 byte | ||
114 | * address in the other process of the 4 bytes that is to be read | ||
115 | * (this is run in a 32-bit process looking at a 64-bit process) | ||
116 | * when I and D space are separate, these will need to be fixed. | ||
117 | */ | ||
118 | case PTRACE_PEEKTEXT_3264: | ||
119 | case PTRACE_PEEKDATA_3264: { | ||
120 | u32 tmp; | ||
121 | int copied; | ||
122 | u32 __user * addrOthers; | ||
123 | |||
124 | ret = -EIO; | ||
125 | |||
126 | /* Get the addr in the other process that we want to read */ | ||
127 | if (get_user(addrOthers, (u32 __user * __user *) (unsigned long) addr) != 0) | ||
128 | break; | ||
129 | |||
130 | copied = access_process_vm(child, (u64)addrOthers, &tmp, | ||
131 | sizeof(tmp), 0); | ||
132 | if (copied != sizeof(tmp)) | ||
133 | break; | ||
134 | ret = put_user(tmp, (u32 __user *) (unsigned long) data); | ||
135 | break; | ||
136 | } | ||
137 | |||
102 | /* Read the word at location addr in the USER area. */ | 138 | /* Read the word at location addr in the USER area. */ |
103 | case PTRACE_PEEKUSR: { | 139 | case PTRACE_PEEKUSR: { |
104 | struct pt_regs *regs; | 140 | struct pt_regs *regs; |
@@ -156,12 +192,44 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) | |||
156 | if (!cpu_has_fpu) | 192 | if (!cpu_has_fpu) |
157 | break; | 193 | break; |
158 | 194 | ||
159 | flags = read_c0_status(); | 195 | preempt_disable(); |
160 | __enable_fpu(); | 196 | if (cpu_has_mipsmt) { |
161 | __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); | 197 | unsigned int vpflags = dvpe(); |
162 | write_c0_status(flags); | 198 | flags = read_c0_status(); |
199 | __enable_fpu(); | ||
200 | __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); | ||
201 | write_c0_status(flags); | ||
202 | evpe(vpflags); | ||
203 | } else { | ||
204 | flags = read_c0_status(); | ||
205 | __enable_fpu(); | ||
206 | __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); | ||
207 | write_c0_status(flags); | ||
208 | } | ||
209 | preempt_enable(); | ||
163 | break; | 210 | break; |
164 | } | 211 | } |
212 | case DSP_BASE ... DSP_BASE + 5: | ||
213 | if (!cpu_has_dsp) { | ||
214 | tmp = 0; | ||
215 | ret = -EIO; | ||
216 | goto out_tsk; | ||
217 | } | ||
218 | if (child->thread.dsp.used_dsp) { | ||
219 | dspreg_t *dregs = __get_dsp_regs(child); | ||
220 | tmp = (unsigned long) (dregs[addr - DSP_BASE]); | ||
221 | } else { | ||
222 | tmp = -1; /* DSP registers yet used */ | ||
223 | } | ||
224 | break; | ||
225 | case DSP_CONTROL: | ||
226 | if (!cpu_has_dsp) { | ||
227 | tmp = 0; | ||
228 | ret = -EIO; | ||
229 | goto out_tsk; | ||
230 | } | ||
231 | tmp = child->thread.dsp.dspcontrol; | ||
232 | break; | ||
165 | default: | 233 | default: |
166 | tmp = 0; | 234 | tmp = 0; |
167 | ret = -EIO; | 235 | ret = -EIO; |
@@ -181,6 +249,31 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) | |||
181 | ret = -EIO; | 249 | ret = -EIO; |
182 | break; | 250 | break; |
183 | 251 | ||
252 | /* | ||
253 | * Write 4 bytes into the other process' storage | ||
254 | * data is the 4 bytes that the user wants written | ||
255 | * addr is a pointer in the user's storage that contains an | ||
256 | * 8 byte address in the other process where the 4 bytes | ||
257 | * that is to be written | ||
258 | * (this is run in a 32-bit process looking at a 64-bit process) | ||
259 | * when I and D space are separate, these will need to be fixed. | ||
260 | */ | ||
261 | case PTRACE_POKETEXT_3264: | ||
262 | case PTRACE_POKEDATA_3264: { | ||
263 | u32 __user * addrOthers; | ||
264 | |||
265 | /* Get the addr in the other process that we want to write into */ | ||
266 | ret = -EIO; | ||
267 | if (get_user(addrOthers, (u32 __user * __user *) (unsigned long) addr) != 0) | ||
268 | break; | ||
269 | ret = 0; | ||
270 | if (access_process_vm(child, (u64)addrOthers, &data, | ||
271 | sizeof(data), 1) == sizeof(data)) | ||
272 | break; | ||
273 | ret = -EIO; | ||
274 | break; | ||
275 | } | ||
276 | |||
184 | case PTRACE_POKEUSR: { | 277 | case PTRACE_POKEUSR: { |
185 | struct pt_regs *regs; | 278 | struct pt_regs *regs; |
186 | ret = 0; | 279 | ret = 0; |
@@ -231,6 +324,22 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) | |||
231 | else | 324 | else |
232 | child->thread.fpu.soft.fcr31 = data; | 325 | child->thread.fpu.soft.fcr31 = data; |
233 | break; | 326 | break; |
327 | case DSP_BASE ... DSP_BASE + 5: | ||
328 | if (!cpu_has_dsp) { | ||
329 | ret = -EIO; | ||
330 | break; | ||
331 | } | ||
332 | |||
333 | dspreg_t *dregs = __get_dsp_regs(child); | ||
334 | dregs[addr - DSP_BASE] = data; | ||
335 | break; | ||
336 | case DSP_CONTROL: | ||
337 | if (!cpu_has_dsp) { | ||
338 | ret = -EIO; | ||
339 | break; | ||
340 | } | ||
341 | child->thread.dsp.dspcontrol = data; | ||
342 | break; | ||
234 | default: | 343 | default: |
235 | /* The rest are not allowed. */ | 344 | /* The rest are not allowed. */ |
236 | ret = -EIO; | 345 | ret = -EIO; |
@@ -239,6 +348,22 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) | |||
239 | break; | 348 | break; |
240 | } | 349 | } |
241 | 350 | ||
351 | case PTRACE_GETREGS: | ||
352 | ret = ptrace_getregs (child, (__u64 __user *) (__u64) data); | ||
353 | break; | ||
354 | |||
355 | case PTRACE_SETREGS: | ||
356 | ret = ptrace_setregs (child, (__u64 __user *) (__u64) data); | ||
357 | break; | ||
358 | |||
359 | case PTRACE_GETFPREGS: | ||
360 | ret = ptrace_getfpregs (child, (__u32 __user *) (__u64) data); | ||
361 | break; | ||
362 | |||
363 | case PTRACE_SETFPREGS: | ||
364 | ret = ptrace_setfpregs (child, (__u32 __user *) (__u64) data); | ||
365 | break; | ||
366 | |||
242 | case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ | 367 | case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ |
243 | case PTRACE_CONT: { /* restart after signal. */ | 368 | case PTRACE_CONT: { /* restart after signal. */ |
244 | ret = -EIO; | 369 | ret = -EIO; |
@@ -269,10 +394,25 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) | |||
269 | wake_up_process(child); | 394 | wake_up_process(child); |
270 | break; | 395 | break; |
271 | 396 | ||
397 | case PTRACE_GET_THREAD_AREA: | ||
398 | ret = put_user(child->thread_info->tp_value, | ||
399 | (unsigned int __user *) (unsigned long) data); | ||
400 | break; | ||
401 | |||
272 | case PTRACE_DETACH: /* detach a process that was attached. */ | 402 | case PTRACE_DETACH: /* detach a process that was attached. */ |
273 | ret = ptrace_detach(child, data); | 403 | ret = ptrace_detach(child, data); |
274 | break; | 404 | break; |
275 | 405 | ||
406 | case PTRACE_GETEVENTMSG: | ||
407 | ret = put_user(child->ptrace_message, | ||
408 | (unsigned int __user *) (unsigned long) data); | ||
409 | break; | ||
410 | |||
411 | case PTRACE_GET_THREAD_AREA_3264: | ||
412 | ret = put_user(child->thread_info->tp_value, | ||
413 | (unsigned long __user *) (unsigned long) data); | ||
414 | break; | ||
415 | |||
276 | default: | 416 | default: |
277 | ret = ptrace_request(child, request, addr, data); | 417 | ret = ptrace_request(child, request, addr, data); |
278 | break; | 418 | break; |