[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