aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-02-07 06:00:17 -0500
committerDavid S. Miller <davem@davemloft.net>2008-02-07 06:00:17 -0500
commit9775369ec06bad8edb2fbd8c77316f49b439c225 (patch)
tree14b0cb23d5fad3dbd99da0e21cf1b7e3db92595f /arch/sparc/kernel
parent190aa9f60f9575d1b7382cd1ee33e2589208c514 (diff)
[SPARC]: Move over to arch_ptrace().
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/kernel')
-rw-r--r--arch/sparc/kernel/entry.S17
-rw-r--r--arch/sparc/kernel/ptrace.c462
2 files changed, 63 insertions, 416 deletions
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
index 88d2cefd01be..c2eed8f71516 100644
--- a/arch/sparc/kernel/entry.S
+++ b/arch/sparc/kernel/entry.S
@@ -1224,23 +1224,6 @@ sys_nis_syscall:
1224 call c_sys_nis_syscall 1224 call c_sys_nis_syscall
1225 mov %l5, %o7 1225 mov %l5, %o7
1226 1226
1227 .align 4
1228 .globl sys_ptrace
1229sys_ptrace:
1230 call do_ptrace
1231 add %sp, STACKFRAME_SZ, %o0
1232
1233 ld [%curptr + TI_FLAGS], %l5
1234 andcc %l5, _TIF_SYSCALL_TRACE, %g0
1235 be 1f
1236 nop
1237
1238 call syscall_trace
1239 nop
1240
12411:
1242 RESTORE_ALL
1243
1244 .align 4 1227 .align 4
1245 .globl sys_execve 1228 .globl sys_execve
1246sys_execve: 1229sys_execve:
diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c
index 29fa6e5cb450..1c0d5363f720 100644
--- a/arch/sparc/kernel/ptrace.c
+++ b/arch/sparc/kernel/ptrace.c
@@ -26,215 +26,6 @@
26#include <asm/system.h> 26#include <asm/system.h>
27#include <asm/uaccess.h> 27#include <asm/uaccess.h>
28 28
29#define MAGIC_CONSTANT 0x80000000
30
31
32/* Returning from ptrace is a bit tricky because the syscall return
33 * low level code assumes any value returned which is negative and
34 * is a valid errno will mean setting the condition codes to indicate
35 * an error return. This doesn't work, so we have this hook.
36 */
37static inline void pt_error_return(struct pt_regs *regs, unsigned long error)
38{
39 regs->u_regs[UREG_I0] = error;
40 regs->psr |= PSR_C;
41 regs->pc = regs->npc;
42 regs->npc += 4;
43}
44
45static inline void pt_succ_return(struct pt_regs *regs, unsigned long value)
46{
47 regs->u_regs[UREG_I0] = value;
48 regs->psr &= ~PSR_C;
49 regs->pc = regs->npc;
50 regs->npc += 4;
51}
52
53static void
54pt_succ_return_linux(struct pt_regs *regs, unsigned long value, long __user *addr)
55{
56 if (put_user(value, addr)) {
57 pt_error_return(regs, EFAULT);
58 return;
59 }
60 regs->u_regs[UREG_I0] = 0;
61 regs->psr &= ~PSR_C;
62 regs->pc = regs->npc;
63 regs->npc += 4;
64}
65
66static void
67pt_os_succ_return (struct pt_regs *regs, unsigned long val, long __user *addr)
68{
69 if (current->personality == PER_SUNOS)
70 pt_succ_return (regs, val);
71 else
72 pt_succ_return_linux (regs, val, addr);
73}
74
75/* Fuck me gently with a chainsaw... */
76static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset,
77 struct task_struct *tsk, long __user *addr)
78{
79 struct pt_regs *cregs = tsk->thread.kregs;
80 struct thread_info *t = task_thread_info(tsk);
81 int v;
82
83 if(offset >= 1024)
84 offset -= 1024; /* whee... */
85 if(offset & ((sizeof(unsigned long) - 1))) {
86 pt_error_return(regs, EIO);
87 return;
88 }
89 if(offset >= 16 && offset < 784) {
90 offset -= 16; offset >>= 2;
91 pt_os_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset), addr);
92 return;
93 }
94 if(offset >= 784 && offset < 832) {
95 offset -= 784; offset >>= 2;
96 pt_os_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset), addr);
97 return;
98 }
99 switch(offset) {
100 case 0:
101 v = t->ksp;
102 break;
103 case 4:
104 v = t->kpc;
105 break;
106 case 8:
107 v = t->kpsr;
108 break;
109 case 12:
110 v = t->uwinmask;
111 break;
112 case 832:
113 v = t->w_saved;
114 break;
115 case 896:
116 v = cregs->u_regs[UREG_I0];
117 break;
118 case 900:
119 v = cregs->u_regs[UREG_I1];
120 break;
121 case 904:
122 v = cregs->u_regs[UREG_I2];
123 break;
124 case 908:
125 v = cregs->u_regs[UREG_I3];
126 break;
127 case 912:
128 v = cregs->u_regs[UREG_I4];
129 break;
130 case 916:
131 v = cregs->u_regs[UREG_I5];
132 break;
133 case 920:
134 v = cregs->u_regs[UREG_I6];
135 break;
136 case 924:
137 if(tsk->thread.flags & MAGIC_CONSTANT)
138 v = cregs->u_regs[UREG_G1];
139 else
140 v = 0;
141 break;
142 case 940:
143 v = cregs->u_regs[UREG_I0];
144 break;
145 case 944:
146 v = cregs->u_regs[UREG_I1];
147 break;
148
149 case 948:
150 /* Isn't binary compatibility _fun_??? */
151 if(cregs->psr & PSR_C)
152 v = cregs->u_regs[UREG_I0] << 24;
153 else
154 v = 0;
155 break;
156
157 /* Rest of them are completely unsupported. */
158 default:
159 printk("%s [%d]: Wants to read user offset %ld\n",
160 current->comm, task_pid_nr(current), offset);
161 pt_error_return(regs, EIO);
162 return;
163 }
164 if (current->personality == PER_SUNOS)
165 pt_succ_return (regs, v);
166 else
167 pt_succ_return_linux (regs, v, addr);
168 return;
169}
170
171static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset,
172 struct task_struct *tsk)
173{
174 struct pt_regs *cregs = tsk->thread.kregs;
175 struct thread_info *t = task_thread_info(tsk);
176 unsigned long value = regs->u_regs[UREG_I3];
177
178 if(offset >= 1024)
179 offset -= 1024; /* whee... */
180 if(offset & ((sizeof(unsigned long) - 1)))
181 goto failure;
182 if(offset >= 16 && offset < 784) {
183 offset -= 16; offset >>= 2;
184 *(((unsigned long *)(&t->reg_window[0]))+offset) = value;
185 goto success;
186 }
187 if(offset >= 784 && offset < 832) {
188 offset -= 784; offset >>= 2;
189 *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value;
190 goto success;
191 }
192 switch(offset) {
193 case 896:
194 cregs->u_regs[UREG_I0] = value;
195 break;
196 case 900:
197 cregs->u_regs[UREG_I1] = value;
198 break;
199 case 904:
200 cregs->u_regs[UREG_I2] = value;
201 break;
202 case 908:
203 cregs->u_regs[UREG_I3] = value;
204 break;
205 case 912:
206 cregs->u_regs[UREG_I4] = value;
207 break;
208 case 916:
209 cregs->u_regs[UREG_I5] = value;
210 break;
211 case 920:
212 cregs->u_regs[UREG_I6] = value;
213 break;
214 case 924:
215 cregs->u_regs[UREG_I7] = value;
216 break;
217 case 940:
218 cregs->u_regs[UREG_I0] = value;
219 break;
220 case 944:
221 cregs->u_regs[UREG_I1] = value;
222 break;
223
224 /* Rest of them are completely unsupported or "no-touch". */
225 default:
226 printk("%s [%d]: Wants to write user offset %ld\n",
227 current->comm, task_pid_nr(current), offset);
228 goto failure;
229 }
230success:
231 pt_succ_return(regs, 0);
232 return;
233failure:
234 pt_error_return(regs, EIO);
235 return;
236}
237
238/* #define ALLOW_INIT_TRACING */ 29/* #define ALLOW_INIT_TRACING */
239 30
240/* 31/*
@@ -528,113 +319,42 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task)
528 return &user_sparc32_view; 319 return &user_sparc32_view;
529} 320}
530 321
531asmlinkage void do_ptrace(struct pt_regs *regs) 322long arch_ptrace(struct task_struct *child, long request, long addr, long data)
532{ 323{
533 unsigned long request = regs->u_regs[UREG_I0]; 324 unsigned long addr2 = current->thread.kregs->u_regs[UREG_I4];
534 unsigned long pid = regs->u_regs[UREG_I1]; 325 int i, ret;
535 unsigned long addr = regs->u_regs[UREG_I2];
536 unsigned long data = regs->u_regs[UREG_I3];
537 unsigned long addr2 = regs->u_regs[UREG_I4];
538 struct task_struct *child;
539 int ret;
540
541 lock_kernel();
542
543 if (request == PTRACE_TRACEME) {
544 ret = ptrace_traceme();
545 if (ret < 0)
546 pt_error_return(regs, -ret);
547 else
548 pt_succ_return(regs, 0);
549 goto out;
550 }
551
552 child = ptrace_get_task_struct(pid);
553 if (IS_ERR(child)) {
554 ret = PTR_ERR(child);
555 pt_error_return(regs, -ret);
556 goto out;
557 }
558
559 if (request == PTRACE_ATTACH) {
560 if (ptrace_attach(child)) {
561 pt_error_return(regs, EPERM);
562 goto out_tsk;
563 }
564 pt_succ_return(regs, 0);
565 goto out_tsk;
566 }
567
568 ret = ptrace_check_attach(child, request == PTRACE_KILL);
569 if (ret < 0) {
570 pt_error_return(regs, -ret);
571 goto out_tsk;
572 }
573 326
574 switch(request) { 327 switch(request) {
575 case PTRACE_PEEKTEXT: /* read word at location addr. */
576 case PTRACE_PEEKDATA: {
577 unsigned long tmp;
578
579 if (access_process_vm(child, addr,
580 &tmp, sizeof(tmp), 0) == sizeof(tmp))
581 pt_os_succ_return(regs, tmp, (long __user *)data);
582 else
583 pt_error_return(regs, EIO);
584 goto out_tsk;
585 }
586
587 case PTRACE_PEEKUSR:
588 read_sunos_user(regs, addr, child, (long __user *) data);
589 goto out_tsk;
590
591 case PTRACE_POKEUSR:
592 write_sunos_user(regs, addr, child);
593 goto out_tsk;
594
595 case PTRACE_POKETEXT: /* write the word at location addr. */
596 case PTRACE_POKEDATA: {
597 if (access_process_vm(child, addr,
598 &data, sizeof(data), 1) == sizeof(data))
599 pt_succ_return(regs, 0);
600 else
601 pt_error_return(regs, EIO);
602 goto out_tsk;
603 }
604
605 case PTRACE_GETREGS: { 328 case PTRACE_GETREGS: {
606 struct pt_regs __user *pregs = (struct pt_regs __user *) addr; 329 struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
607 struct pt_regs *cregs = child->thread.kregs; 330 struct pt_regs *cregs = child->thread.kregs;
608 int rval;
609 331
610 if (!access_ok(VERIFY_WRITE, pregs, sizeof(struct pt_regs))) { 332 ret = -EFAULT;
611 rval = -EFAULT; 333 if (!access_ok(VERIFY_WRITE, pregs, sizeof(struct pt_regs)))
612 pt_error_return(regs, -rval); 334 break;
613 goto out_tsk; 335
614 }
615 __put_user(cregs->psr, (&pregs->psr)); 336 __put_user(cregs->psr, (&pregs->psr));
616 __put_user(cregs->pc, (&pregs->pc)); 337 __put_user(cregs->pc, (&pregs->pc));
617 __put_user(cregs->npc, (&pregs->npc)); 338 __put_user(cregs->npc, (&pregs->npc));
618 __put_user(cregs->y, (&pregs->y)); 339 __put_user(cregs->y, (&pregs->y));
619 for(rval = 1; rval < 16; rval++) 340 for (i = 1; i < 16; i++)
620 __put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1])); 341 __put_user(cregs->u_regs[i], &pregs->u_regs[i - 1]);
621 pt_succ_return(regs, 0); 342 ret = 0;
622 goto out_tsk; 343 break;
623 } 344 }
624 345
625 case PTRACE_SETREGS: { 346 case PTRACE_SETREGS: {
626 struct pt_regs __user *pregs = (struct pt_regs __user *) addr; 347 struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
627 struct pt_regs *cregs = child->thread.kregs; 348 struct pt_regs *cregs = child->thread.kregs;
628 unsigned long psr, pc, npc, y; 349 unsigned long psr, pc, npc, y;
629 int i;
630 350
631 /* Must be careful, tracing process can only set certain 351 /* Must be careful, tracing process can only set certain
632 * bits in the psr. 352 * bits in the psr.
633 */ 353 */
634 if (!access_ok(VERIFY_READ, pregs, sizeof(struct pt_regs))) { 354 ret = -EFAULT;
635 pt_error_return(regs, EFAULT); 355 if (!access_ok(VERIFY_READ, pregs, sizeof(struct pt_regs)))
636 goto out_tsk; 356 break;
637 } 357
638 __get_user(psr, (&pregs->psr)); 358 __get_user(psr, (&pregs->psr));
639 __get_user(pc, (&pregs->pc)); 359 __get_user(pc, (&pregs->pc));
640 __get_user(npc, (&pregs->npc)); 360 __get_user(npc, (&pregs->npc));
@@ -647,10 +367,10 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
647 cregs->npc =npc; 367 cregs->npc =npc;
648 } 368 }
649 cregs->y = y; 369 cregs->y = y;
650 for(i = 1; i < 16; i++) 370 for (i = 1; i < 16; i++)
651 __get_user(cregs->u_regs[i], (&pregs->u_regs[i-1])); 371 __get_user(cregs->u_regs[i], &pregs->u_regs[i-1]);
652 pt_succ_return(regs, 0); 372 ret = 0;
653 goto out_tsk; 373 break;
654 } 374 }
655 375
656 case PTRACE_GETFPREGS: { 376 case PTRACE_GETFPREGS: {
@@ -666,26 +386,25 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
666 } fpq[16]; 386 } fpq[16];
667 }; 387 };
668 struct fps __user *fps = (struct fps __user *) addr; 388 struct fps __user *fps = (struct fps __user *) addr;
669 int i;
670 389
671 if (!access_ok(VERIFY_WRITE, fps, sizeof(struct fps))) { 390 ret = -EFAULT;
672 i = -EFAULT; 391 if (!access_ok(VERIFY_WRITE, fps, sizeof(struct fps)))
673 pt_error_return(regs, -i); 392 break;
674 goto out_tsk; 393
675 } 394 for (i = 0; i < 32; i++)
676 for(i = 0; i < 32; i++) 395 __put_user(child->thread.float_regs[i], &fps->regs[i]);
677 __put_user(child->thread.float_regs[i], (&fps->regs[i]));
678 __put_user(child->thread.fsr, (&fps->fsr)); 396 __put_user(child->thread.fsr, (&fps->fsr));
679 __put_user(child->thread.fpqdepth, (&fps->fpqd)); 397 __put_user(child->thread.fpqdepth, (&fps->fpqd));
680 __put_user(0, (&fps->flags)); 398 __put_user(0, (&fps->flags));
681 __put_user(0, (&fps->extra)); 399 __put_user(0, (&fps->extra));
682 for(i = 0; i < 16; i++) { 400 for (i = 0; i < 16; i++) {
683 __put_user(child->thread.fpqueue[i].insn_addr, 401 __put_user(child->thread.fpqueue[i].insn_addr,
684 (&fps->fpq[i].insnaddr)); 402 (&fps->fpq[i].insnaddr));
685 __put_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn)); 403 __put_user(child->thread.fpqueue[i].insn,
404 &fps->fpq[i].insn);
686 } 405 }
687 pt_succ_return(regs, 0); 406 ret = 0;
688 goto out_tsk; 407 break;
689 } 408 }
690 409
691 case PTRACE_SETFPREGS: { 410 case PTRACE_SETFPREGS: {
@@ -701,107 +420,53 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
701 } fpq[16]; 420 } fpq[16];
702 }; 421 };
703 struct fps __user *fps = (struct fps __user *) addr; 422 struct fps __user *fps = (struct fps __user *) addr;
704 int i;
705 423
706 if (!access_ok(VERIFY_READ, fps, sizeof(struct fps))) { 424 ret = -EFAULT;
707 i = -EFAULT; 425 if (!access_ok(VERIFY_READ, fps, sizeof(struct fps)))
708 pt_error_return(regs, -i); 426 break;
709 goto out_tsk; 427
710 } 428 copy_from_user(&child->thread.float_regs[0], &fps->regs[0],
711 copy_from_user(&child->thread.float_regs[0], &fps->regs[0], (32 * sizeof(unsigned long))); 429 (32 * sizeof(unsigned long)));
712 __get_user(child->thread.fsr, (&fps->fsr)); 430 __get_user(child->thread.fsr, (&fps->fsr));
713 __get_user(child->thread.fpqdepth, (&fps->fpqd)); 431 __get_user(child->thread.fpqdepth, (&fps->fpqd));
714 for(i = 0; i < 16; i++) { 432 for (i = 0; i < 16; i++) {
715 __get_user(child->thread.fpqueue[i].insn_addr, 433 __get_user(child->thread.fpqueue[i].insn_addr,
716 (&fps->fpq[i].insnaddr)); 434 (&fps->fpq[i].insnaddr));
717 __get_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn)); 435 __get_user(child->thread.fpqueue[i].insn,
436 &fps->fpq[i].insn);
718 } 437 }
719 pt_succ_return(regs, 0); 438 ret = 0;
720 goto out_tsk; 439 break;
721 } 440 }
722 441
723 case PTRACE_READTEXT: 442 case PTRACE_READTEXT:
724 case PTRACE_READDATA: { 443 case PTRACE_READDATA:
725 int res = ptrace_readdata(child, addr, 444 ret = ptrace_readdata(child, addr,
726 (void __user *) addr2, data); 445 (void __user *) addr2, data);
727 446
728 if (res == data) { 447 if (ret == data)
729 pt_succ_return(regs, 0); 448 ret = 0;
730 goto out_tsk; 449 else if (ret >= 0)
731 } 450 ret = -EIO;
732 /* Partial read is an IO failure */ 451 break;
733 if (res >= 0)
734 res = -EIO;
735 pt_error_return(regs, -res);
736 goto out_tsk;
737 }
738 452
739 case PTRACE_WRITETEXT: 453 case PTRACE_WRITETEXT:
740 case PTRACE_WRITEDATA: { 454 case PTRACE_WRITEDATA:
741 int res = ptrace_writedata(child, (void __user *) addr2, 455 ret = ptrace_writedata(child, (void __user *) addr2,
742 addr, data); 456 addr, data);
743 457
744 if (res == data) { 458 if (ret == data)
745 pt_succ_return(regs, 0); 459 ret = 0;
746 goto out_tsk; 460 else if (ret >= 0)
747 } 461 ret = -EIO;
748 /* Partial write is an IO failure */ 462 break;
749 if (res >= 0)
750 res = -EIO;
751 pt_error_return(regs, -res);
752 goto out_tsk;
753 }
754
755 case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
756 addr = 1;
757
758 case PTRACE_CONT: { /* restart after signal. */
759 if (!valid_signal(data)) {
760 pt_error_return(regs, EIO);
761 goto out_tsk;
762 }
763
764 if (request == PTRACE_SYSCALL)
765 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
766 else
767 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
768
769 child->exit_code = data;
770 wake_up_process(child);
771 pt_succ_return(regs, 0);
772 goto out_tsk;
773 }
774 463
775/* 464 default:
776 * make the child exit. Best I can do is send it a sigkill. 465 ret = ptrace_request(child, request, addr, data);
777 * perhaps it should be put in the status that it wants to 466 break;
778 * exit.
779 */
780 case PTRACE_KILL: {
781 if (child->exit_state == EXIT_ZOMBIE) { /* already dead */
782 pt_succ_return(regs, 0);
783 goto out_tsk;
784 }
785 wake_up_process(child);
786 child->exit_code = SIGKILL;
787 pt_succ_return(regs, 0);
788 goto out_tsk;
789 } 467 }
790 468
791 default: { 469 return ret;
792 int err = ptrace_request(child, request, addr, data);
793 if (err)
794 pt_error_return(regs, -err);
795 else
796 pt_succ_return(regs, 0);
797 goto out_tsk;
798 }
799 }
800out_tsk:
801 if (child)
802 put_task_struct(child);
803out:
804 unlock_kernel();
805} 470}
806 471
807asmlinkage void syscall_trace(void) 472asmlinkage void syscall_trace(void)
@@ -810,7 +475,6 @@ asmlinkage void syscall_trace(void)
810 return; 475 return;
811 if (!(current->ptrace & PT_PTRACED)) 476 if (!(current->ptrace & PT_PTRACED))
812 return; 477 return;
813 current->thread.flags ^= MAGIC_CONSTANT;
814 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) 478 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
815 ? 0x80 : 0)); 479 ? 0x80 : 0));
816 /* 480 /*