aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/ptrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/kernel/ptrace.c')
-rw-r--r--arch/sparc64/kernel/ptrace.c222
1 files changed, 189 insertions, 33 deletions
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
index 9a1ba1fe859d..e9fc0aa2da38 100644
--- a/arch/sparc64/kernel/ptrace.c
+++ b/arch/sparc64/kernel/ptrace.c
@@ -35,6 +35,9 @@
35#include <asm/spitfire.h> 35#include <asm/spitfire.h>
36#include <asm/page.h> 36#include <asm/page.h>
37#include <asm/cpudata.h> 37#include <asm/cpudata.h>
38#include <asm/cacheflush.h>
39
40#include "entry.h"
38 41
39/* #define ALLOW_INIT_TRACING */ 42/* #define ALLOW_INIT_TRACING */
40 43
@@ -67,6 +70,8 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
67 if (tlb_type == hypervisor) 70 if (tlb_type == hypervisor)
68 return; 71 return;
69 72
73 preempt_disable();
74
70#ifdef DCACHE_ALIASING_POSSIBLE 75#ifdef DCACHE_ALIASING_POSSIBLE
71 /* If bit 13 of the kernel address we used to access the 76 /* If bit 13 of the kernel address we used to access the
72 * user page is the same as the virtual address that page 77 * user page is the same as the virtual address that page
@@ -105,6 +110,87 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
105 for (; start < end; start += icache_line_size) 110 for (; start < end; start += icache_line_size)
106 flushi(start); 111 flushi(start);
107 } 112 }
113
114 preempt_enable();
115}
116
117static 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
131static 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
145static 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
170static 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;
108} 194}
109 195
110enum sparc_regset { 196enum sparc_regset {
@@ -126,16 +212,13 @@ static int genregs64_get(struct task_struct *target,
126 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, 212 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
127 regs->u_regs, 213 regs->u_regs,
128 0, 16 * sizeof(u64)); 214 0, 16 * sizeof(u64));
129 if (!ret) { 215 if (!ret && count && pos < (32 * sizeof(u64))) {
130 unsigned long __user *reg_window = (unsigned long __user *) 216 struct reg_window window;
131 (regs->u_regs[UREG_I6] + STACK_BIAS);
132 unsigned long window[16];
133 217
134 if (copy_from_user(window, reg_window, sizeof(window))) 218 if (regwindow64_get(target, regs, &window))
135 return -EFAULT; 219 return -EFAULT;
136
137 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, 220 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
138 window, 221 &window,
139 16 * sizeof(u64), 222 16 * sizeof(u64),
140 32 * sizeof(u64)); 223 32 * sizeof(u64));
141 } 224 }
@@ -157,10 +240,11 @@ static int genregs64_get(struct task_struct *target,
157 36 * sizeof(u64)); 240 36 * sizeof(u64));
158 } 241 }
159 242
160 if (!ret) 243 if (!ret) {
161 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 244 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
162 36 * sizeof(u64), -1); 245 36 * sizeof(u64), -1);
163 246
247 }
164 return ret; 248 return ret;
165} 249}
166 250
@@ -178,20 +262,19 @@ static int genregs64_set(struct task_struct *target,
178 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 262 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
179 regs->u_regs, 263 regs->u_regs,
180 0, 16 * sizeof(u64)); 264 0, 16 * sizeof(u64));
181 if (!ret && count > 0) { 265 if (!ret && count && pos < (32 * sizeof(u64))) {
182 unsigned long __user *reg_window = (unsigned long __user *) 266 struct reg_window window;
183 (regs->u_regs[UREG_I6] + STACK_BIAS);
184 unsigned long window[16];
185 267
186 if (copy_from_user(window, reg_window, sizeof(window))) 268 if (regwindow64_get(target, regs, &window))
187 return -EFAULT; 269 return -EFAULT;
188 270
189 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 271 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
190 window, 272 &window,
191 16 * sizeof(u64), 273 16 * sizeof(u64),
192 32 * sizeof(u64)); 274 32 * sizeof(u64));
275
193 if (!ret && 276 if (!ret &&
194 copy_to_user(reg_window, window, sizeof(window))) 277 regwindow64_set(target, regs, &window))
195 return -EFAULT; 278 return -EFAULT;
196 } 279 }
197 280
@@ -382,6 +465,7 @@ static const struct user_regset_view user_sparc64_view = {
382 .regsets = sparc64_regsets, .n = ARRAY_SIZE(sparc64_regsets) 465 .regsets = sparc64_regsets, .n = ARRAY_SIZE(sparc64_regsets)
383}; 466};
384 467
468#ifdef CONFIG_COMPAT
385static int genregs32_get(struct task_struct *target, 469static int genregs32_get(struct task_struct *target,
386 const struct user_regset *regset, 470 const struct user_regset *regset,
387 unsigned int pos, unsigned int count, 471 unsigned int pos, unsigned int count,
@@ -404,9 +488,22 @@ static int genregs32_get(struct task_struct *target,
404 *k++ = regs->u_regs[pos++]; 488 *k++ = regs->u_regs[pos++];
405 489
406 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; 490 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
407 for (; count > 0 && pos < 32; count--) { 491 if (target == current) {
408 if (get_user(*k++, &reg_window[pos++])) 492 for (; count > 0 && pos < 32; count--) {
409 return -EFAULT; 493 if (get_user(*k++, &reg_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 &reg_window[pos],
501 k, sizeof(*k), 0)
502 != sizeof(*k))
503 return -EFAULT;
504 k++;
505 pos++;
506 }
410 } 507 }
411 } else { 508 } else {
412 for (; count > 0 && pos < 16; count--) { 509 for (; count > 0 && pos < 16; count--) {
@@ -415,10 +512,28 @@ static int genregs32_get(struct task_struct *target,
415 } 512 }
416 513
417 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; 514 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
418 for (; count > 0 && pos < 32; count--) { 515 if (target == current) {
419 if (get_user(reg, &reg_window[pos++]) || 516 for (; count > 0 && pos < 32; count--) {
420 put_user(reg, u++)) 517 if (get_user(reg, &reg_window[pos++]) ||
421 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 &reg_window[pos],
526 &reg, sizeof(reg), 0)
527 != sizeof(reg))
528 return -EFAULT;
529 if (access_process_vm(target,
530 (unsigned long) u,
531 &reg, sizeof(reg), 1)
532 != sizeof(reg))
533 return -EFAULT;
534 pos++;
535 u++;
536 }
422 } 537 }
423 } 538 }
424 while (count > 0) { 539 while (count > 0) {
@@ -480,9 +595,23 @@ static int genregs32_set(struct task_struct *target,
480 regs->u_regs[pos++] = *k++; 595 regs->u_regs[pos++] = *k++;
481 596
482 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; 597 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
483 for (; count > 0 && pos < 32; count--) { 598 if (target == current) {
484 if (put_user(*k++, &reg_window[pos++])) 599 for (; count > 0 && pos < 32; count--) {
485 return -EFAULT; 600 if (put_user(*k++, &reg_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 &reg_window[pos],
608 (void *) k,
609 sizeof(*k), 1)
610 != sizeof(*k))
611 return -EFAULT;
612 k++;
613 pos++;
614 }
486 } 615 }
487 } else { 616 } else {
488 for (; count > 0 && pos < 16; count--) { 617 for (; count > 0 && pos < 16; count--) {
@@ -492,10 +621,29 @@ static int genregs32_set(struct task_struct *target,
492 } 621 }
493 622
494 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; 623 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
495 for (; count > 0 && pos < 32; count--) { 624 if (target == current) {
496 if (get_user(reg, u++) || 625 for (; count > 0 && pos < 32; count--) {
497 put_user(reg, &reg_window[pos++])) 626 if (get_user(reg, u++) ||
498 return -EFAULT; 627 put_user(reg, &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 &reg, sizeof(reg), 0)
636 != sizeof(reg))
637 return -EFAULT;
638 if (access_process_vm(target,
639 (unsigned long)
640 &reg_window[pos],
641 &reg, sizeof(reg), 1)
642 != sizeof(reg))
643 return -EFAULT;
644 pos++;
645 u++;
646 }
499 } 647 }
500 } 648 }
501 while (count > 0) { 649 while (count > 0) {
@@ -676,14 +824,18 @@ static const struct user_regset_view user_sparc32_view = {
676 .name = "sparc", .e_machine = EM_SPARC, 824 .name = "sparc", .e_machine = EM_SPARC,
677 .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets) 825 .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
678}; 826};
827#endif /* CONFIG_COMPAT */
679 828
680const struct user_regset_view *task_user_regset_view(struct task_struct *task) 829const struct user_regset_view *task_user_regset_view(struct task_struct *task)
681{ 830{
831#ifdef CONFIG_COMPAT
682 if (test_tsk_thread_flag(task, TIF_32BIT)) 832 if (test_tsk_thread_flag(task, TIF_32BIT))
683 return &user_sparc32_view; 833 return &user_sparc32_view;
834#endif
684 return &user_sparc64_view; 835 return &user_sparc64_view;
685} 836}
686 837
838#ifdef CONFIG_COMPAT
687struct compat_fps { 839struct compat_fps {
688 unsigned int regs[32]; 840 unsigned int regs[32];
689 unsigned int fsr; 841 unsigned int fsr;
@@ -699,7 +851,7 @@ struct compat_fps {
699long compat_arch_ptrace(struct task_struct *child, compat_long_t request, 851long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
700 compat_ulong_t caddr, compat_ulong_t cdata) 852 compat_ulong_t caddr, compat_ulong_t cdata)
701{ 853{
702 const struct user_regset_view *view = task_user_regset_view(child); 854 const struct user_regset_view *view = task_user_regset_view(current);
703 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];
704 struct pt_regs32 __user *pregs; 856 struct pt_regs32 __user *pregs;
705 struct compat_fps __user *fps; 857 struct compat_fps __user *fps;
@@ -798,6 +950,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
798 950
799 return ret; 951 return ret;
800} 952}
953#endif /* CONFIG_COMPAT */
801 954
802struct fps { 955struct fps {
803 unsigned int regs[64]; 956 unsigned int regs[64];
@@ -806,12 +959,15 @@ struct fps {
806 959
807long arch_ptrace(struct task_struct *child, long request, long addr, long data) 960long arch_ptrace(struct task_struct *child, long request, long addr, long data)
808{ 961{
809 const struct user_regset_view *view = task_user_regset_view(child); 962 const struct user_regset_view *view = task_user_regset_view(current);
810 struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
811 unsigned long addr2 = task_pt_regs(current)->u_regs[UREG_I4]; 963 unsigned long addr2 = task_pt_regs(current)->u_regs[UREG_I4];
812 struct fps __user *fps = (struct fps __user *) addr; 964 struct pt_regs __user *pregs;
965 struct fps __user *fps;
813 int ret; 966 int ret;
814 967
968 pregs = (struct pt_regs __user *) (unsigned long) addr;
969 fps = (struct fps __user *) (unsigned long) addr;
970
815 switch (request) { 971 switch (request) {
816 case PTRACE_PEEKUSR: 972 case PTRACE_PEEKUSR:
817 ret = (addr != 0) ? -EIO : 0; 973 ret = (addr != 0) ? -EIO : 0;