diff options
Diffstat (limited to 'arch/sparc64/kernel/ptrace.c')
-rw-r--r-- | arch/sparc64/kernel/ptrace.c | 202 |
1 files changed, 171 insertions, 31 deletions
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index aaae865e7932..e9fc0aa2da38 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c | |||
@@ -114,6 +114,85 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, | |||
114 | preempt_enable(); | 114 | preempt_enable(); |
115 | } | 115 | } |
116 | 116 | ||
117 | static int get_from_target(struct task_struct *target, unsigned long uaddr, | ||
118 | void *kbuf, int len) | ||
119 | { | ||
120 | if (target == current) { | ||
121 | if (copy_from_user(kbuf, (void __user *) uaddr, len)) | ||
122 | return -EFAULT; | ||
123 | } else { | ||
124 | int len2 = access_process_vm(target, uaddr, kbuf, len, 0); | ||
125 | if (len2 != len) | ||
126 | return -EFAULT; | ||
127 | } | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int set_to_target(struct task_struct *target, unsigned long uaddr, | ||
132 | void *kbuf, int len) | ||
133 | { | ||
134 | if (target == current) { | ||
135 | if (copy_to_user((void __user *) uaddr, kbuf, len)) | ||
136 | return -EFAULT; | ||
137 | } else { | ||
138 | int len2 = access_process_vm(target, uaddr, kbuf, len, 1); | ||
139 | if (len2 != len) | ||
140 | return -EFAULT; | ||
141 | } | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static int regwindow64_get(struct task_struct *target, | ||
146 | const struct pt_regs *regs, | ||
147 | struct reg_window *wbuf) | ||
148 | { | ||
149 | unsigned long rw_addr = regs->u_regs[UREG_I6]; | ||
150 | |||
151 | if (test_tsk_thread_flag(current, TIF_32BIT)) { | ||
152 | struct reg_window32 win32; | ||
153 | int i; | ||
154 | |||
155 | if (get_from_target(target, rw_addr, &win32, sizeof(win32))) | ||
156 | return -EFAULT; | ||
157 | for (i = 0; i < 8; i++) | ||
158 | wbuf->locals[i] = win32.locals[i]; | ||
159 | for (i = 0; i < 8; i++) | ||
160 | wbuf->ins[i] = win32.ins[i]; | ||
161 | } else { | ||
162 | rw_addr += STACK_BIAS; | ||
163 | if (get_from_target(target, rw_addr, wbuf, sizeof(*wbuf))) | ||
164 | return -EFAULT; | ||
165 | } | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | static int regwindow64_set(struct task_struct *target, | ||
171 | const struct pt_regs *regs, | ||
172 | struct reg_window *wbuf) | ||
173 | { | ||
174 | unsigned long rw_addr = regs->u_regs[UREG_I6]; | ||
175 | |||
176 | if (test_tsk_thread_flag(current, TIF_32BIT)) { | ||
177 | struct reg_window32 win32; | ||
178 | int i; | ||
179 | |||
180 | for (i = 0; i < 8; i++) | ||
181 | win32.locals[i] = wbuf->locals[i]; | ||
182 | for (i = 0; i < 8; i++) | ||
183 | win32.ins[i] = wbuf->ins[i]; | ||
184 | |||
185 | if (set_to_target(target, rw_addr, &win32, sizeof(win32))) | ||
186 | return -EFAULT; | ||
187 | } else { | ||
188 | rw_addr += STACK_BIAS; | ||
189 | if (set_to_target(target, rw_addr, wbuf, sizeof(*wbuf))) | ||
190 | return -EFAULT; | ||
191 | } | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
117 | enum sparc_regset { | 196 | enum sparc_regset { |
118 | REGSET_GENERAL, | 197 | REGSET_GENERAL, |
119 | REGSET_FP, | 198 | REGSET_FP, |
@@ -133,16 +212,13 @@ static int genregs64_get(struct task_struct *target, | |||
133 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | 212 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
134 | regs->u_regs, | 213 | regs->u_regs, |
135 | 0, 16 * sizeof(u64)); | 214 | 0, 16 * sizeof(u64)); |
136 | if (!ret) { | 215 | if (!ret && count && pos < (32 * sizeof(u64))) { |
137 | unsigned long __user *reg_window = (unsigned long __user *) | 216 | struct reg_window window; |
138 | (regs->u_regs[UREG_I6] + STACK_BIAS); | ||
139 | unsigned long window[16]; | ||
140 | 217 | ||
141 | if (copy_from_user(window, reg_window, sizeof(window))) | 218 | if (regwindow64_get(target, regs, &window)) |
142 | return -EFAULT; | 219 | return -EFAULT; |
143 | |||
144 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | 220 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
145 | window, | 221 | &window, |
146 | 16 * sizeof(u64), | 222 | 16 * sizeof(u64), |
147 | 32 * sizeof(u64)); | 223 | 32 * sizeof(u64)); |
148 | } | 224 | } |
@@ -164,10 +240,11 @@ static int genregs64_get(struct task_struct *target, | |||
164 | 36 * sizeof(u64)); | 240 | 36 * sizeof(u64)); |
165 | } | 241 | } |
166 | 242 | ||
167 | if (!ret) | 243 | if (!ret) { |
168 | ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, | 244 | ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, |
169 | 36 * sizeof(u64), -1); | 245 | 36 * sizeof(u64), -1); |
170 | 246 | ||
247 | } | ||
171 | return ret; | 248 | return ret; |
172 | } | 249 | } |
173 | 250 | ||
@@ -185,20 +262,19 @@ static int genregs64_set(struct task_struct *target, | |||
185 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | 262 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, |
186 | regs->u_regs, | 263 | regs->u_regs, |
187 | 0, 16 * sizeof(u64)); | 264 | 0, 16 * sizeof(u64)); |
188 | if (!ret && count > 0) { | 265 | if (!ret && count && pos < (32 * sizeof(u64))) { |
189 | unsigned long __user *reg_window = (unsigned long __user *) | 266 | struct reg_window window; |
190 | (regs->u_regs[UREG_I6] + STACK_BIAS); | ||
191 | unsigned long window[16]; | ||
192 | 267 | ||
193 | if (copy_from_user(window, reg_window, sizeof(window))) | 268 | if (regwindow64_get(target, regs, &window)) |
194 | return -EFAULT; | 269 | return -EFAULT; |
195 | 270 | ||
196 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | 271 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, |
197 | window, | 272 | &window, |
198 | 16 * sizeof(u64), | 273 | 16 * sizeof(u64), |
199 | 32 * sizeof(u64)); | 274 | 32 * sizeof(u64)); |
275 | |||
200 | if (!ret && | 276 | if (!ret && |
201 | copy_to_user(reg_window, window, sizeof(window))) | 277 | regwindow64_set(target, regs, &window)) |
202 | return -EFAULT; | 278 | return -EFAULT; |
203 | } | 279 | } |
204 | 280 | ||
@@ -412,9 +488,22 @@ static int genregs32_get(struct task_struct *target, | |||
412 | *k++ = regs->u_regs[pos++]; | 488 | *k++ = regs->u_regs[pos++]; |
413 | 489 | ||
414 | reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; | 490 | reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; |
415 | for (; count > 0 && pos < 32; count--) { | 491 | if (target == current) { |
416 | if (get_user(*k++, ®_window[pos++])) | 492 | for (; count > 0 && pos < 32; count--) { |
417 | return -EFAULT; | 493 | if (get_user(*k++, ®_window[pos++])) |
494 | return -EFAULT; | ||
495 | } | ||
496 | } else { | ||
497 | for (; count > 0 && pos < 32; count--) { | ||
498 | if (access_process_vm(target, | ||
499 | (unsigned long) | ||
500 | ®_window[pos], | ||
501 | k, sizeof(*k), 0) | ||
502 | != sizeof(*k)) | ||
503 | return -EFAULT; | ||
504 | k++; | ||
505 | pos++; | ||
506 | } | ||
418 | } | 507 | } |
419 | } else { | 508 | } else { |
420 | for (; count > 0 && pos < 16; count--) { | 509 | for (; count > 0 && pos < 16; count--) { |
@@ -423,10 +512,28 @@ static int genregs32_get(struct task_struct *target, | |||
423 | } | 512 | } |
424 | 513 | ||
425 | reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; | 514 | reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; |
426 | for (; count > 0 && pos < 32; count--) { | 515 | if (target == current) { |
427 | if (get_user(reg, ®_window[pos++]) || | 516 | for (; count > 0 && pos < 32; count--) { |
428 | put_user(reg, u++)) | 517 | if (get_user(reg, ®_window[pos++]) || |
429 | return -EFAULT; | 518 | put_user(reg, u++)) |
519 | return -EFAULT; | ||
520 | } | ||
521 | } else { | ||
522 | for (; count > 0 && pos < 32; count--) { | ||
523 | if (access_process_vm(target, | ||
524 | (unsigned long) | ||
525 | ®_window[pos], | ||
526 | ®, sizeof(reg), 0) | ||
527 | != sizeof(reg)) | ||
528 | return -EFAULT; | ||
529 | if (access_process_vm(target, | ||
530 | (unsigned long) u, | ||
531 | ®, sizeof(reg), 1) | ||
532 | != sizeof(reg)) | ||
533 | return -EFAULT; | ||
534 | pos++; | ||
535 | u++; | ||
536 | } | ||
430 | } | 537 | } |
431 | } | 538 | } |
432 | while (count > 0) { | 539 | while (count > 0) { |
@@ -488,9 +595,23 @@ static int genregs32_set(struct task_struct *target, | |||
488 | regs->u_regs[pos++] = *k++; | 595 | regs->u_regs[pos++] = *k++; |
489 | 596 | ||
490 | reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; | 597 | reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; |
491 | for (; count > 0 && pos < 32; count--) { | 598 | if (target == current) { |
492 | if (put_user(*k++, ®_window[pos++])) | 599 | for (; count > 0 && pos < 32; count--) { |
493 | return -EFAULT; | 600 | if (put_user(*k++, ®_window[pos++])) |
601 | return -EFAULT; | ||
602 | } | ||
603 | } else { | ||
604 | for (; count > 0 && pos < 32; count--) { | ||
605 | if (access_process_vm(target, | ||
606 | (unsigned long) | ||
607 | ®_window[pos], | ||
608 | (void *) k, | ||
609 | sizeof(*k), 1) | ||
610 | != sizeof(*k)) | ||
611 | return -EFAULT; | ||
612 | k++; | ||
613 | pos++; | ||
614 | } | ||
494 | } | 615 | } |
495 | } else { | 616 | } else { |
496 | for (; count > 0 && pos < 16; count--) { | 617 | for (; count > 0 && pos < 16; count--) { |
@@ -500,10 +621,29 @@ static int genregs32_set(struct task_struct *target, | |||
500 | } | 621 | } |
501 | 622 | ||
502 | reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; | 623 | reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; |
503 | for (; count > 0 && pos < 32; count--) { | 624 | if (target == current) { |
504 | if (get_user(reg, u++) || | 625 | for (; count > 0 && pos < 32; count--) { |
505 | put_user(reg, ®_window[pos++])) | 626 | if (get_user(reg, u++) || |
506 | return -EFAULT; | 627 | put_user(reg, ®_window[pos++])) |
628 | return -EFAULT; | ||
629 | } | ||
630 | } else { | ||
631 | for (; count > 0 && pos < 32; count--) { | ||
632 | if (access_process_vm(target, | ||
633 | (unsigned long) | ||
634 | u, | ||
635 | ®, sizeof(reg), 0) | ||
636 | != sizeof(reg)) | ||
637 | return -EFAULT; | ||
638 | if (access_process_vm(target, | ||
639 | (unsigned long) | ||
640 | ®_window[pos], | ||
641 | ®, sizeof(reg), 1) | ||
642 | != sizeof(reg)) | ||
643 | return -EFAULT; | ||
644 | pos++; | ||
645 | u++; | ||
646 | } | ||
507 | } | 647 | } |
508 | } | 648 | } |
509 | while (count > 0) { | 649 | while (count > 0) { |
@@ -711,7 +851,7 @@ struct compat_fps { | |||
711 | long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | 851 | long compat_arch_ptrace(struct task_struct *child, compat_long_t request, |
712 | compat_ulong_t caddr, compat_ulong_t cdata) | 852 | compat_ulong_t caddr, compat_ulong_t cdata) |
713 | { | 853 | { |
714 | const struct user_regset_view *view = task_user_regset_view(child); | 854 | const struct user_regset_view *view = task_user_regset_view(current); |
715 | compat_ulong_t caddr2 = task_pt_regs(current)->u_regs[UREG_I4]; | 855 | compat_ulong_t caddr2 = task_pt_regs(current)->u_regs[UREG_I4]; |
716 | struct pt_regs32 __user *pregs; | 856 | struct pt_regs32 __user *pregs; |
717 | struct compat_fps __user *fps; | 857 | struct compat_fps __user *fps; |
@@ -819,7 +959,7 @@ struct fps { | |||
819 | 959 | ||
820 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) | 960 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) |
821 | { | 961 | { |
822 | const struct user_regset_view *view = task_user_regset_view(child); | 962 | const struct user_regset_view *view = task_user_regset_view(current); |
823 | unsigned long addr2 = task_pt_regs(current)->u_regs[UREG_I4]; | 963 | unsigned long addr2 = task_pt_regs(current)->u_regs[UREG_I4]; |
824 | struct pt_regs __user *pregs; | 964 | struct pt_regs __user *pregs; |
825 | struct fps __user *fps; | 965 | struct fps __user *fps; |