summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/kernel/hw_breakpoint.c25
-rw-r--r--arch/arm64/kernel/hw_breakpoint.c4
-rw-r--r--include/linux/perf_event.h6
-rw-r--r--kernel/events/core.c14
4 files changed, 24 insertions, 25 deletions
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c
index 78c6be1b2714..89fd86301242 100644
--- a/arch/arm/kernel/hw_breakpoint.c
+++ b/arch/arm/kernel/hw_breakpoint.c
@@ -631,7 +631,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
info->address &= ~alignment_mask;
info->ctrl.len <<= offset;
- if (!bp->overflow_handler) {
+ if (is_default_overflow_handler(bp)) {
/*
* Mismatch breakpoints are required for single-stepping
* breakpoints.
@@ -688,12 +688,6 @@ static void disable_single_step(struct perf_event *bp)
arch_install_hw_breakpoint(bp);
}
-static int watchpoint_fault_on_uaccess(struct pt_regs *regs,
- struct arch_hw_breakpoint *info)
-{
- return !user_mode(regs) && info->ctrl.privilege == ARM_BREAKPOINT_USER;
-}
-
static void watchpoint_handler(unsigned long addr, unsigned int fsr,
struct pt_regs *regs)
{
@@ -760,20 +754,17 @@ static void watchpoint_handler(unsigned long addr, unsigned int fsr,
* can't help us with this.
*/
if (watchpoint_fault_on_uaccess(regs, info))
- goto step;
+ enable_single_step(wp, instruction_pointer(regs));
perf_bp_event(wp, regs);
/*
- * Defer stepping to the overflow handler if one is installed.
- * Otherwise, insert a temporary mismatch breakpoint so that
- * we can single-step over the watchpoint trigger.
+ * If no overflow handler is present, insert a temporary
+ * mismatch breakpoint so we can single-step over the
+ * watchpoint trigger.
*/
- if (wp->overflow_handler)
- goto unlock;
-
-step:
- enable_single_step(wp, instruction_pointer(regs));
+ if (is_default_overflow_handler(wp))
+ enable_single_step(wp, instruction_pointer(regs));
unlock:
rcu_read_unlock();
}
@@ -1163,4 +1154,4 @@ int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
unsigned long val, void *data)
{
return NOTIFY_DONE;
-}
+} \ No newline at end of file
diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
index bef4b659d816..3530541b3f5b 100644
--- a/arch/arm64/kernel/hw_breakpoint.c
+++ b/arch/arm64/kernel/hw_breakpoint.c
@@ -662,7 +662,7 @@ static int breakpoint_handler(unsigned long unused, unsigned int esr,
perf_bp_event(bp, regs);
/* Do we need to handle the stepping? */
- if (!bp->overflow_handler)
+ if (is_default_overflow_handler(bp))
step = 1;
unlock:
rcu_read_unlock();
@@ -788,7 +788,7 @@ static int watchpoint_handler(unsigned long addr, unsigned int esr,
perf_bp_event(wp, regs);
/* Do we need to handle the stepping? */
- if (!wp->overflow_handler)
+ if (is_default_overflow_handler(wp))
step = 1;
}
if (min_dist > 0 && min_dist != -1) {
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 8e50962b984b..f29f84898698 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -863,6 +863,12 @@ extern void perf_event_output(struct perf_event *event,
struct perf_sample_data *data,
struct pt_regs *regs);
+static inline bool
+is_default_overflow_handler(struct perf_event *event)
+{
+ return (event->overflow_handler == perf_event_output);
+}
+
extern void
perf_event_header__init_id(struct perf_event_header *header,
struct perf_sample_data *data,
diff --git a/kernel/events/core.c b/kernel/events/core.c
index befba6489d5e..658f21d9b180 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -6700,10 +6700,7 @@ static int __perf_event_overflow(struct perf_event *event,
irq_work_queue(&event->pending);
}
- if (event->overflow_handler)
- event->overflow_handler(event, data, regs);
- else
- perf_event_output(event, data, regs);
+ event->overflow_handler(event, data, regs);
if (*perf_event_fasync(event) && event->pending_kill) {
event->pending_wakeup = 1;
@@ -8209,8 +8206,13 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
context = parent_event->overflow_handler_context;
}
- event->overflow_handler = overflow_handler;
- event->overflow_handler_context = context;
+ if (overflow_handler) {
+ event->overflow_handler = overflow_handler;
+ event->overflow_handler_context = context;
+ } else {
+ event->overflow_handler = perf_event_output;
+ event->overflow_handler_context = NULL;
+ }
perf_event__state_init(event);