| @@ -683,6 +683,12 @@ static void disable_single_step(struct perf_event *bp) · 682 unmodified lines |
| 683 | 683 | arch_install_hw_breakpoint(bp); |
| 684 | 684 | } |
| 685 | 685 | |
| 686 | +static int watchpoint_fault_on_uaccess(struct pt_regs *regs, |
| 687 | + struct arch_hw_breakpoint *info) |
| 688 | +{ |
| 689 | + return !user_mode(regs) && info->ctrl.privilege == ARM_BREAKPOINT_USER; |
| 690 | +} |
| 691 | + |
| 686 | 692 | static void watchpoint_handler(unsigned long addr, unsigned int fsr, |
| 687 | 693 | struct pt_regs *regs) |
| 688 | 694 | { |
| @@ -742,16 +748,27 @@ static void watchpoint_handler(unsigned long addr, unsigned int fsr, · 53 unmodified lines |
| 742 | 748 | } |
| 743 | 749 | |
| 744 | 750 | pr_debug("watchpoint fired: address = 0x%x\n", info->trigger); |
| 751 | + |
| 752 | + /* |
| 753 | + * If we triggered a user watchpoint from a uaccess routine, |
| 754 | + * then handle the stepping ourselves since userspace really |
| 755 | + * can't help us with this. |
| 756 | + */ |
| 757 | + if (watchpoint_fault_on_uaccess(regs, info)) |
| 758 | + goto step; |
| 759 | + |
| 745 | 760 | perf_bp_event(wp, regs); |
| 746 | 761 | |
| 747 | 762 | /* |
| 748 | | − * If no overflow handler is present, insert a temporary |
| 749 | | − * mismatch breakpoint so we can single-step over the |
| 750 | | − * watchpoint trigger. |
| 763 | + * Defer stepping to the overflow handler if one is installed. |
| 764 | + * Otherwise, insert a temporary mismatch breakpoint so that |
| 765 | + * we can single-step over the watchpoint trigger. |
| 751 | 766 | */ |
| 752 | | − if (is_default_overflow_handler(wp)) |
| 753 | | − enable_single_step(wp, instruction_pointer(regs)); |
| 767 | + if (!is_default_overflow_handler(wp)) |
| 768 | + goto unlock; |
| 754 | 769 | |
| 770 | +step: |
| 771 | + enable_single_step(wp, instruction_pointer(regs)); |
| 755 | 772 | unlock: |
| 756 | 773 | rcu_read_unlock(); |
| 757 | 774 | } |