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

Figure 11.3. DBGWCR

 

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

 

posted @ 2021-12-06 20:25  aspirs  阅读(155)  评论(0编辑  收藏  举报