@@ -680,6 +680,12 @@ static void disable_single_step(struct perf_event *bp)
680680 arch_install_hw_breakpoint (bp );
681681}
682682
683+ static int watchpoint_fault_on_uaccess (struct pt_regs * regs ,
684+ struct arch_hw_breakpoint * info )
685+ {
686+ return !user_mode (regs ) && info -> ctrl .privilege == ARM_BREAKPOINT_USER ;
687+ }
688+
683689static void watchpoint_handler (unsigned long addr , unsigned int fsr ,
684690 struct pt_regs * regs )
685691{
@@ -739,16 +745,27 @@ static void watchpoint_handler(unsigned long addr, unsigned int fsr,
739745 }
740746
741747 pr_debug ("watchpoint fired: address = 0x%x\n" , info -> trigger );
748+
749+ /*
750+ * If we triggered a user watchpoint from a uaccess routine,
751+ * then handle the stepping ourselves since userspace really
752+ * can't help us with this.
753+ */
754+ if (watchpoint_fault_on_uaccess (regs , info ))
755+ goto step ;
756+
742757 perf_bp_event (wp , regs );
743758
744759 /*
745- * If no overflow handler is present, insert a temporary
746- * mismatch breakpoint so we can single-step over the
747- * watchpoint trigger.
760+ * Defer stepping to the overflow handler if one is installed.
761+ * Otherwise, insert a temporary mismatch breakpoint so that
762+ * we can single-step over the watchpoint trigger.
748763 */
749- if (is_default_overflow_handler (wp ))
750- enable_single_step ( wp , instruction_pointer ( regs )) ;
764+ if (! is_default_overflow_handler (wp ))
765+ goto unlock ;
751766
767+ step :
768+ enable_single_step (wp , instruction_pointer (regs ));
752769unlock :
753770 rcu_read_unlock ();
754771 }
0 commit comments