diff options
Diffstat (limited to 'arch/powerpc/kernel/ptrace.c')
-rw-r--r-- | arch/powerpc/kernel/ptrace.c | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 7a0c0199ea28..11f3cd9c832f 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c | |||
@@ -32,6 +32,8 @@ | |||
32 | #ifdef CONFIG_PPC32 | 32 | #ifdef CONFIG_PPC32 |
33 | #include <linux/module.h> | 33 | #include <linux/module.h> |
34 | #endif | 34 | #endif |
35 | #include <linux/hw_breakpoint.h> | ||
36 | #include <linux/perf_event.h> | ||
35 | 37 | ||
36 | #include <asm/uaccess.h> | 38 | #include <asm/uaccess.h> |
37 | #include <asm/page.h> | 39 | #include <asm/page.h> |
@@ -866,9 +868,34 @@ void user_disable_single_step(struct task_struct *task) | |||
866 | clear_tsk_thread_flag(task, TIF_SINGLESTEP); | 868 | clear_tsk_thread_flag(task, TIF_SINGLESTEP); |
867 | } | 869 | } |
868 | 870 | ||
871 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | ||
872 | void ptrace_triggered(struct perf_event *bp, int nmi, | ||
873 | struct perf_sample_data *data, struct pt_regs *regs) | ||
874 | { | ||
875 | struct perf_event_attr attr; | ||
876 | |||
877 | /* | ||
878 | * Disable the breakpoint request here since ptrace has defined a | ||
879 | * one-shot behaviour for breakpoint exceptions in PPC64. | ||
880 | * The SIGTRAP signal is generated automatically for us in do_dabr(). | ||
881 | * We don't have to do anything about that here | ||
882 | */ | ||
883 | attr = bp->attr; | ||
884 | attr.disabled = true; | ||
885 | modify_user_hw_breakpoint(bp, &attr); | ||
886 | } | ||
887 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ | ||
888 | |||
869 | int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, | 889 | int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, |
870 | unsigned long data) | 890 | unsigned long data) |
871 | { | 891 | { |
892 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | ||
893 | int ret; | ||
894 | struct thread_struct *thread = &(task->thread); | ||
895 | struct perf_event *bp; | ||
896 | struct perf_event_attr attr; | ||
897 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ | ||
898 | |||
872 | /* For ppc64 we support one DABR and no IABR's at the moment (ppc64). | 899 | /* For ppc64 we support one DABR and no IABR's at the moment (ppc64). |
873 | * For embedded processors we support one DAC and no IAC's at the | 900 | * For embedded processors we support one DAC and no IAC's at the |
874 | * moment. | 901 | * moment. |
@@ -896,6 +923,43 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, | |||
896 | /* Ensure breakpoint translation bit is set */ | 923 | /* Ensure breakpoint translation bit is set */ |
897 | if (data && !(data & DABR_TRANSLATION)) | 924 | if (data && !(data & DABR_TRANSLATION)) |
898 | return -EIO; | 925 | return -EIO; |
926 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | ||
927 | bp = thread->ptrace_bps[0]; | ||
928 | if ((!data) || !(data & (DABR_DATA_WRITE | DABR_DATA_READ))) { | ||
929 | if (bp) { | ||
930 | unregister_hw_breakpoint(bp); | ||
931 | thread->ptrace_bps[0] = NULL; | ||
932 | } | ||
933 | return 0; | ||
934 | } | ||
935 | if (bp) { | ||
936 | attr = bp->attr; | ||
937 | attr.bp_addr = data & ~HW_BREAKPOINT_ALIGN; | ||
938 | arch_bp_generic_fields(data & | ||
939 | (DABR_DATA_WRITE | DABR_DATA_READ), | ||
940 | &attr.bp_type); | ||
941 | ret = modify_user_hw_breakpoint(bp, &attr); | ||
942 | if (ret) | ||
943 | return ret; | ||
944 | thread->ptrace_bps[0] = bp; | ||
945 | thread->dabr = data; | ||
946 | return 0; | ||
947 | } | ||
948 | |||
949 | /* Create a new breakpoint request if one doesn't exist already */ | ||
950 | hw_breakpoint_init(&attr); | ||
951 | attr.bp_addr = data & ~HW_BREAKPOINT_ALIGN; | ||
952 | arch_bp_generic_fields(data & (DABR_DATA_WRITE | DABR_DATA_READ), | ||
953 | &attr.bp_type); | ||
954 | |||
955 | thread->ptrace_bps[0] = bp = register_user_hw_breakpoint(&attr, | ||
956 | ptrace_triggered, task); | ||
957 | if (IS_ERR(bp)) { | ||
958 | thread->ptrace_bps[0] = NULL; | ||
959 | return PTR_ERR(bp); | ||
960 | } | ||
961 | |||
962 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ | ||
899 | 963 | ||
900 | /* Move contents to the DABR register */ | 964 | /* Move contents to the DABR register */ |
901 | task->thread.dabr = data; | 965 | task->thread.dabr = data; |