diff options
Diffstat (limited to 'arch/powerpc/kernel/ptrace32.c')
-rw-r--r-- | arch/powerpc/kernel/ptrace32.c | 161 |
1 files changed, 31 insertions, 130 deletions
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c index fea6206ff90f..4c1de6af4c09 100644 --- a/arch/powerpc/kernel/ptrace32.c +++ b/arch/powerpc/kernel/ptrace32.c | |||
@@ -24,9 +24,11 @@ | |||
24 | #include <linux/smp_lock.h> | 24 | #include <linux/smp_lock.h> |
25 | #include <linux/errno.h> | 25 | #include <linux/errno.h> |
26 | #include <linux/ptrace.h> | 26 | #include <linux/ptrace.h> |
27 | #include <linux/regset.h> | ||
27 | #include <linux/user.h> | 28 | #include <linux/user.h> |
28 | #include <linux/security.h> | 29 | #include <linux/security.h> |
29 | #include <linux/signal.h> | 30 | #include <linux/signal.h> |
31 | #include <linux/compat.h> | ||
30 | 32 | ||
31 | #include <asm/uaccess.h> | 33 | #include <asm/uaccess.h> |
32 | #include <asm/page.h> | 34 | #include <asm/page.h> |
@@ -45,87 +47,31 @@ | |||
45 | static long compat_ptrace_old(struct task_struct *child, long request, | 47 | static long compat_ptrace_old(struct task_struct *child, long request, |
46 | long addr, long data) | 48 | long addr, long data) |
47 | { | 49 | { |
48 | int ret = -EPERM; | 50 | switch (request) { |
49 | 51 | case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */ | |
50 | switch(request) { | 52 | return copy_regset_to_user(child, |
51 | case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */ | 53 | task_user_regset_view(current), 0, |
52 | int i; | 54 | 0, 32 * sizeof(compat_long_t), |
53 | unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; | 55 | compat_ptr(data)); |
54 | unsigned int __user *tmp = (unsigned int __user *)addr; | 56 | |
55 | 57 | case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */ | |
56 | CHECK_FULL_REGS(child->thread.regs); | 58 | return copy_regset_from_user(child, |
57 | for (i = 0; i < 32; i++) { | 59 | task_user_regset_view(current), 0, |
58 | ret = put_user(*reg, tmp); | 60 | 0, 32 * sizeof(compat_long_t), |
59 | if (ret) | 61 | compat_ptr(data)); |
60 | break; | ||
61 | reg++; | ||
62 | tmp++; | ||
63 | } | ||
64 | break; | ||
65 | } | ||
66 | |||
67 | case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */ | ||
68 | int i; | ||
69 | unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; | ||
70 | unsigned int __user *tmp = (unsigned int __user *)addr; | ||
71 | |||
72 | CHECK_FULL_REGS(child->thread.regs); | ||
73 | for (i = 0; i < 32; i++) { | ||
74 | ret = get_user(*reg, tmp); | ||
75 | if (ret) | ||
76 | break; | ||
77 | reg++; | ||
78 | tmp++; | ||
79 | } | ||
80 | break; | ||
81 | } | 62 | } |
82 | 63 | ||
83 | } | 64 | return -EPERM; |
84 | return ret; | ||
85 | } | 65 | } |
86 | 66 | ||
87 | long compat_sys_ptrace(int request, int pid, unsigned long addr, | 67 | long compat_arch_ptrace(struct task_struct *child, compat_long_t request, |
88 | unsigned long data) | 68 | compat_ulong_t caddr, compat_ulong_t cdata) |
89 | { | 69 | { |
90 | struct task_struct *child; | 70 | unsigned long addr = caddr; |
71 | unsigned long data = cdata; | ||
91 | int ret; | 72 | int ret; |
92 | 73 | ||
93 | lock_kernel(); | ||
94 | if (request == PTRACE_TRACEME) { | ||
95 | ret = ptrace_traceme(); | ||
96 | goto out; | ||
97 | } | ||
98 | |||
99 | child = ptrace_get_task_struct(pid); | ||
100 | if (IS_ERR(child)) { | ||
101 | ret = PTR_ERR(child); | ||
102 | goto out; | ||
103 | } | ||
104 | |||
105 | if (request == PTRACE_ATTACH) { | ||
106 | ret = ptrace_attach(child); | ||
107 | goto out_tsk; | ||
108 | } | ||
109 | |||
110 | ret = ptrace_check_attach(child, request == PTRACE_KILL); | ||
111 | if (ret < 0) | ||
112 | goto out_tsk; | ||
113 | |||
114 | switch (request) { | 74 | switch (request) { |
115 | /* when I and D space are separate, these will need to be fixed. */ | ||
116 | case PTRACE_PEEKTEXT: /* read word at location addr. */ | ||
117 | case PTRACE_PEEKDATA: { | ||
118 | unsigned int tmp; | ||
119 | int copied; | ||
120 | |||
121 | copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); | ||
122 | ret = -EIO; | ||
123 | if (copied != sizeof(tmp)) | ||
124 | break; | ||
125 | ret = put_user(tmp, (u32 __user *)data); | ||
126 | break; | ||
127 | } | ||
128 | |||
129 | /* | 75 | /* |
130 | * Read 4 bytes of the other process' storage | 76 | * Read 4 bytes of the other process' storage |
131 | * data is a pointer specifying where the user wants the | 77 | * data is a pointer specifying where the user wants the |
@@ -225,19 +171,6 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, | |||
225 | break; | 171 | break; |
226 | } | 172 | } |
227 | 173 | ||
228 | /* If I and D space are separate, this will have to be fixed. */ | ||
229 | case PTRACE_POKETEXT: /* write the word at location addr. */ | ||
230 | case PTRACE_POKEDATA: { | ||
231 | unsigned int tmp; | ||
232 | tmp = data; | ||
233 | ret = 0; | ||
234 | if (access_process_vm(child, addr, &tmp, sizeof(tmp), 1) | ||
235 | == sizeof(tmp)) | ||
236 | break; | ||
237 | ret = -EIO; | ||
238 | break; | ||
239 | } | ||
240 | |||
241 | /* | 174 | /* |
242 | * Write 4 bytes into the other process' storage | 175 | * Write 4 bytes into the other process' storage |
243 | * data is the 4 bytes that the user wants written | 176 | * data is the 4 bytes that the user wants written |
@@ -337,46 +270,17 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, | |||
337 | break; | 270 | break; |
338 | } | 271 | } |
339 | 272 | ||
340 | case PTRACE_GETEVENTMSG: | 273 | case PTRACE_GETREGS: /* Get all pt_regs from the child. */ |
341 | ret = put_user(child->ptrace_message, (unsigned int __user *) data); | 274 | return copy_regset_to_user( |
342 | break; | 275 | child, task_user_regset_view(current), 0, |
276 | 0, PT_REGS_COUNT * sizeof(compat_long_t), | ||
277 | compat_ptr(data)); | ||
343 | 278 | ||
344 | case PTRACE_GETREGS: { /* Get all pt_regs from the child. */ | 279 | case PTRACE_SETREGS: /* Set all gp regs in the child. */ |
345 | int ui; | 280 | return copy_regset_from_user( |
346 | if (!access_ok(VERIFY_WRITE, (void __user *)data, | 281 | child, task_user_regset_view(current), 0, |
347 | PT_REGS_COUNT * sizeof(int))) { | 282 | 0, PT_REGS_COUNT * sizeof(compat_long_t), |
348 | ret = -EIO; | 283 | compat_ptr(data)); |
349 | break; | ||
350 | } | ||
351 | CHECK_FULL_REGS(child->thread.regs); | ||
352 | ret = 0; | ||
353 | for (ui = 0; ui < PT_REGS_COUNT; ui ++) { | ||
354 | ret |= __put_user(ptrace_get_reg(child, ui), | ||
355 | (unsigned int __user *) data); | ||
356 | data += sizeof(int); | ||
357 | } | ||
358 | break; | ||
359 | } | ||
360 | |||
361 | case PTRACE_SETREGS: { /* Set all gp regs in the child. */ | ||
362 | unsigned long tmp; | ||
363 | int ui; | ||
364 | if (!access_ok(VERIFY_READ, (void __user *)data, | ||
365 | PT_REGS_COUNT * sizeof(int))) { | ||
366 | ret = -EIO; | ||
367 | break; | ||
368 | } | ||
369 | CHECK_FULL_REGS(child->thread.regs); | ||
370 | ret = 0; | ||
371 | for (ui = 0; ui < PT_REGS_COUNT; ui ++) { | ||
372 | ret = __get_user(tmp, (unsigned int __user *) data); | ||
373 | if (ret) | ||
374 | break; | ||
375 | ptrace_put_reg(child, ui, tmp); | ||
376 | data += sizeof(int); | ||
377 | } | ||
378 | break; | ||
379 | } | ||
380 | 284 | ||
381 | case PTRACE_GETFPREGS: | 285 | case PTRACE_GETFPREGS: |
382 | case PTRACE_SETFPREGS: | 286 | case PTRACE_SETFPREGS: |
@@ -402,12 +306,9 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, | |||
402 | break; | 306 | break; |
403 | 307 | ||
404 | default: | 308 | default: |
405 | ret = ptrace_request(child, request, addr, data); | 309 | ret = compat_ptrace_request(child, request, addr, data); |
406 | break; | 310 | break; |
407 | } | 311 | } |
408 | out_tsk: | 312 | |
409 | put_task_struct(child); | ||
410 | out: | ||
411 | unlock_kernel(); | ||
412 | return ret; | 313 | return ret; |
413 | } | 314 | } |