|
@@ -349,7 +349,7 @@ int arch_check_bp_in_kernelspace(struct perf_event *bp)
|
|
* to generic breakpoint descriptions.
|
|
* to generic breakpoint descriptions.
|
|
*/
|
|
*/
|
|
int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
|
|
int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
|
|
- int *gen_len, int *gen_type)
|
|
|
|
|
|
+ int *gen_len, int *gen_type, int *offset)
|
|
{
|
|
{
|
|
/* Type */
|
|
/* Type */
|
|
switch (ctrl.type) {
|
|
switch (ctrl.type) {
|
|
@@ -369,8 +369,12 @@ int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (!ctrl.len)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ *offset = __ffs(ctrl.len);
|
|
|
|
+
|
|
/* Len */
|
|
/* Len */
|
|
- switch (ctrl.len) {
|
|
|
|
|
|
+ switch (ctrl.len >> *offset) {
|
|
case ARM_BREAKPOINT_LEN_1:
|
|
case ARM_BREAKPOINT_LEN_1:
|
|
*gen_len = HW_BREAKPOINT_LEN_1;
|
|
*gen_len = HW_BREAKPOINT_LEN_1;
|
|
break;
|
|
break;
|
|
@@ -517,18 +521,17 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
|
|
default:
|
|
default:
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
-
|
|
|
|
- info->address &= ~alignment_mask;
|
|
|
|
- info->ctrl.len <<= offset;
|
|
|
|
} else {
|
|
} else {
|
|
if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE)
|
|
if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE)
|
|
alignment_mask = 0x3;
|
|
alignment_mask = 0x3;
|
|
else
|
|
else
|
|
alignment_mask = 0x7;
|
|
alignment_mask = 0x7;
|
|
- if (info->address & alignment_mask)
|
|
|
|
- return -EINVAL;
|
|
|
|
|
|
+ offset = info->address & alignment_mask;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ info->address &= ~alignment_mask;
|
|
|
|
+ info->ctrl.len <<= offset;
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Disallow per-task kernel breakpoints since these would
|
|
* Disallow per-task kernel breakpoints since these would
|
|
* complicate the stepping code.
|
|
* complicate the stepping code.
|
|
@@ -665,8 +668,8 @@ static int watchpoint_handler(unsigned long addr, unsigned int esr,
|
|
struct pt_regs *regs)
|
|
struct pt_regs *regs)
|
|
{
|
|
{
|
|
int i, step = 0, *kernel_step, access;
|
|
int i, step = 0, *kernel_step, access;
|
|
- u32 ctrl_reg;
|
|
|
|
- u64 val, alignment_mask;
|
|
|
|
|
|
+ u32 ctrl_reg, lens, lene;
|
|
|
|
+ u64 val;
|
|
struct perf_event *wp, **slots;
|
|
struct perf_event *wp, **slots;
|
|
struct debug_info *debug_info;
|
|
struct debug_info *debug_info;
|
|
struct arch_hw_breakpoint *info;
|
|
struct arch_hw_breakpoint *info;
|
|
@@ -684,25 +687,21 @@ static int watchpoint_handler(unsigned long addr, unsigned int esr,
|
|
goto unlock;
|
|
goto unlock;
|
|
|
|
|
|
info = counter_arch_bp(wp);
|
|
info = counter_arch_bp(wp);
|
|
- /* AArch32 watchpoints are either 4 or 8 bytes aligned. */
|
|
|
|
- if (is_compat_task()) {
|
|
|
|
- if (info->ctrl.len == ARM_BREAKPOINT_LEN_8)
|
|
|
|
- alignment_mask = 0x7;
|
|
|
|
- else
|
|
|
|
- alignment_mask = 0x3;
|
|
|
|
- } else {
|
|
|
|
- alignment_mask = 0x7;
|
|
|
|
- }
|
|
|
|
|
|
|
|
- /* Check if the watchpoint value matches. */
|
|
|
|
|
|
+ /* Check if the watchpoint value and byte select match. */
|
|
val = read_wb_reg(AARCH64_DBG_REG_WVR, i);
|
|
val = read_wb_reg(AARCH64_DBG_REG_WVR, i);
|
|
- if (val != (addr & ~alignment_mask))
|
|
|
|
- goto unlock;
|
|
|
|
-
|
|
|
|
- /* Possible match, check the byte address select to confirm. */
|
|
|
|
ctrl_reg = read_wb_reg(AARCH64_DBG_REG_WCR, i);
|
|
ctrl_reg = read_wb_reg(AARCH64_DBG_REG_WCR, i);
|
|
decode_ctrl_reg(ctrl_reg, &ctrl);
|
|
decode_ctrl_reg(ctrl_reg, &ctrl);
|
|
- if (!((1 << (addr & alignment_mask)) & ctrl.len))
|
|
|
|
|
|
+ lens = ffs(ctrl.len) - 1;
|
|
|
|
+ lene = fls(ctrl.len) - 1;
|
|
|
|
+ /*
|
|
|
|
+ * FIXME: reported address can be anywhere between "the
|
|
|
|
+ * lowest address accessed by the memory access that
|
|
|
|
+ * triggered the watchpoint" and "the highest watchpointed
|
|
|
|
+ * address accessed by the memory access". So, it may not
|
|
|
|
+ * lie in the interval of watchpoint address range.
|
|
|
|
+ */
|
|
|
|
+ if (addr < val + lens || addr > val + lene)
|
|
goto unlock;
|
|
goto unlock;
|
|
|
|
|
|
/*
|
|
/*
|