aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/ptrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/ptrace.c')
-rw-r--r--arch/powerpc/kernel/ptrace.c64
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
872void 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
869int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, 889int 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;