diff options
-rw-r--r-- | arch/sparc64/kernel/ptrace.c | 209 |
1 files changed, 77 insertions, 132 deletions
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index 7e28ee36419e..51f012410f9d 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c | |||
@@ -687,11 +687,14 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) | |||
687 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) | 687 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) |
688 | { | 688 | { |
689 | long addr2 = task_pt_regs(current)->u_regs[UREG_I4]; | 689 | long addr2 = task_pt_regs(current)->u_regs[UREG_I4]; |
690 | int i, ret; | 690 | const struct user_regset_view *view; |
691 | int ret; | ||
691 | 692 | ||
692 | if (test_thread_flag(TIF_32BIT)) | 693 | if (test_thread_flag(TIF_32BIT)) |
693 | addr2 &= 0xffffffffUL; | 694 | addr2 &= 0xffffffffUL; |
694 | 695 | ||
696 | view = task_user_regset_view(child); | ||
697 | |||
695 | switch(request) { | 698 | switch(request) { |
696 | case PTRACE_PEEKUSR: | 699 | case PTRACE_PEEKUSR: |
697 | ret = (addr != 0) ? -EIO : 0; | 700 | ret = (addr != 0) ? -EIO : 0; |
@@ -746,111 +749,66 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
746 | case PTRACE_GETREGS: { | 749 | case PTRACE_GETREGS: { |
747 | struct pt_regs32 __user *pregs = | 750 | struct pt_regs32 __user *pregs = |
748 | (struct pt_regs32 __user *) addr; | 751 | (struct pt_regs32 __user *) addr; |
749 | struct pt_regs *cregs = task_pt_regs(child); | ||
750 | 752 | ||
751 | ret = -EFAULT; | 753 | ret = copy_regset_to_user(child, view, REGSET_GENERAL, |
752 | if (__put_user(tstate_to_psr(cregs->tstate), (&pregs->psr)) || | 754 | 32 * sizeof(u32), |
753 | __put_user(cregs->tpc, (&pregs->pc)) || | 755 | 4 * sizeof(u32), |
754 | __put_user(cregs->tnpc, (&pregs->npc)) || | 756 | &pregs->psr); |
755 | __put_user(cregs->y, (&pregs->y))) | 757 | if (!ret) |
756 | break; | 758 | ret = copy_regset_to_user(child, view, REGSET_GENERAL, |
757 | for (i = 1; i < 16; i++) { | 759 | 1 * sizeof(u32), |
758 | if (__put_user(cregs->u_regs[i], | 760 | 15 * sizeof(u32), |
759 | (&pregs->u_regs[i - 1]))) | 761 | &pregs->u_regs[0]); |
760 | break; | ||
761 | } | ||
762 | if (i == 16) | ||
763 | ret = 0; | ||
764 | break; | 762 | break; |
765 | } | 763 | } |
766 | 764 | ||
767 | case PTRACE_GETREGS64: { | 765 | case PTRACE_GETREGS64: { |
768 | struct pt_regs __user *pregs = (struct pt_regs __user *) addr; | 766 | struct pt_regs __user *pregs = (struct pt_regs __user *) addr; |
769 | struct pt_regs *cregs = task_pt_regs(child); | ||
770 | unsigned long tpc = cregs->tpc; | ||
771 | |||
772 | if ((task_thread_info(child)->flags & _TIF_32BIT) != 0) | ||
773 | tpc &= 0xffffffff; | ||
774 | 767 | ||
775 | ret = -EFAULT; | 768 | ret = copy_regset_to_user(child, view, REGSET_GENERAL, |
776 | if (__put_user(cregs->tstate, (&pregs->tstate)) || | 769 | 1 * sizeof(u64), |
777 | __put_user(tpc, (&pregs->tpc)) || | 770 | 15 * sizeof(u64), |
778 | __put_user(cregs->tnpc, (&pregs->tnpc)) || | 771 | &pregs->u_regs[0]); |
779 | __put_user(cregs->y, (&pregs->y))) | 772 | if (!ret) { |
780 | break; | 773 | /* XXX doesn't handle 'y' register correctly XXX */ |
781 | for (i = 1; i < 16; i++) { | 774 | ret = copy_regset_to_user(child, view, REGSET_GENERAL, |
782 | if (__put_user(cregs->u_regs[i], | 775 | 32 * sizeof(u64), |
783 | (&pregs->u_regs[i - 1]))) | 776 | 4 * sizeof(u64), |
784 | break; | 777 | &pregs->tstate); |
785 | } | 778 | } |
786 | if (i == 16) | ||
787 | ret = 0; | ||
788 | break; | 779 | break; |
789 | } | 780 | } |
790 | 781 | ||
791 | case PTRACE_SETREGS: { | 782 | case PTRACE_SETREGS: { |
792 | struct pt_regs32 __user *pregs = | 783 | struct pt_regs32 __user *pregs = |
793 | (struct pt_regs32 __user *) addr; | 784 | (struct pt_regs32 __user *) addr; |
794 | struct pt_regs *cregs = task_pt_regs(child); | 785 | |
795 | unsigned int psr, pc, npc, y; | 786 | ret = copy_regset_from_user(child, view, REGSET_GENERAL, |
796 | 787 | 32 * sizeof(u32), | |
797 | /* Must be careful, tracing process can only set certain | 788 | 4 * sizeof(u32), |
798 | * bits in the psr. | 789 | &pregs->psr); |
799 | */ | 790 | if (!ret) |
800 | ret = -EFAULT; | 791 | ret = copy_regset_from_user(child, view, REGSET_GENERAL, |
801 | if (__get_user(psr, (&pregs->psr)) || | 792 | 1 * sizeof(u32), |
802 | __get_user(pc, (&pregs->pc)) || | 793 | 15 * sizeof(u32), |
803 | __get_user(npc, (&pregs->npc)) || | 794 | &pregs->u_regs[0]); |
804 | __get_user(y, (&pregs->y))) | ||
805 | break; | ||
806 | cregs->tstate &= ~(TSTATE_ICC); | ||
807 | cregs->tstate |= psr_to_tstate_icc(psr); | ||
808 | if (!((pc | npc) & 3)) { | ||
809 | cregs->tpc = pc; | ||
810 | cregs->tnpc = npc; | ||
811 | } | ||
812 | cregs->y = y; | ||
813 | for (i = 1; i < 16; i++) { | ||
814 | if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) | ||
815 | break; | ||
816 | } | ||
817 | if (i == 16) | ||
818 | ret = 0; | ||
819 | break; | 795 | break; |
820 | } | 796 | } |
821 | 797 | ||
822 | case PTRACE_SETREGS64: { | 798 | case PTRACE_SETREGS64: { |
823 | struct pt_regs __user *pregs = (struct pt_regs __user *) addr; | 799 | struct pt_regs __user *pregs = (struct pt_regs __user *) addr; |
824 | struct pt_regs *cregs = task_pt_regs(child); | 800 | |
825 | unsigned long tstate, tpc, tnpc, y; | 801 | ret = copy_regset_from_user(child, view, REGSET_GENERAL, |
826 | 802 | 1 * sizeof(u64), | |
827 | /* Must be careful, tracing process can only set certain | 803 | 15 * sizeof(u64), |
828 | * bits in the psr. | 804 | &pregs->u_regs[0]); |
829 | */ | 805 | if (!ret) { |
830 | ret = -EFAULT; | 806 | /* XXX doesn't handle 'y' register correctly XXX */ |
831 | if (__get_user(tstate, (&pregs->tstate)) || | 807 | ret = copy_regset_from_user(child, view, REGSET_GENERAL, |
832 | __get_user(tpc, (&pregs->tpc)) || | 808 | 32 * sizeof(u64), |
833 | __get_user(tnpc, (&pregs->tnpc)) || | 809 | 4 * sizeof(u64), |
834 | __get_user(y, (&pregs->y))) | 810 | &pregs->tstate); |
835 | break; | ||
836 | if ((task_thread_info(child)->flags & _TIF_32BIT) != 0) { | ||
837 | tpc &= 0xffffffff; | ||
838 | tnpc &= 0xffffffff; | ||
839 | } | ||
840 | tstate &= (TSTATE_ICC | TSTATE_XCC); | ||
841 | cregs->tstate &= ~(TSTATE_ICC | TSTATE_XCC); | ||
842 | cregs->tstate |= tstate; | ||
843 | if (!((tpc | tnpc) & 3)) { | ||
844 | cregs->tpc = tpc; | ||
845 | cregs->tnpc = tnpc; | ||
846 | } | ||
847 | cregs->y = y; | ||
848 | for (i = 1; i < 16; i++) { | ||
849 | if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) | ||
850 | break; | ||
851 | } | 811 | } |
852 | if (i == 16) | ||
853 | ret = 0; | ||
854 | break; | 812 | break; |
855 | } | 813 | } |
856 | 814 | ||
@@ -867,19 +825,23 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
867 | } fpq[16]; | 825 | } fpq[16]; |
868 | }; | 826 | }; |
869 | struct fps __user *fps = (struct fps __user *) addr; | 827 | struct fps __user *fps = (struct fps __user *) addr; |
870 | unsigned long *fpregs = task_thread_info(child)->fpregs; | ||
871 | |||
872 | ret = -EFAULT; | ||
873 | if (copy_to_user(&fps->regs[0], fpregs, | ||
874 | (32 * sizeof(unsigned int))) || | ||
875 | __put_user(task_thread_info(child)->xfsr[0], (&fps->fsr)) || | ||
876 | __put_user(0, (&fps->fpqd)) || | ||
877 | __put_user(0, (&fps->flags)) || | ||
878 | __put_user(0, (&fps->extra)) || | ||
879 | clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) | ||
880 | break; | ||
881 | 828 | ||
882 | ret = 0; | 829 | ret = copy_regset_to_user(child, view, REGSET_FP, |
830 | 0 * sizeof(u32), | ||
831 | 32 * sizeof(u32), | ||
832 | &fps->regs[0]); | ||
833 | if (!ret) | ||
834 | ret = copy_regset_to_user(child, view, REGSET_FP, | ||
835 | 33 * sizeof(u32), | ||
836 | 1 * sizeof(u32), | ||
837 | &fps->fsr); | ||
838 | if (!ret) { | ||
839 | if (__put_user(0, &fps->flags) || | ||
840 | __put_user(0, &fps->extra) || | ||
841 | __put_user(0, &fps->fpqd) || | ||
842 | clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) | ||
843 | ret = -EFAULT; | ||
844 | } | ||
883 | break; | 845 | break; |
884 | } | 846 | } |
885 | 847 | ||
@@ -889,15 +851,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
889 | unsigned long fsr; | 851 | unsigned long fsr; |
890 | }; | 852 | }; |
891 | struct fps __user *fps = (struct fps __user *) addr; | 853 | struct fps __user *fps = (struct fps __user *) addr; |
892 | unsigned long *fpregs = task_thread_info(child)->fpregs; | ||
893 | 854 | ||
894 | ret = -EFAULT; | 855 | ret = copy_regset_to_user(child, view, REGSET_FP, |
895 | if (copy_to_user(&fps->regs[0], fpregs, | 856 | 0 * sizeof(u64), |
896 | (64 * sizeof(unsigned int))) || | 857 | 33 * sizeof(u64), |
897 | __put_user(task_thread_info(child)->xfsr[0], (&fps->fsr))) | 858 | fps); |
898 | break; | ||
899 | |||
900 | ret = 0; | ||
901 | break; | 859 | break; |
902 | } | 860 | } |
903 | 861 | ||
@@ -914,21 +872,16 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
914 | } fpq[16]; | 872 | } fpq[16]; |
915 | }; | 873 | }; |
916 | struct fps __user *fps = (struct fps __user *) addr; | 874 | struct fps __user *fps = (struct fps __user *) addr; |
917 | unsigned long *fpregs = task_thread_info(child)->fpregs; | ||
918 | unsigned fsr; | ||
919 | |||
920 | ret = -EFAULT; | ||
921 | if (copy_from_user(fpregs, &fps->regs[0], | ||
922 | (32 * sizeof(unsigned int))) || | ||
923 | __get_user(fsr, (&fps->fsr))) | ||
924 | break; | ||
925 | 875 | ||
926 | task_thread_info(child)->xfsr[0] &= 0xffffffff00000000UL; | 876 | ret = copy_regset_from_user(child, view, REGSET_FP, |
927 | task_thread_info(child)->xfsr[0] |= fsr; | 877 | 0 * sizeof(u32), |
928 | if (!(task_thread_info(child)->fpsaved[0] & FPRS_FEF)) | 878 | 32 * sizeof(u32), |
929 | task_thread_info(child)->gsr[0] = 0; | 879 | &fps->regs[0]); |
930 | task_thread_info(child)->fpsaved[0] |= (FPRS_FEF | FPRS_DL); | 880 | if (!ret) |
931 | ret = 0; | 881 | ret = copy_regset_from_user(child, view, REGSET_FP, |
882 | 33 * sizeof(u32), | ||
883 | 1 * sizeof(u32), | ||
884 | &fps->fsr); | ||
932 | break; | 885 | break; |
933 | } | 886 | } |
934 | 887 | ||
@@ -938,19 +891,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
938 | unsigned long fsr; | 891 | unsigned long fsr; |
939 | }; | 892 | }; |
940 | struct fps __user *fps = (struct fps __user *) addr; | 893 | struct fps __user *fps = (struct fps __user *) addr; |
941 | unsigned long *fpregs = task_thread_info(child)->fpregs; | ||
942 | |||
943 | ret = -EFAULT; | ||
944 | if (copy_from_user(fpregs, &fps->regs[0], | ||
945 | (64 * sizeof(unsigned int))) || | ||
946 | __get_user(task_thread_info(child)->xfsr[0], (&fps->fsr))) | ||
947 | break; | ||
948 | 894 | ||
949 | if (!(task_thread_info(child)->fpsaved[0] & FPRS_FEF)) | 895 | ret = copy_regset_to_user(child, view, REGSET_FP, |
950 | task_thread_info(child)->gsr[0] = 0; | 896 | 0 * sizeof(u64), |
951 | task_thread_info(child)->fpsaved[0] |= | 897 | 33 * sizeof(u64), |
952 | (FPRS_FEF | FPRS_DL | FPRS_DU); | 898 | fps); |
953 | ret = 0; | ||
954 | break; | 899 | break; |
955 | } | 900 | } |
956 | 901 | ||