diff options
| -rw-r--r-- | arch/powerpc/kernel/ptrace.c | 234 |
1 files changed, 59 insertions, 175 deletions
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 60de9ee3701d..2c1ee2cf9419 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c | |||
| @@ -237,24 +237,6 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset, | |||
| 237 | &target->thread.fpr, 0, -1); | 237 | &target->thread.fpr, 0, -1); |
| 238 | } | 238 | } |
| 239 | 239 | ||
| 240 | static int get_fpregs(void __user *data, struct task_struct *task, | ||
| 241 | int has_fpscr) | ||
| 242 | { | ||
| 243 | unsigned int count = has_fpscr ? 33 : 32; | ||
| 244 | if (!access_ok(VERIFY_WRITE, data, count * sizeof(double))) | ||
| 245 | return -EFAULT; | ||
| 246 | return fpr_get(task, NULL, 0, count * sizeof(double), NULL, data); | ||
| 247 | } | ||
| 248 | |||
| 249 | static int set_fpregs(void __user *data, struct task_struct *task, | ||
| 250 | int has_fpscr) | ||
| 251 | { | ||
| 252 | unsigned int count = has_fpscr ? 33 : 32; | ||
| 253 | if (!access_ok(VERIFY_READ, data, count * sizeof(double))) | ||
| 254 | return -EFAULT; | ||
| 255 | return fpr_set(task, NULL, 0, count * sizeof(double), NULL, data); | ||
| 256 | } | ||
| 257 | |||
| 258 | 240 | ||
| 259 | #ifdef CONFIG_ALTIVEC | 241 | #ifdef CONFIG_ALTIVEC |
| 260 | /* | 242 | /* |
| @@ -339,31 +321,6 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset, | |||
| 339 | 321 | ||
| 340 | return ret; | 322 | return ret; |
| 341 | } | 323 | } |
| 342 | |||
| 343 | /* | ||
| 344 | * Get contents of AltiVec register state in task TASK | ||
| 345 | */ | ||
| 346 | static int get_vrregs(unsigned long __user *data, struct task_struct *task) | ||
| 347 | { | ||
| 348 | if (!access_ok(VERIFY_WRITE, data, | ||
| 349 | 33 * sizeof(vector128) + sizeof(u32))) | ||
| 350 | return -EFAULT; | ||
| 351 | |||
| 352 | return vr_get(task, NULL, 0, 33 * sizeof(vector128) + sizeof(u32), | ||
| 353 | NULL, data); | ||
| 354 | } | ||
| 355 | |||
| 356 | /* | ||
| 357 | * Write contents of AltiVec register state into task TASK. | ||
| 358 | */ | ||
| 359 | static int set_vrregs(struct task_struct *task, unsigned long __user *data) | ||
| 360 | { | ||
| 361 | if (!access_ok(VERIFY_READ, data, 33 * sizeof(vector128) + sizeof(u32))) | ||
| 362 | return -EFAULT; | ||
| 363 | |||
| 364 | return vr_set(task, NULL, 0, 33 * sizeof(vector128) + sizeof(u32), | ||
| 365 | NULL, data); | ||
| 366 | } | ||
| 367 | #endif /* CONFIG_ALTIVEC */ | 324 | #endif /* CONFIG_ALTIVEC */ |
| 368 | 325 | ||
| 369 | #ifdef CONFIG_SPE | 326 | #ifdef CONFIG_SPE |
| @@ -430,28 +387,6 @@ static int evr_set(struct task_struct *target, const struct user_regset *regset, | |||
| 430 | 387 | ||
| 431 | return ret; | 388 | return ret; |
| 432 | } | 389 | } |
| 433 | |||
| 434 | /* | ||
| 435 | * Get contents of SPE register state in task TASK. | ||
| 436 | */ | ||
| 437 | static int get_evrregs(unsigned long __user *data, struct task_struct *task) | ||
| 438 | { | ||
| 439 | if (!access_ok(VERIFY_WRITE, data, 35 * sizeof(u32))) | ||
| 440 | return -EFAULT; | ||
| 441 | |||
| 442 | return evr_get(task, NULL, 0, 35 * sizeof(u32), NULL, data); | ||
| 443 | } | ||
| 444 | |||
| 445 | /* | ||
| 446 | * Write contents of SPE register state into task TASK. | ||
| 447 | */ | ||
| 448 | static int set_evrregs(struct task_struct *task, unsigned long *data) | ||
| 449 | { | ||
| 450 | if (!access_ok(VERIFY_READ, data, 35 * sizeof(u32))) | ||
| 451 | return -EFAULT; | ||
| 452 | |||
| 453 | return evr_set(task, NULL, 0, 35 * sizeof(u32), NULL, data); | ||
| 454 | } | ||
| 455 | #endif /* CONFIG_SPE */ | 390 | #endif /* CONFIG_SPE */ |
| 456 | 391 | ||
| 457 | 392 | ||
| @@ -736,55 +671,29 @@ void ptrace_disable(struct task_struct *child) | |||
| 736 | static long arch_ptrace_old(struct task_struct *child, long request, long addr, | 671 | static long arch_ptrace_old(struct task_struct *child, long request, long addr, |
| 737 | long data) | 672 | long data) |
| 738 | { | 673 | { |
| 739 | int ret = -EPERM; | 674 | switch (request) { |
| 740 | 675 | case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */ | |
| 741 | switch(request) { | 676 | return copy_regset_to_user(child, &user_ppc_native_view, |
| 742 | case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */ | 677 | REGSET_GPR, 0, 32 * sizeof(long), |
| 743 | int i; | 678 | (void __user *) data); |
| 744 | unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; | 679 | |
| 745 | unsigned long __user *tmp = (unsigned long __user *)addr; | 680 | case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */ |
| 746 | 681 | return copy_regset_from_user(child, &user_ppc_native_view, | |
| 747 | CHECK_FULL_REGS(child->thread.regs); | 682 | REGSET_GPR, 0, 32 * sizeof(long), |
| 748 | for (i = 0; i < 32; i++) { | 683 | (const void __user *) data); |
| 749 | ret = put_user(*reg, tmp); | 684 | |
| 750 | if (ret) | 685 | case PPC_PTRACE_GETFPREGS: /* Get FPRs 0 - 31. */ |
| 751 | break; | 686 | return copy_regset_to_user(child, &user_ppc_native_view, |
| 752 | reg++; | 687 | REGSET_FPR, 0, 32 * sizeof(double), |
| 753 | tmp++; | 688 | (void __user *) data); |
| 754 | } | 689 | |
| 755 | break; | 690 | case PPC_PTRACE_SETFPREGS: /* Set FPRs 0 - 31. */ |
| 756 | } | 691 | return copy_regset_from_user(child, &user_ppc_native_view, |
| 757 | 692 | REGSET_FPR, 0, 32 * sizeof(double), | |
| 758 | case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */ | 693 | (const void __user *) data); |
| 759 | int i; | ||
| 760 | unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; | ||
| 761 | unsigned long __user *tmp = (unsigned long __user *)addr; | ||
| 762 | |||
| 763 | CHECK_FULL_REGS(child->thread.regs); | ||
| 764 | for (i = 0; i < 32; i++) { | ||
| 765 | ret = get_user(*reg, tmp); | ||
| 766 | if (ret) | ||
| 767 | break; | ||
| 768 | reg++; | ||
| 769 | tmp++; | ||
| 770 | } | ||
| 771 | break; | ||
| 772 | } | ||
| 773 | |||
| 774 | case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */ | ||
| 775 | flush_fp_to_thread(child); | ||
| 776 | ret = get_fpregs((void __user *)addr, child, 0); | ||
| 777 | break; | ||
| 778 | } | ||
| 779 | |||
| 780 | case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */ | ||
| 781 | flush_fp_to_thread(child); | ||
| 782 | ret = set_fpregs((void __user *)addr, child, 0); | ||
| 783 | break; | ||
| 784 | } | 694 | } |
| 785 | 695 | ||
| 786 | } | 696 | return -EPERM; |
| 787 | return ret; | ||
| 788 | } | 697 | } |
| 789 | 698 | ||
| 790 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) | 699 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) |
| @@ -875,85 +784,60 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
| 875 | #ifdef CONFIG_PPC64 | 784 | #ifdef CONFIG_PPC64 |
| 876 | case PTRACE_GETREGS64: | 785 | case PTRACE_GETREGS64: |
| 877 | #endif | 786 | #endif |
| 878 | case PTRACE_GETREGS: { /* Get all pt_regs from the child. */ | 787 | case PTRACE_GETREGS: /* Get all pt_regs from the child. */ |
| 879 | int ui; | 788 | return copy_regset_to_user(child, &user_ppc_native_view, |
| 880 | if (!access_ok(VERIFY_WRITE, (void __user *)data, | 789 | REGSET_GPR, |
| 881 | sizeof(struct pt_regs))) { | 790 | 0, sizeof(struct pt_regs), |
| 882 | ret = -EIO; | 791 | (void __user *) data); |
| 883 | break; | ||
| 884 | } | ||
| 885 | CHECK_FULL_REGS(child->thread.regs); | ||
| 886 | ret = 0; | ||
| 887 | for (ui = 0; ui < PT_REGS_COUNT; ui ++) { | ||
| 888 | ret |= __put_user(ptrace_get_reg(child, ui), | ||
| 889 | (unsigned long __user *) data); | ||
| 890 | data += sizeof(long); | ||
| 891 | } | ||
| 892 | break; | ||
| 893 | } | ||
| 894 | 792 | ||
| 895 | #ifdef CONFIG_PPC64 | 793 | #ifdef CONFIG_PPC64 |
| 896 | case PTRACE_SETREGS64: | 794 | case PTRACE_SETREGS64: |
| 897 | #endif | 795 | #endif |
| 898 | case PTRACE_SETREGS: { /* Set all gp regs in the child. */ | 796 | case PTRACE_SETREGS: /* Set all gp regs in the child. */ |
| 899 | unsigned long tmp; | 797 | return copy_regset_from_user(child, &user_ppc_native_view, |
| 900 | int ui; | 798 | REGSET_GPR, |
| 901 | if (!access_ok(VERIFY_READ, (void __user *)data, | 799 | 0, sizeof(struct pt_regs), |
| 902 | sizeof(struct pt_regs))) { | 800 | (const void __user *) data); |
| 903 | ret = -EIO; | 801 | |
| 904 | break; | 802 | case PTRACE_GETFPREGS: /* Get the child FPU state (FPR0...31 + FPSCR) */ |
| 905 | } | 803 | return copy_regset_to_user(child, &user_ppc_native_view, |
| 906 | CHECK_FULL_REGS(child->thread.regs); | 804 | REGSET_FPR, |
| 907 | ret = 0; | 805 | 0, sizeof(elf_fpregset_t), |
| 908 | for (ui = 0; ui < PT_REGS_COUNT; ui ++) { | 806 | (void __user *) data); |
| 909 | ret = __get_user(tmp, (unsigned long __user *) data); | 807 | |
| 910 | if (ret) | 808 | case PTRACE_SETFPREGS: /* Set the child FPU state (FPR0...31 + FPSCR) */ |
| 911 | break; | 809 | return copy_regset_from_user(child, &user_ppc_native_view, |
| 912 | ptrace_put_reg(child, ui, tmp); | 810 | REGSET_FPR, |
| 913 | data += sizeof(long); | 811 | 0, sizeof(elf_fpregset_t), |
| 914 | } | 812 | (const void __user *) data); |
| 915 | break; | ||
| 916 | } | ||
| 917 | |||
| 918 | case PTRACE_GETFPREGS: { /* Get the child FPU state (FPR0...31 + FPSCR) */ | ||
| 919 | flush_fp_to_thread(child); | ||
| 920 | ret = get_fpregs((void __user *)data, child, 1); | ||
| 921 | break; | ||
| 922 | } | ||
| 923 | |||
| 924 | case PTRACE_SETFPREGS: { /* Set the child FPU state (FPR0...31 + FPSCR) */ | ||
| 925 | flush_fp_to_thread(child); | ||
| 926 | ret = set_fpregs((void __user *)data, child, 1); | ||
| 927 | break; | ||
| 928 | } | ||
| 929 | 813 | ||
| 930 | #ifdef CONFIG_ALTIVEC | 814 | #ifdef CONFIG_ALTIVEC |
| 931 | case PTRACE_GETVRREGS: | 815 | case PTRACE_GETVRREGS: |
| 932 | /* Get the child altivec register state. */ | 816 | return copy_regset_to_user(child, &user_ppc_native_view, |
| 933 | flush_altivec_to_thread(child); | 817 | REGSET_VMX, |
| 934 | ret = get_vrregs((unsigned long __user *)data, child); | 818 | 0, (33 * sizeof(vector128) + |
| 935 | break; | 819 | sizeof(u32)), |
| 820 | (void __user *) data); | ||
| 936 | 821 | ||
| 937 | case PTRACE_SETVRREGS: | 822 | case PTRACE_SETVRREGS: |
| 938 | /* Set the child altivec register state. */ | 823 | return copy_regset_from_user(child, &user_ppc_native_view, |
| 939 | flush_altivec_to_thread(child); | 824 | REGSET_VMX, |
| 940 | ret = set_vrregs(child, (unsigned long __user *)data); | 825 | 0, (33 * sizeof(vector128) + |
| 941 | break; | 826 | sizeof(u32)), |
| 827 | (const void __user *) data); | ||
| 942 | #endif | 828 | #endif |
| 943 | #ifdef CONFIG_SPE | 829 | #ifdef CONFIG_SPE |
| 944 | case PTRACE_GETEVRREGS: | 830 | case PTRACE_GETEVRREGS: |
| 945 | /* Get the child spe register state. */ | 831 | /* Get the child spe register state. */ |
| 946 | flush_spe_to_thread(child); | 832 | return copy_regset_to_user(child, &user_ppc_native_view, |
| 947 | ret = get_evrregs((unsigned long __user *)data, child); | 833 | REGSET_SPE, 0, 35 * sizeof(u32), |
| 948 | break; | 834 | (void __user *) data); |
| 949 | 835 | ||
| 950 | case PTRACE_SETEVRREGS: | 836 | case PTRACE_SETEVRREGS: |
| 951 | /* Set the child spe register state. */ | 837 | /* Set the child spe register state. */ |
| 952 | /* this is to clear the MSR_SPE bit to force a reload | 838 | return copy_regset_from_user(child, &user_ppc_native_view, |
| 953 | * of register state from memory */ | 839 | REGSET_SPE, 0, 35 * sizeof(u32), |
| 954 | flush_spe_to_thread(child); | 840 | (const void __user *) data); |
| 955 | ret = set_evrregs(child, (unsigned long __user *)data); | ||
| 956 | break; | ||
| 957 | #endif | 841 | #endif |
| 958 | 842 | ||
| 959 | /* Old reverse args ptrace callss */ | 843 | /* Old reverse args ptrace callss */ |
