diff options
| author | David S. Miller <davem@davemloft.net> | 2008-02-07 08:06:12 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2008-02-07 08:06:12 -0500 |
| commit | 9473272af395e1f76cf917ddd20abd2326fc58f1 (patch) | |
| tree | 4ca6e90ec90ae9ce6debeadea70d16999e2a17ed | |
| parent | 5a4924d7be5df430132e109d3d2f26be610b4707 (diff) | |
[SPARC64]: Use regsets in arch_ptrace().
Signed-off-by: David S. Miller <davem@davemloft.net>
| -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 | ||
