diff options
Diffstat (limited to 'arch/powerpc/kernel/ptrace.c')
-rw-r--r-- | arch/powerpc/kernel/ptrace.c | 64 |
1 files changed, 30 insertions, 34 deletions
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index a5d0e78779c8..3635be61f899 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/errno.h> | 22 | #include <linux/errno.h> |
23 | #include <linux/ptrace.h> | 23 | #include <linux/ptrace.h> |
24 | #include <linux/regset.h> | 24 | #include <linux/regset.h> |
25 | #include <linux/tracehook.h> | ||
25 | #include <linux/elf.h> | 26 | #include <linux/elf.h> |
26 | #include <linux/user.h> | 27 | #include <linux/user.h> |
27 | #include <linux/security.h> | 28 | #include <linux/security.h> |
@@ -374,7 +375,7 @@ static int vsr_get(struct task_struct *target, const struct user_regset *regset, | |||
374 | flush_vsx_to_thread(target); | 375 | flush_vsx_to_thread(target); |
375 | 376 | ||
376 | for (i = 0; i < 32 ; i++) | 377 | for (i = 0; i < 32 ; i++) |
377 | buf[i] = current->thread.fpr[i][TS_VSRLOWOFFSET]; | 378 | buf[i] = target->thread.fpr[i][TS_VSRLOWOFFSET]; |
378 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | 379 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
379 | buf, 0, 32 * sizeof(double)); | 380 | buf, 0, 32 * sizeof(double)); |
380 | 381 | ||
@@ -393,7 +394,7 @@ static int vsr_set(struct task_struct *target, const struct user_regset *regset, | |||
393 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | 394 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, |
394 | buf, 0, 32 * sizeof(double)); | 395 | buf, 0, 32 * sizeof(double)); |
395 | for (i = 0; i < 32 ; i++) | 396 | for (i = 0; i < 32 ; i++) |
396 | current->thread.fpr[i][TS_VSRLOWOFFSET] = buf[i]; | 397 | target->thread.fpr[i][TS_VSRLOWOFFSET] = buf[i]; |
397 | 398 | ||
398 | 399 | ||
399 | return ret; | 400 | return ret; |
@@ -717,7 +718,7 @@ void user_disable_single_step(struct task_struct *task) | |||
717 | struct pt_regs *regs = task->thread.regs; | 718 | struct pt_regs *regs = task->thread.regs; |
718 | 719 | ||
719 | 720 | ||
720 | #if defined(CONFIG_44x) || defined(CONFIG_BOOKE) | 721 | #if defined(CONFIG_BOOKE) |
721 | /* If DAC then do not single step, skip */ | 722 | /* If DAC then do not single step, skip */ |
722 | if (task->thread.dabr) | 723 | if (task->thread.dabr) |
723 | return; | 724 | return; |
@@ -744,10 +745,11 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, | |||
744 | if (addr > 0) | 745 | if (addr > 0) |
745 | return -EINVAL; | 746 | return -EINVAL; |
746 | 747 | ||
748 | /* The bottom 3 bits in dabr are flags */ | ||
747 | if ((data & ~0x7UL) >= TASK_SIZE) | 749 | if ((data & ~0x7UL) >= TASK_SIZE) |
748 | return -EIO; | 750 | return -EIO; |
749 | 751 | ||
750 | #ifdef CONFIG_PPC64 | 752 | #ifndef CONFIG_BOOKE |
751 | 753 | ||
752 | /* For processors using DABR (i.e. 970), the bottom 3 bits are flags. | 754 | /* For processors using DABR (i.e. 970), the bottom 3 bits are flags. |
753 | * It was assumed, on previous implementations, that 3 bits were | 755 | * It was assumed, on previous implementations, that 3 bits were |
@@ -769,7 +771,7 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, | |||
769 | task->thread.dabr = data; | 771 | task->thread.dabr = data; |
770 | 772 | ||
771 | #endif | 773 | #endif |
772 | #if defined(CONFIG_44x) || defined(CONFIG_BOOKE) | 774 | #if defined(CONFIG_BOOKE) |
773 | 775 | ||
774 | /* As described above, it was assumed 3 bits were passed with the data | 776 | /* As described above, it was assumed 3 bits were passed with the data |
775 | * address, but we will assume only the mode bits will be passed | 777 | * address, but we will assume only the mode bits will be passed |
@@ -973,15 +975,13 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
973 | case PTRACE_GETVSRREGS: | 975 | case PTRACE_GETVSRREGS: |
974 | return copy_regset_to_user(child, &user_ppc_native_view, | 976 | return copy_regset_to_user(child, &user_ppc_native_view, |
975 | REGSET_VSX, | 977 | REGSET_VSX, |
976 | 0, (32 * sizeof(vector128) + | 978 | 0, 32 * sizeof(double), |
977 | sizeof(u32)), | ||
978 | (void __user *) data); | 979 | (void __user *) data); |
979 | 980 | ||
980 | case PTRACE_SETVSRREGS: | 981 | case PTRACE_SETVSRREGS: |
981 | return copy_regset_from_user(child, &user_ppc_native_view, | 982 | return copy_regset_from_user(child, &user_ppc_native_view, |
982 | REGSET_VSX, | 983 | REGSET_VSX, |
983 | 0, (32 * sizeof(vector128) + | 984 | 0, 32 * sizeof(double), |
984 | sizeof(u32)), | ||
985 | (const void __user *) data); | 985 | (const void __user *) data); |
986 | #endif | 986 | #endif |
987 | #ifdef CONFIG_SPE | 987 | #ifdef CONFIG_SPE |
@@ -1013,31 +1013,24 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
1013 | return ret; | 1013 | return ret; |
1014 | } | 1014 | } |
1015 | 1015 | ||
1016 | static void do_syscall_trace(void) | 1016 | /* |
1017 | * We must return the syscall number to actually look up in the table. | ||
1018 | * This can be -1L to skip running any syscall at all. | ||
1019 | */ | ||
1020 | long do_syscall_trace_enter(struct pt_regs *regs) | ||
1017 | { | 1021 | { |
1018 | /* the 0x80 provides a way for the tracing parent to distinguish | 1022 | long ret = 0; |
1019 | between a syscall stop and SIGTRAP delivery */ | ||
1020 | ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) | ||
1021 | ? 0x80 : 0)); | ||
1022 | |||
1023 | /* | ||
1024 | * this isn't the same as continuing with a signal, but it will do | ||
1025 | * for normal use. strace only continues with a signal if the | ||
1026 | * stopping signal is not SIGTRAP. -brl | ||
1027 | */ | ||
1028 | if (current->exit_code) { | ||
1029 | send_sig(current->exit_code, current, 1); | ||
1030 | current->exit_code = 0; | ||
1031 | } | ||
1032 | } | ||
1033 | 1023 | ||
1034 | void do_syscall_trace_enter(struct pt_regs *regs) | ||
1035 | { | ||
1036 | secure_computing(regs->gpr[0]); | 1024 | secure_computing(regs->gpr[0]); |
1037 | 1025 | ||
1038 | if (test_thread_flag(TIF_SYSCALL_TRACE) | 1026 | if (test_thread_flag(TIF_SYSCALL_TRACE) && |
1039 | && (current->ptrace & PT_PTRACED)) | 1027 | tracehook_report_syscall_entry(regs)) |
1040 | do_syscall_trace(); | 1028 | /* |
1029 | * Tracing decided this syscall should not happen. | ||
1030 | * We'll return a bogus call number to get an ENOSYS | ||
1031 | * error, but leave the original number in regs->gpr[0]. | ||
1032 | */ | ||
1033 | ret = -1L; | ||
1041 | 1034 | ||
1042 | if (unlikely(current->audit_context)) { | 1035 | if (unlikely(current->audit_context)) { |
1043 | #ifdef CONFIG_PPC64 | 1036 | #ifdef CONFIG_PPC64 |
@@ -1055,16 +1048,19 @@ void do_syscall_trace_enter(struct pt_regs *regs) | |||
1055 | regs->gpr[5] & 0xffffffff, | 1048 | regs->gpr[5] & 0xffffffff, |
1056 | regs->gpr[6] & 0xffffffff); | 1049 | regs->gpr[6] & 0xffffffff); |
1057 | } | 1050 | } |
1051 | |||
1052 | return ret ?: regs->gpr[0]; | ||
1058 | } | 1053 | } |
1059 | 1054 | ||
1060 | void do_syscall_trace_leave(struct pt_regs *regs) | 1055 | void do_syscall_trace_leave(struct pt_regs *regs) |
1061 | { | 1056 | { |
1057 | int step; | ||
1058 | |||
1062 | if (unlikely(current->audit_context)) | 1059 | if (unlikely(current->audit_context)) |
1063 | audit_syscall_exit((regs->ccr&0x10000000)?AUDITSC_FAILURE:AUDITSC_SUCCESS, | 1060 | audit_syscall_exit((regs->ccr&0x10000000)?AUDITSC_FAILURE:AUDITSC_SUCCESS, |
1064 | regs->result); | 1061 | regs->result); |
1065 | 1062 | ||
1066 | if ((test_thread_flag(TIF_SYSCALL_TRACE) | 1063 | step = test_thread_flag(TIF_SINGLESTEP); |
1067 | || test_thread_flag(TIF_SINGLESTEP)) | 1064 | if (step || test_thread_flag(TIF_SYSCALL_TRACE)) |
1068 | && (current->ptrace & PT_PTRACED)) | 1065 | tracehook_report_syscall_exit(regs, step); |
1069 | do_syscall_trace(); | ||
1070 | } | 1066 | } |