[QUESTION] arm: perf_events: HW breakpoint continually triggers handler callback

From: Andrii Veres <hidden>
Date: 2019-05-26 14:30:26

Hello.

I observed difference in HW breakpoint, behaviour (CPU watch registers)
for x86_64 and ARM architectures:

ARM (QUEMU): HW breakpoint handler continuing calls in infinite loop
after first access to monitored memory after HW breakpoint registartion.

x86_64 (VirtualBox): HW breakpoint handler calls once each time, when
required access to monitored memory, till HW breakpoint unregistration.

Verivied in: v5.0

Example of usage: /samples/hw_breakpoint/data_breakpoint.c

NOTE: according to some info, described in: 
(https://stackoverflow.com/questions/28280813/register-wide-hw-breakpoint-continually-triggers-handler-callback)
ARM core have specific instruction execution, so as workaround proposed
to do HW breakpoint unregistration in HW breakpoint handler for preventing
infinite loop of calls.

QUESTION: so workaround is the final solution for comfortable usage of
HW breakpoint, for example in debug cases when need to track
access for memory from undefined source? But between HW breakpoint
unregistration and re-registration possibly access to memory can`t
be tracked? Or NOTE is not fully correct, and possible there is
some way, that makes possible change behaviour of ARM HW breakpoint
as well, as for x86_64 (i.e. call HW breakpoint handler once each
time, when required access ti monitored memory)?


Best regards, Andrii Veres.

APPENDIX A: EXAMPLE, THAT I USED FOR TESTS ON x86_64 AND ARM

/*
 * hello_watchpoint.c - Kernel module, that register watchpoint
 * on test val (test_val) and trigger it usage by postincrement usage
 * BUG:  infinite loop of calls of sample_hbp_handler() can be fixed only by call
 *       unregister_wide_hw_breakpoint() inside it.
 */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/perf_event.h>
#include <linux/hw_breakpoint.h>

MODULE_LICENSE    ("GPL");
MODULE_DESCRIPTION("Hello Watchpoint, simple module for work with CPU watch register");

/* Module parameters */

int test_val = 0;
struct perf_event * __percpu *sample_hbp;

static void sample_hbp_handler(struct perf_event *bp, struct perf_sample_data *data, struct pt_regs *regs)
{
    printk("WATCHPOINT value is changed\n");
    //dump_stack();
    printk("WATCHPOINT Dump stack from sample_hbp_handler\n");
    //unregister_wide_hw_breakpoint(sample_hbp); /* CAN BREAK INFINITE LOOP */
}

static int __init hello_init(void)
{
    struct perf_event_attr attr;

    hw_breakpoint_init(&attr);
    attr.bp_addr = (unsigned long)((void *)&(test_val));
    attr.bp_len  = HW_BREAKPOINT_LEN_4;
    attr.bp_type = HW_BREAKPOINT_RW;

    sample_hbp = register_wide_hw_breakpoint(&attr, sample_hbp_handler, NULL);
    if (IS_ERR((void __force *)sample_hbp)) {
        printk("WATCHPOINT: %s %d failed to register HW BREAKPOINT \n",__func__,__LINE__);
    } else {
        printk("WATCHPOINT: %s %d successfully registered HW BREAKPOINT \n",__func__,__LINE__);
    }

    test_val++;
    return 0;
}

static void __exit hello_exit(void)
{
    printk("WATCHPOINT: module de-initialization success");
    
    unregister_wide_hw_breakpoint(sample_hbp);
}

module_init(hello_init);
module_exit(hello_exit);


APPENDIX B: x86_64 LOG

[ 1195.324243] hello_watchpoint: loading out-of-tree module taints kernel.
[ 1195.324315] hello_watchpoint: module verification failed: signature and/or required key missing - tainting kernel
[ 1195.325593] WATCHPOINT: hello_init 44 successfully registered HW BREAKPOINT 
[ 1195.325603] WATCHPOINT value is changed
[ 1195.325604] WATCHPOINT Dump stack from sample_hbp_handler
[ 1222.021365] WATCHPOINT: module de-initialization success

APPENDIX C: ARM LOG

[   96.212220] hello_watchpoint: loading out-of-tree module taints kernel.
[   96.212321] hello_watchpoint: module verification failed: signature and/or required key missing - tainting kernel
[   96.212425] WATCHPOINT: hello_init 44 successfully registered HW BREAKPOINT 
[   96.212536] WATCHPOINT value is changed
[   96.212688] WATCHPOINT Dump stack from sample_hbp_handler
[   96.212711] WATCHPOINT: module de-initialization success
[   96.212890] WATCHPOINT: hello_init 44 successfully registered HW BREAKPOINT 
[   96.213113] WATCHPOINT value is changed
[   96.212320] WATCHPOINT Dump stack from sample_hbp_handler
[   96.213601] WATCHPOINT value is changed
[   96.213884] WATCHPOINT Dump stack from sample_hbp_handler
[   96.214326] WATCHPOINT value is changed
[   96.214618] WATCHPOINT Dump stack from sample_hbp_handler
[   96.215048] WATCHPOINT value is changed
[   96.215335] WATCHPOINT Dump stack from sample_hbp_handler
[   96.215756] WATCHPOINT value is changed
[   96.216031] WATCHPOINT Dump stack from sample_hbp_handler
[   96.216419] WATCHPOINT value is changed
[   96.216691] WATCHPOINT Dump stack from sample_hbp_handler
[   96.217413] WATCHPOINT value is changed
[   96.217743] WATCHPOINT Dump stack from sample_hbp_handler
[   96.218217] WATCHPOINT value is changed
[   96.218524] WATCHPOINT Dump stack from sample_hbp_handler
[   96.218967] WATCHPOINT value is changed
[   96.219255] WATCHPOINT Dump stack from sample_hbp_handler
[   96.219673] WATCHPOINT value is changed
[   96.219947] WATCHPOINT Dump stack from sample_hbp_handler
[   96.220360] WATCHPOINT value is changed
[   96.220639] WATCHPOINT Dump stack from sample_hbp_handler
[   96.221028] WATCHPOINT value is changed
[   96.221296] WATCHPOINT Dump stack from sample_hbp_handler
[   96.221688] WATCHPOINT value is changed
[   96.221977] WATCHPOINT Dump stack from sample_hbp_handler
[   96.222355] WATCHPOINT value is changed
[   96.222660] WATCHPOINT Dump stack from sample_hbp_handler
QEMU: Terminated
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help