struct arch_hw_breakpoint结构体
struct arch_hw_breakpoint结构体
watchpoint or breakpoint(type)、watchpoint监测的数据长度、监测的地址,这些信息都保存在arch_hw_breakpoint结构体里
struct arch_hw_breakpoint { u64 address; u64 trigger; struct arch_hw_breakpoint_ctrl ctrl; };
在arch_build_bp_info()里设置这个结构体:
对于设置watchpoint时,attr->bp_type值为HW_BREAKPOINT_W(2),然后将attr->bp_addr的值赋值给arch_hw_breakpoint结构类型的address成员。
attr->bp_len表示watchpoint监视的地址要监视多少个byte,比如值为8时,表示监视连续的8个字节,将这个len赋值给arch_hw_breakpoint里的ctrl.len成员,赋值给ctrl.len的len的含义用一个8bit的byte来表示某一个byte是否监视,比如bp_len是8时,赋值给ctrl.len的值为0xff,如果为7,则为0x7f。
dbgwcrx_el1 register bitfield描述如下,这里的ctrl.len即是BAS field,[12:5],一共8bit:
Figure 11.3. DBGWCRn_EL1 bit assignments
4.19/arch/arm64/kernel/hw_breakpoint.c
static int arch_build_bp_info(struct perf_event *bp, const struct perf_event_attr *attr, struct arch_hw_breakpoint *hw) { /* Type */ switch (attr->bp_type) { case HW_BREAKPOINT_X: hw->ctrl.type = ARM_BREAKPOINT_EXECUTE; break; case HW_BREAKPOINT_R: hw->ctrl.type = ARM_BREAKPOINT_LOAD; break; case HW_BREAKPOINT_W: hw->ctrl.type = ARM_BREAKPOINT_STORE; break; case HW_BREAKPOINT_RW: hw->ctrl.type = ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE; break; default: return -EINVAL; } /* Len */ switch (attr->bp_len) { case HW_BREAKPOINT_LEN_1: hw->ctrl.len = ARM_BREAKPOINT_LEN_1; break; case HW_BREAKPOINT_LEN_2: hw->ctrl.len = ARM_BREAKPOINT_LEN_2; break; case HW_BREAKPOINT_LEN_3: hw->ctrl.len = ARM_BREAKPOINT_LEN_3; break; case HW_BREAKPOINT_LEN_4: hw->ctrl.len = ARM_BREAKPOINT_LEN_4; break; case HW_BREAKPOINT_LEN_5: hw->ctrl.len = ARM_BREAKPOINT_LEN_5; break; case HW_BREAKPOINT_LEN_6: hw->ctrl.len = ARM_BREAKPOINT_LEN_6; break; case HW_BREAKPOINT_LEN_7: hw->ctrl.len = ARM_BREAKPOINT_LEN_7; break; case HW_BREAKPOINT_LEN_8: hw->ctrl.len = ARM_BREAKPOINT_LEN_8; break; default: return -EINVAL; } /* * On AArch64, we only permit breakpoints of length 4, whereas * AArch32 also requires breakpoints of length 2 for Thumb. * Watchpoints can be of length 1, 2, 4 or 8 bytes. */ if (hw->ctrl.type == ARM_BREAKPOINT_EXECUTE) { if (is_compat_bp(bp)) { if (hw->ctrl.len != ARM_BREAKPOINT_LEN_2 && hw->ctrl.len != ARM_BREAKPOINT_LEN_4) return -EINVAL; } else if (hw->ctrl.len != ARM_BREAKPOINT_LEN_4) { /* * FIXME: Some tools (I'm looking at you perf) assume * that breakpoints should be sizeof(long). This * is nonsense. For now, we fix up the parameter * but we should probably return -EINVAL instead. */ hw->ctrl.len = ARM_BREAKPOINT_LEN_4; } } /* Address */ hw->address = attr->bp_addr;
下面的hw_breakpoint_arch_parse()对于watchpoint,alignment_mask为0x7,如果address本身没有8对齐,则会将address向下对齐到8,同时ctrl.len也会左移对应的bit,比如address为0x5,则它会对齐到0x0,len为8(对应ctrl.len为0xff),offset为5,将0xff左移5bit得到0xe0,即只有最高3bit为1,表示只监视地址5/6/7,低位地址0-4不监视:
setup watchpoint时,调用hw_breakpoint_control(),在这个函数里ops参数值为0,即HW_BREAKPOINT_INSTALL:
[ 21.943510] hw-breakpoint: ops: 0, reg_enable: 1. [ 21.948240] CPU: 1 PID: 34 Comm: kworker/1:1 Tainted: P O 4.19.116+ #19 [ 21.956172] Hardware name: test_mach(DT) [ 21.959855] Workqueue: events watch_point_delayed_work_func [ 21.965433] Call trace: [ 21.967899] dump_backtrace+0x0/0x4 [ 21.971414] dump_stack+0xf4/0x134 [ 21.974829] hw_breakpoint_control+0x184/0x29c [ 21.979280] hw_breakpoint_add+0x80/0x8c [ 21.983210] event_sched_in+0x44c/0x718 [ 21.987049] group_sched_in+0x6c/0x218 [ 21.990816] pinned_sched_in+0x158/0x264 [ 21.994749] visit_groups_merge+0x140/0x1fc [ 21.998947] ctx_sched_in+0x1a4/0x1ec [ 22.002631] ctx_resched+0xdc/0x1e4 [ 22.006142] __perf_event_enable+0x1d0/0x2c4 [ 22.010420] event_function.9234+0x128/0x224 [ 22.014695] remote_function+0x74/0xb4 [ 22.018469] generic_exec_single+0x7c/0x1a4 [ 22.022679] smp_call_function_single+0xc0/0x1e8 [ 22.027320] event_function_call+0x84/0x274 [ 22.031512] perf_event_enable+0xec/0x158 [ 22.035527] _register_wp_bp+0x408/0x4b8 [ 22.039456] watch_point_delayed_work_func+0x68/0xcc [ 22.044443] process_one_work+0x3c0/0x670 [ 22.048478] worker_thread+0x32c/0x6d0 [ 22.052236] kthread+0x130/0x140 [ 22.055468] ret_from_fork+0x10/0x18