以下是Linux内核中通过perf_event监控内存访问的硬件断点触发流程分析,从core.c的入口函数开始:
1. 核心触发路径(kernel/events/core.c)
perf_event_create_kernel_counter()
└─ perf_event_alloc()
└─ hw_breakpoint_alloc() # 分配硬件断点资源
└─ perf_install_in_context() # 将事件绑定到CPU上下文
└─ event_sched_in() # 事件激活
└─ hw_breakpoint_add() # 实际写入CPU调试寄存器
2. 内存访问监控关键函数
(1) 断点属性配置
在perf_event_attr中指定监控类型:
struct perf_event_attr attr = {
.type = PERF_TYPE_BREAKPOINT,
.bp_type = HW_BREAKPOINT_RW, // 读写监控
// 或 HW_BREAKPOINT_W (仅写), HW_BREAKPOINT_R (仅读)
.bp_addr = (unsigned long)&target_var, // 监控地址
.bp_len = sizeof(long), // 监控长度(需对齐)
};
(2) 事件激活入口
核心函数:event_sched_in()
位置:kernel/events/core.c
static void event_sched_in(struct perf_event *event, ...) {
if (event->pmu->event_idx == PERF_TYPE_BREAKPOINT)
hw_breakpoint_add(event); // 调用架构特定安装函数
}
3. 硬件断点触发流程
(1) CPU异常产生
当监控的内存地址被访问时:
CPU生成#DB异常(x86)或Debug Exception(ARM)
跳转到架构相关异常处理程序:
x86: do_debug() (arch/x86/kernel/traps.c)
ARM: do_DataAbort() (arch/arm/mm/fault.c)
(2) 事件回调触发
核心函数链:
arch_trigger_dpft_handler() // 架构相关处理
└─ perf_bp_event() // kernel/events/core.c
├─ perf_sample_data_init(&sample, bp->attr.bp_addr) // 记录断点地址
└─ perf_event_overflow(bp, &sample, regs) // 触发事件处理
├─ 用户态:通过perf环形缓冲区通知
└─ 内核态:直接调用overflow_handler回调
4. 关键代码片段(core.c)
(1) 事件溢出处理
// kernel/events/core.c
void perf_event_overflow(struct perf_event *event, ...) {
if (event->overflow_handler)
event->overflow_handler(event, data, regs); // 直接回调
else
__perf_event_overflow(event, ...); // 用户态通知
}
(2) 断点事件采样
static void perf_bp_event(struct perf_event *bp, void *data) {
struct perf_sample_data sample;
perf_sample_data_init(&sample, bp->attr.bp_addr); // 记录被访问地址
perf_event_overflow(bp, &sample, regs);
}
5. 监控数据流
内存访问 → CPU调试异常 → 内核异常处理 → perf_bp_event() →
├─ 用户态:perf_event_output() → 环形缓冲区 → read(fd)
└─ 内核态:直接调用overflow_handler
6. 调试验证方法
查看已注册断点:
cat /sys/kernel/debug/tracing/events/breakpoints/breakpoint/format
动态追踪触发:
perf probe -a 'perf_bp_event'
echo 1 > /sys/kernel/debug/tracing/events/probe/perf_bp_event/enable
关键结论
起始点:监控流程从event_sched_in()调用hw_breakpoint_add()开始激活硬件断点
触发点:实际内存访问通过CPU异常触发perf_bp_event()回调
数据记录:被访问地址通过perf_sample_data_init()保存在采样数据中
该机制广泛用于内核调试工具(如perf mem)和安全监控场景。