aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/ptrace.c
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2008-07-14 03:58:54 -0400
committerHeiko Carstens <heiko.carstens@de.ibm.com>2008-07-14 04:02:09 -0400
commit63506c41986c4af9d4fd6f3490e98e335f3dc8f5 (patch)
tree6d817aedf37a004c12713a0b594387b9dadd59ea /arch/s390/kernel/ptrace.c
parentae437a452ed20f9d13c1f17b0356201d54394efa (diff)
[S390] Introduce user_regset accessors for s390
Add the user_regset definitions for normal and compat processes, replace the dump_regs core dump cruft with the generic CORE_DUMP_USER_REGSET and replace binfmt_elf32.c with the generic compat_binfmt_elf.c implementation. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel/ptrace.c')
-rw-r--r--arch/s390/kernel/ptrace.c363
1 files changed, 318 insertions, 45 deletions
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index 35827b9bd4d1..2815bfe348a6 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -33,6 +33,8 @@
33#include <linux/security.h> 33#include <linux/security.h>
34#include <linux/audit.h> 34#include <linux/audit.h>
35#include <linux/signal.h> 35#include <linux/signal.h>
36#include <linux/elf.h>
37#include <linux/regset.h>
36 38
37#include <asm/segment.h> 39#include <asm/segment.h>
38#include <asm/page.h> 40#include <asm/page.h>
@@ -47,6 +49,11 @@
47#include "compat_ptrace.h" 49#include "compat_ptrace.h"
48#endif 50#endif
49 51
52enum s390_regset {
53 REGSET_GENERAL,
54 REGSET_FP,
55};
56
50static void 57static void
51FixPerRegisters(struct task_struct *task) 58FixPerRegisters(struct task_struct *task)
52{ 59{
@@ -126,24 +133,10 @@ ptrace_disable(struct task_struct *child)
126 * struct user contain pad bytes that should be read as zeroes. 133 * struct user contain pad bytes that should be read as zeroes.
127 * Lovely... 134 * Lovely...
128 */ 135 */
129static int 136static unsigned long __peek_user(struct task_struct *child, addr_t addr)
130peek_user(struct task_struct *child, addr_t addr, addr_t data)
131{ 137{
132 struct user *dummy = NULL; 138 struct user *dummy = NULL;
133 addr_t offset, tmp, mask; 139 addr_t offset, tmp;
134
135 /*
136 * Stupid gdb peeks/pokes the access registers in 64 bit with
137 * an alignment of 4. Programmers from hell...
138 */
139 mask = __ADDR_MASK;
140#ifdef CONFIG_64BIT
141 if (addr >= (addr_t) &dummy->regs.acrs &&
142 addr < (addr_t) &dummy->regs.orig_gpr2)
143 mask = 3;
144#endif
145 if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)
146 return -EIO;
147 140
148 if (addr < (addr_t) &dummy->regs.acrs) { 141 if (addr < (addr_t) &dummy->regs.acrs) {
149 /* 142 /*
@@ -197,24 +190,18 @@ peek_user(struct task_struct *child, addr_t addr, addr_t data)
197 } else 190 } else
198 tmp = 0; 191 tmp = 0;
199 192
200 return put_user(tmp, (addr_t __user *) data); 193 return tmp;
201} 194}
202 195
203/*
204 * Write a word to the user area of a process at location addr. This
205 * operation does have an additional problem compared to peek_user.
206 * Stores to the program status word and on the floating point
207 * control register needs to get checked for validity.
208 */
209static int 196static int
210poke_user(struct task_struct *child, addr_t addr, addr_t data) 197peek_user(struct task_struct *child, addr_t addr, addr_t data)
211{ 198{
212 struct user *dummy = NULL; 199 struct user *dummy = NULL;
213 addr_t offset, mask; 200 addr_t tmp, mask;
214 201
215 /* 202 /*
216 * Stupid gdb peeks/pokes the access registers in 64 bit with 203 * Stupid gdb peeks/pokes the access registers in 64 bit with
217 * an alignment of 4. Programmers from hell indeed... 204 * an alignment of 4. Programmers from hell...
218 */ 205 */
219 mask = __ADDR_MASK; 206 mask = __ADDR_MASK;
220#ifdef CONFIG_64BIT 207#ifdef CONFIG_64BIT
@@ -225,6 +212,21 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data)
225 if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK) 212 if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)
226 return -EIO; 213 return -EIO;
227 214
215 tmp = __peek_user(child, addr);
216 return put_user(tmp, (addr_t __user *) data);
217}
218
219/*
220 * Write a word to the user area of a process at location addr. This
221 * operation does have an additional problem compared to peek_user.
222 * Stores to the program status word and on the floating point
223 * control register needs to get checked for validity.
224 */
225static int __poke_user(struct task_struct *child, addr_t addr, addr_t data)
226{
227 struct user *dummy = NULL;
228 addr_t offset;
229
228 if (addr < (addr_t) &dummy->regs.acrs) { 230 if (addr < (addr_t) &dummy->regs.acrs) {
229 /* 231 /*
230 * psw and gprs are stored on the stack 232 * psw and gprs are stored on the stack
@@ -292,6 +294,28 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data)
292 return 0; 294 return 0;
293} 295}
294 296
297static int
298poke_user(struct task_struct *child, addr_t addr, addr_t data)
299{
300 struct user *dummy = NULL;
301 addr_t mask;
302
303 /*
304 * Stupid gdb peeks/pokes the access registers in 64 bit with
305 * an alignment of 4. Programmers from hell indeed...
306 */
307 mask = __ADDR_MASK;
308#ifdef CONFIG_64BIT
309 if (addr >= (addr_t) &dummy->regs.acrs &&
310 addr < (addr_t) &dummy->regs.orig_gpr2)
311 mask = 3;
312#endif
313 if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)
314 return -EIO;
315
316 return __poke_user(child, addr, data);
317}
318
295long arch_ptrace(struct task_struct *child, long request, long addr, long data) 319long arch_ptrace(struct task_struct *child, long request, long addr, long data)
296{ 320{
297 ptrace_area parea; 321 ptrace_area parea;
@@ -367,18 +391,13 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
367/* 391/*
368 * Same as peek_user but for a 31 bit program. 392 * Same as peek_user but for a 31 bit program.
369 */ 393 */
370static int 394static u32 __peek_user_compat(struct task_struct *child, addr_t addr)
371peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
372{ 395{
373 struct user32 *dummy32 = NULL; 396 struct user32 *dummy32 = NULL;
374 per_struct32 *dummy_per32 = NULL; 397 per_struct32 *dummy_per32 = NULL;
375 addr_t offset; 398 addr_t offset;
376 __u32 tmp; 399 __u32 tmp;
377 400
378 if (!test_thread_flag(TIF_31BIT) ||
379 (addr & 3) || addr > sizeof(struct user) - 3)
380 return -EIO;
381
382 if (addr < (addr_t) &dummy32->regs.acrs) { 401 if (addr < (addr_t) &dummy32->regs.acrs) {
383 /* 402 /*
384 * psw and gprs are stored on the stack 403 * psw and gprs are stored on the stack
@@ -435,25 +454,32 @@ peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
435 } else 454 } else
436 tmp = 0; 455 tmp = 0;
437 456
457 return tmp;
458}
459
460static int peek_user_compat(struct task_struct *child,
461 addr_t addr, addr_t data)
462{
463 __u32 tmp;
464
465 if (!test_thread_flag(TIF_31BIT) ||
466 (addr & 3) || addr > sizeof(struct user) - 3)
467 return -EIO;
468
469 tmp = __peek_user_compat(child, addr);
438 return put_user(tmp, (__u32 __user *) data); 470 return put_user(tmp, (__u32 __user *) data);
439} 471}
440 472
441/* 473/*
442 * Same as poke_user but for a 31 bit program. 474 * Same as poke_user but for a 31 bit program.
443 */ 475 */
444static int 476static int __poke_user_compat(struct task_struct *child,
445poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data) 477 addr_t addr, addr_t data)
446{ 478{
447 struct user32 *dummy32 = NULL; 479 struct user32 *dummy32 = NULL;
448 per_struct32 *dummy_per32 = NULL; 480 per_struct32 *dummy_per32 = NULL;
481 __u32 tmp = (__u32) data;
449 addr_t offset; 482 addr_t offset;
450 __u32 tmp;
451
452 if (!test_thread_flag(TIF_31BIT) ||
453 (addr & 3) || addr > sizeof(struct user32) - 3)
454 return -EIO;
455
456 tmp = (__u32) data;
457 483
458 if (addr < (addr_t) &dummy32->regs.acrs) { 484 if (addr < (addr_t) &dummy32->regs.acrs) {
459 /* 485 /*
@@ -528,6 +554,16 @@ poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
528 return 0; 554 return 0;
529} 555}
530 556
557static int poke_user_compat(struct task_struct *child,
558 addr_t addr, addr_t data)
559{
560 if (!test_thread_flag(TIF_31BIT) ||
561 (addr & 3) || addr > sizeof(struct user32) - 3)
562 return -EIO;
563
564 return __poke_user_compat(child, addr, data);
565}
566
531long compat_arch_ptrace(struct task_struct *child, compat_long_t request, 567long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
532 compat_ulong_t caddr, compat_ulong_t cdata) 568 compat_ulong_t caddr, compat_ulong_t cdata)
533{ 569{
@@ -539,11 +575,11 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
539 switch (request) { 575 switch (request) {
540 case PTRACE_PEEKUSR: 576 case PTRACE_PEEKUSR:
541 /* read the word at location addr in the USER area. */ 577 /* read the word at location addr in the USER area. */
542 return peek_user_emu31(child, addr, data); 578 return peek_user_compat(child, addr, data);
543 579
544 case PTRACE_POKEUSR: 580 case PTRACE_POKEUSR:
545 /* write the word at location addr in the USER area */ 581 /* write the word at location addr in the USER area */
546 return poke_user_emu31(child, addr, data); 582 return poke_user_compat(child, addr, data);
547 583
548 case PTRACE_PEEKUSR_AREA: 584 case PTRACE_PEEKUSR_AREA:
549 case PTRACE_POKEUSR_AREA: 585 case PTRACE_POKEUSR_AREA:
@@ -555,13 +591,13 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
555 copied = 0; 591 copied = 0;
556 while (copied < parea.len) { 592 while (copied < parea.len) {
557 if (request == PTRACE_PEEKUSR_AREA) 593 if (request == PTRACE_PEEKUSR_AREA)
558 ret = peek_user_emu31(child, addr, data); 594 ret = peek_user_compat(child, addr, data);
559 else { 595 else {
560 __u32 utmp; 596 __u32 utmp;
561 if (get_user(utmp, 597 if (get_user(utmp,
562 (__u32 __force __user *) data)) 598 (__u32 __force __user *) data))
563 return -EFAULT; 599 return -EFAULT;
564 ret = poke_user_emu31(child, addr, utmp); 600 ret = poke_user_compat(child, addr, utmp);
565 } 601 }
566 if (ret) 602 if (ret)
567 return ret; 603 return ret;
@@ -610,3 +646,240 @@ syscall_trace(struct pt_regs *regs, int entryexit)
610 regs->gprs[2], regs->orig_gpr2, regs->gprs[3], 646 regs->gprs[2], regs->orig_gpr2, regs->gprs[3],
611 regs->gprs[4], regs->gprs[5]); 647 regs->gprs[4], regs->gprs[5]);
612} 648}
649
650/*
651 * user_regset definitions.
652 */
653
654static int s390_regs_get(struct task_struct *target,
655 const struct user_regset *regset,
656 unsigned int pos, unsigned int count,
657 void *kbuf, void __user *ubuf)
658{
659 if (target == current)
660 save_access_regs(target->thread.acrs);
661
662 if (kbuf) {
663 unsigned long *k = kbuf;
664 while (count > 0) {
665 *k++ = __peek_user(target, pos);
666 count -= sizeof(*k);
667 pos += sizeof(*k);
668 }
669 } else {
670 unsigned long __user *u = ubuf;
671 while (count > 0) {
672 if (__put_user(__peek_user(target, pos), u++))
673 return -EFAULT;
674 count -= sizeof(*u);
675 pos += sizeof(*u);
676 }
677 }
678 return 0;
679}
680
681static int s390_regs_set(struct task_struct *target,
682 const struct user_regset *regset,
683 unsigned int pos, unsigned int count,
684 const void *kbuf, const void __user *ubuf)
685{
686 int rc = 0;
687
688 if (target == current)
689 save_access_regs(target->thread.acrs);
690
691 if (kbuf) {
692 const unsigned long *k = kbuf;
693 while (count > 0 && !rc) {
694 rc = __poke_user(target, pos, *k++);
695 count -= sizeof(*k);
696 pos += sizeof(*k);
697 }
698 } else {
699 const unsigned long __user *u = ubuf;
700 while (count > 0 && !rc) {
701 unsigned long word;
702 rc = __get_user(word, u++);
703 if (rc)
704 break;
705 rc = __poke_user(target, pos, word);
706 count -= sizeof(*u);
707 pos += sizeof(*u);
708 }
709 }
710
711 if (rc == 0 && target == current)
712 restore_access_regs(target->thread.acrs);
713
714 return rc;
715}
716
717static int s390_fpregs_get(struct task_struct *target,
718 const struct user_regset *regset, unsigned int pos,
719 unsigned int count, void *kbuf, void __user *ubuf)
720{
721 if (target == current)
722 save_fp_regs(&target->thread.fp_regs);
723
724 return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
725 &target->thread.fp_regs, 0, -1);
726}
727
728static int s390_fpregs_set(struct task_struct *target,
729 const struct user_regset *regset, unsigned int pos,
730 unsigned int count, const void *kbuf,
731 const void __user *ubuf)
732{
733 int rc = 0;
734
735 if (target == current)
736 save_fp_regs(&target->thread.fp_regs);
737
738 /* If setting FPC, must validate it first. */
739 if (count > 0 && pos < offsetof(s390_fp_regs, fprs)) {
740 u32 fpc[2] = { target->thread.fp_regs.fpc, 0 };
741 rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &fpc,
742 0, offsetof(s390_fp_regs, fprs));
743 if (rc)
744 return rc;
745 if ((fpc[0] & ~FPC_VALID_MASK) != 0 || fpc[1] != 0)
746 return -EINVAL;
747 target->thread.fp_regs.fpc = fpc[0];
748 }
749
750 if (rc == 0 && count > 0)
751 rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
752 target->thread.fp_regs.fprs,
753 offsetof(s390_fp_regs, fprs), -1);
754
755 if (rc == 0 && target == current)
756 restore_fp_regs(&target->thread.fp_regs);
757
758 return rc;
759}
760
761static const struct user_regset s390_regsets[] = {
762 [REGSET_GENERAL] = {
763 .core_note_type = NT_PRSTATUS,
764 .n = sizeof(s390_regs) / sizeof(long),
765 .size = sizeof(long),
766 .align = sizeof(long),
767 .get = s390_regs_get,
768 .set = s390_regs_set,
769 },
770 [REGSET_FP] = {
771 .core_note_type = NT_PRFPREG,
772 .n = sizeof(s390_fp_regs) / sizeof(long),
773 .size = sizeof(long),
774 .align = sizeof(long),
775 .get = s390_fpregs_get,
776 .set = s390_fpregs_set,
777 },
778};
779
780static const struct user_regset_view user_s390_view = {
781 .name = UTS_MACHINE,
782 .e_machine = EM_S390,
783 .regsets = s390_regsets,
784 .n = ARRAY_SIZE(s390_regsets)
785};
786
787#ifdef CONFIG_COMPAT
788static int s390_compat_regs_get(struct task_struct *target,
789 const struct user_regset *regset,
790 unsigned int pos, unsigned int count,
791 void *kbuf, void __user *ubuf)
792{
793 if (target == current)
794 save_access_regs(target->thread.acrs);
795
796 if (kbuf) {
797 compat_ulong_t *k = kbuf;
798 while (count > 0) {
799 *k++ = __peek_user_compat(target, pos);
800 count -= sizeof(*k);
801 pos += sizeof(*k);
802 }
803 } else {
804 compat_ulong_t __user *u = ubuf;
805 while (count > 0) {
806 if (__put_user(__peek_user_compat(target, pos), u++))
807 return -EFAULT;
808 count -= sizeof(*u);
809 pos += sizeof(*u);
810 }
811 }
812 return 0;
813}
814
815static int s390_compat_regs_set(struct task_struct *target,
816 const struct user_regset *regset,
817 unsigned int pos, unsigned int count,
818 const void *kbuf, const void __user *ubuf)
819{
820 int rc = 0;
821
822 if (target == current)
823 save_access_regs(target->thread.acrs);
824
825 if (kbuf) {
826 const compat_ulong_t *k = kbuf;
827 while (count > 0 && !rc) {
828 rc = __poke_user_compat(target, pos, *k++);
829 count -= sizeof(*k);
830 pos += sizeof(*k);
831 }
832 } else {
833 const compat_ulong_t __user *u = ubuf;
834 while (count > 0 && !rc) {
835 compat_ulong_t word;
836 rc = __get_user(word, u++);
837 if (rc)
838 break;
839 rc = __poke_user_compat(target, pos, word);
840 count -= sizeof(*u);
841 pos += sizeof(*u);
842 }
843 }
844
845 if (rc == 0 && target == current)
846 restore_access_regs(target->thread.acrs);
847
848 return rc;
849}
850
851static const struct user_regset s390_compat_regsets[] = {
852 [REGSET_GENERAL] = {
853 .core_note_type = NT_PRSTATUS,
854 .n = sizeof(s390_compat_regs) / sizeof(compat_long_t),
855 .size = sizeof(compat_long_t),
856 .align = sizeof(compat_long_t),
857 .get = s390_compat_regs_get,
858 .set = s390_compat_regs_set,
859 },
860 [REGSET_FP] = {
861 .core_note_type = NT_PRFPREG,
862 .n = sizeof(s390_fp_regs) / sizeof(compat_long_t),
863 .size = sizeof(compat_long_t),
864 .align = sizeof(compat_long_t),
865 .get = s390_fpregs_get,
866 .set = s390_fpregs_set,
867 },
868};
869
870static const struct user_regset_view user_s390_compat_view = {
871 .name = "s390",
872 .e_machine = EM_S390,
873 .regsets = s390_compat_regsets,
874 .n = ARRAY_SIZE(s390_compat_regsets)
875};
876#endif
877
878const struct user_regset_view *task_user_regset_view(struct task_struct *task)
879{
880#ifdef CONFIG_COMPAT
881 if (test_tsk_thread_flag(task, TIF_31BIT))
882 return &user_s390_compat_view;
883#endif
884 return &user_s390_view;
885}