|
@@ -239,19 +239,20 @@ int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw)
|
|
|
return (va >= TASK_SIZE_MAX) || ((va + len - 1) >= TASK_SIZE_MAX);
|
|
|
}
|
|
|
|
|
|
-static int arch_build_bp_info(struct perf_event *bp)
|
|
|
+static int arch_build_bp_info(struct perf_event *bp,
|
|
|
+ const struct perf_event_attr *attr,
|
|
|
+ struct arch_hw_breakpoint *hw)
|
|
|
{
|
|
|
- struct arch_hw_breakpoint *info = counter_arch_bp(bp);
|
|
|
-
|
|
|
- info->address = bp->attr.bp_addr;
|
|
|
+ hw->address = attr->bp_addr;
|
|
|
+ hw->mask = 0;
|
|
|
|
|
|
/* Type */
|
|
|
- switch (bp->attr.bp_type) {
|
|
|
+ switch (attr->bp_type) {
|
|
|
case HW_BREAKPOINT_W:
|
|
|
- info->type = X86_BREAKPOINT_WRITE;
|
|
|
+ hw->type = X86_BREAKPOINT_WRITE;
|
|
|
break;
|
|
|
case HW_BREAKPOINT_W | HW_BREAKPOINT_R:
|
|
|
- info->type = X86_BREAKPOINT_RW;
|
|
|
+ hw->type = X86_BREAKPOINT_RW;
|
|
|
break;
|
|
|
case HW_BREAKPOINT_X:
|
|
|
/*
|
|
@@ -259,23 +260,23 @@ static int arch_build_bp_info(struct perf_event *bp)
|
|
|
* acceptable for kprobes. On non-kprobes kernels, we don't
|
|
|
* allow kernel breakpoints at all.
|
|
|
*/
|
|
|
- if (bp->attr.bp_addr >= TASK_SIZE_MAX) {
|
|
|
+ if (attr->bp_addr >= TASK_SIZE_MAX) {
|
|
|
#ifdef CONFIG_KPROBES
|
|
|
- if (within_kprobe_blacklist(bp->attr.bp_addr))
|
|
|
+ if (within_kprobe_blacklist(attr->bp_addr))
|
|
|
return -EINVAL;
|
|
|
#else
|
|
|
return -EINVAL;
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
- info->type = X86_BREAKPOINT_EXECUTE;
|
|
|
+ hw->type = X86_BREAKPOINT_EXECUTE;
|
|
|
/*
|
|
|
* x86 inst breakpoints need to have a specific undefined len.
|
|
|
* But we still need to check userspace is not trying to setup
|
|
|
* an unsupported length, to get a range breakpoint for example.
|
|
|
*/
|
|
|
- if (bp->attr.bp_len == sizeof(long)) {
|
|
|
- info->len = X86_BREAKPOINT_LEN_X;
|
|
|
+ if (attr->bp_len == sizeof(long)) {
|
|
|
+ hw->len = X86_BREAKPOINT_LEN_X;
|
|
|
return 0;
|
|
|
}
|
|
|
default:
|
|
@@ -283,28 +284,26 @@ static int arch_build_bp_info(struct perf_event *bp)
|
|
|
}
|
|
|
|
|
|
/* Len */
|
|
|
- info->mask = 0;
|
|
|
-
|
|
|
- switch (bp->attr.bp_len) {
|
|
|
+ switch (attr->bp_len) {
|
|
|
case HW_BREAKPOINT_LEN_1:
|
|
|
- info->len = X86_BREAKPOINT_LEN_1;
|
|
|
+ hw->len = X86_BREAKPOINT_LEN_1;
|
|
|
break;
|
|
|
case HW_BREAKPOINT_LEN_2:
|
|
|
- info->len = X86_BREAKPOINT_LEN_2;
|
|
|
+ hw->len = X86_BREAKPOINT_LEN_2;
|
|
|
break;
|
|
|
case HW_BREAKPOINT_LEN_4:
|
|
|
- info->len = X86_BREAKPOINT_LEN_4;
|
|
|
+ hw->len = X86_BREAKPOINT_LEN_4;
|
|
|
break;
|
|
|
#ifdef CONFIG_X86_64
|
|
|
case HW_BREAKPOINT_LEN_8:
|
|
|
- info->len = X86_BREAKPOINT_LEN_8;
|
|
|
+ hw->len = X86_BREAKPOINT_LEN_8;
|
|
|
break;
|
|
|
#endif
|
|
|
default:
|
|
|
/* AMD range breakpoint */
|
|
|
- if (!is_power_of_2(bp->attr.bp_len))
|
|
|
+ if (!is_power_of_2(attr->bp_len))
|
|
|
return -EINVAL;
|
|
|
- if (bp->attr.bp_addr & (bp->attr.bp_len - 1))
|
|
|
+ if (attr->bp_addr & (attr->bp_len - 1))
|
|
|
return -EINVAL;
|
|
|
|
|
|
if (!boot_cpu_has(X86_FEATURE_BPEXT))
|
|
@@ -317,8 +316,8 @@ static int arch_build_bp_info(struct perf_event *bp)
|
|
|
* breakpoints, then we'll have to check for kprobe-blacklisted
|
|
|
* addresses anywhere in the range.
|
|
|
*/
|
|
|
- info->mask = bp->attr.bp_len - 1;
|
|
|
- info->len = X86_BREAKPOINT_LEN_1;
|
|
|
+ hw->mask = attr->bp_len - 1;
|
|
|
+ hw->len = X86_BREAKPOINT_LEN_1;
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
@@ -327,22 +326,23 @@ static int arch_build_bp_info(struct perf_event *bp)
|
|
|
/*
|
|
|
* Validate the arch-specific HW Breakpoint register settings
|
|
|
*/
|
|
|
-int arch_validate_hwbkpt_settings(struct perf_event *bp)
|
|
|
+int hw_breakpoint_arch_parse(struct perf_event *bp,
|
|
|
+ const struct perf_event_attr *attr,
|
|
|
+ struct arch_hw_breakpoint *hw)
|
|
|
{
|
|
|
- struct arch_hw_breakpoint *info = counter_arch_bp(bp);
|
|
|
unsigned int align;
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
- ret = arch_build_bp_info(bp);
|
|
|
+ ret = arch_build_bp_info(bp, attr, hw);
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
|
|
|
- switch (info->len) {
|
|
|
+ switch (hw->len) {
|
|
|
case X86_BREAKPOINT_LEN_1:
|
|
|
align = 0;
|
|
|
- if (info->mask)
|
|
|
- align = info->mask;
|
|
|
+ if (hw->mask)
|
|
|
+ align = hw->mask;
|
|
|
break;
|
|
|
case X86_BREAKPOINT_LEN_2:
|
|
|
align = 1;
|
|
@@ -363,7 +363,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
|
|
|
* Check that the low-order bits of the address are appropriate
|
|
|
* for the alignment implied by len.
|
|
|
*/
|
|
|
- if (info->address & align)
|
|
|
+ if (hw->address & align)
|
|
|
return -EINVAL;
|
|
|
|
|
|
return 0;
|