register_wide_hw_breakpoint实现分析

以下是对register_wide_hw_breakpoint内核函数的详细分析:

 

1. 功能说明

该函数用于在全CPU核心上注册硬件断点,属于Linux内核的调试基础设施。核心功能:

 

为每个在线CPU创建硬件断点(通过perf_event子系统)

返回一组per-CPU的perf_event指针(用于后续管理)

2. 关键代码逻辑

(1) 内存分配

cpu_events = alloc_percpu(typeof(*cpu_events));

使用alloc_percpu分配per-CPU内存,每个CPU核心会有独立副本

失败时返回ENOMEM错误(强制类型转换为ERR_PTR)

(2) 断点注册循环

for_each_online_cpu(cpu) {

    bp = perf_event_create_kernel_counter(attr, cpu, NULL, triggered, context);

    per_cpu(*cpu_events, cpu) = bp;

}

for_each_online_cpu:遍历所有在线CPU

perf_event_create_kernel_counter:核心操作,实际创建硬件断点

attr:指定断点属性(地址、类型等)

triggered:断点触发时的回调函数

结果存储到per-CPU变量中

(3) 错误处理

if (IS_ERR(bp)) {

    err = PTR_ERR(bp);

    break; // 任一CPU失败则终止

}

...

if (likely(!err)) return cpu_events;

使用IS_ERR/PTR_ERR处理内核错误码

likely()优化分支预测,假设成功是常见路径

失败时调用unregister_wide_hw_breakpoint清理已注册断点

3. 技术亮点

CPU热插拔安全

get_online_cpus()/put_online_cpus():防止操作期间CPU状态变化

硬件断点管理

通过perf_event子系统抽象不同架构的硬件断点(x86/ARM等)

内存模型

__percpu标注显式声明per-CPU内存语义

使用per_cpu()宏安全访问per-CPU变量

 

 

// SPDX-License-Identifier: GPL-2.0 #include <linux/syscalls.h> #include <linux/pid.h> #include <linux/perf_event.h> #include <linux/hw_breakpoint.h> #include <linux/sched.h> #include <linux/slab.h> #include <asm/fpsimd.h> #include <linux/thread_info.h> #include <linux/uaccess.h> // 新增用户态访问头文件 static struct perf_event *bp; static void hit_handler(struct perf_event *bp, struct perf_sample_data *data, struct pt_regs *regs) { int i; struct user_fpsimd_state fp; struct task_struct *current_task = current; pr_info("=== HWBP hit @%p ===\n", (void *)regs->pc); /* 通用寄存器 */ for (i = 0; i < 31; ++i) pr_info("X%-2d = 0x%016llx\n", i, regs->regs[i]); pr_info("SP = 0x%016llx\n", regs->sp); pr_info("PC = 0x%016llx\n", regs->pc); pr_info("LR = 0x%016llx\n", regs->regs[30]); /* 浮点寄存器:5.15+ 正确方式 */ if (!user_mode(regs)) { fpsimd_save_state(&fp); // 内核态直接保存 } else { // 用户态需通过线程信息访问 memcpy(&fp, &current_task->thread.uw.fpsimd_state, sizeof(fp)); } pr_info("【浮点寄存器 S0-S31 (32-bit)】\n"); for (i = 0; i < 32; ++i) pr_info("S%-2d = 0x%08x\n", i, (u32)(fp.vregs[i] & 0xFFFFFFFF)); pr_info("【浮点寄存器 D0-D31 (64-bit)】\n"); for (i = 0; i < 32; ++i) pr_info("D%-2d = 0x%016llx\n", i, fp.vregs[i]); pr_info("【命中地址】PC = 0x%016llx\n", regs->pc); pr_info("【返回地址】LR = 0x%016llx\n", regs->regs[30]); } SYSCALL_DEFINE4(process_vm_writev, int, pid, unsigned long long, addr, int, len, int, type) { struct perf_event_attr attr = {}; struct pid *pid_struct; struct task_struct *tsk; if (bp && !IS_ERR(bp)) { unregister_hw_breakpoint(bp); bp = NULL; } pid_struct = find_get_pid(pid); if (!pid_struct) return -ESRCH; tsk = get_pid_task(pid_struct, PIDTYPE_PID); put_pid(pid_struct); if (!tsk) return -ESRCH; attr.type = PERF_TYPE_BREAKPOINT; attr.size = sizeof(attr); attr.bp_addr = addr; attr.bp_len = (len == 8) ? HW_BREAKPOINT_LEN_8 : HW_BREAKPOINT_LEN_4; switch (type) { case 0: attr.bp_type = HW_BREAKPOINT_R; break; case 1: attr.bp_type = HW_BREAKPOINT_W; break; case 2: attr.bp_type = HW_BREAKPOINT_RW; break; case 3: attr.bp_type = HW_BREAKPOINT_X; break; default: return -EINVAL; } // 5.15+ 正确参数顺序(新增 group 参数) bp = register_wide_hw_breakpoint(&attr, hit_handler, NULL, tsk, NULL); return IS_ERR(bp) ? PTR_ERR(bp) : 0; }报错:root@localhost:~/5.15-13# tools/bazel run //common:kernel_aarch64_dist --config=fast INFO: Analyzed target //common:kernel_aarch64_dist (0 packages loaded, 0 targets configured). INFO: Found 1 target... ERROR: /root/5.15-13/common/BUILD.bazel:52:22: Building kernel kernel_aarch64 failed: (Exit 2): bash failed: error executing command (from target //common:kernel_aarch64) /bin/bash -c ... (remaining 1 argument skipped) /root/5.15-13/common/kernel/sys.c:3032:60: error: too many arguments to function call, expected 3, have 5 bp = register_wide_hw_breakpoint(&attr, hit_handler, NULL, tsk, NULL); ~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^~~~~~~~~ /root/5.15-13/common/include/linux/hw_breakpoint.h:70:1: note: 'register_wide_hw_breakpoint' declared here register_wide_hw_breakpoint(struct perf_event_attr *attr, ^ 1 error generated. make[2]: *** [/root/5.15-13/common/scripts/Makefile.build:287: kernel/sys.o] Error 1 make[1]: *** [/root/5.15-13/common/Makefile:1953: kernel] Error 2 make: *** [Makefile:244: __sub-make] Error 2 Target //common:kernel_aarch64_dist failed to build Use --verbose_failures to see the command lines of failed build steps. ERROR: /root/5.15-13/common/BUILD.bazel:52:22 Middleman _middlemen/common_Skernel_Uaarch64_Udist-runfiles failed: (Exit 2): bash failed: error executing command (from target //common:kernel_aarch64) /bin/bash -c ... (remaining 1 argument skipped) INFO: Elapsed time: 39.149s, Critical Path: 38.07s INFO: 4 processes: 4 internal. FAILED: Build did NOT complete successfully FAILED: Build did NOT complete successfully root@localhost:~/5.15-13# 修复好完整发给我 要求可以给任意进程硬件断点 中文注释
07-20
root@localhost:~/5.15-13# tools/bazel run //common:kernel_aarch64_dist --config=fast INFO: Analyzed target //common:kernel_aarch64_dist (0 packages loaded, 0 targets configured). INFO: Found 1 target... ERROR: /root/5.15-13/common/BUILD.bazel:52:22: Building kernel kernel_aarch64 failed: (Exit 2): bash failed: error executing command (from target //common:kernel_aarch64) /bin/bash -c ... (remaining 1 argument skipped) /root/5.15-13/common/kernel/sys.c:3099:20: error: initializing 'struct perf_event *' with an expression of incompatible type 'typeof (*(*bp_ptr))' (aka 'struct perf_event'); remove * struct perf_event *cpu_event = *this_cpu_ptr(*bp_ptr); ^ ~~~~~~~~~~~~~~~~~~~~~~ /root/5.15-13/common/kernel/sys.c:3124:8: error: incompatible pointer types assigning to 'struct perf_event *' from 'struct perf_event **'; dereference with * [-Werror,-Wincompatible-pointer-types] new_bp = register_wide_hw_breakpoint(&new_attr, hwbp_handler, current); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * /root/5.15-13/common/kernel/sys.c:3131:31: error: incompatible pointer types passing 'struct perf_event *' to parameter of type 'struct perf_event **'; remove * [-Werror,-Wincompatible-pointer-types] unregister_wide_hw_breakpoint(*bp_ptr); ^~~~~~~ /root/5.15-13/common/include/linux/hw_breakpoint.h:76:73: note: passing argument to parameter 'cpu_events' here extern void unregister_wide_hw_breakpoint(struct perf_event * __percpu *cpu_events); ^ /root/5.15-13/common/kernel/sys.c:3137:18: error: assigning to 'struct perf_event *' from incompatible type 'typeof (*(new_bp))' (aka 'struct perf_event'); remove * info->sample_hbp = *this_cpu_ptr(new_bp); ^ ~~~~~~~~~~~~~~~~~~~~~ /root/5.15-13/common/kernel/sys.c:3099:20: error: mixing declarations and code is a C99 extension [-Werror,-Wdeclaration-after-statement] struct perf_event *cpu_event = *this_cpu_ptr(*bp_ptr); ^ /root/5.15-13/common/kernel/sys.c:3161:9: error: incompatible pointer types assigning to 'struct perf_event *' from 'struct perf_event **'; dereference with * [-Werror,-Wincompatible-pointer-types] orig_bp = register_wide_hw_breakpoint(&orig_attr, hwbp_handler, current); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * /root/5.15-13/common/kernel/sys.c:3168:31: error: incompatible pointer types passing 'struct perf_event *' to parameter of type 'struct perf_event **'; remove * [-Werror,-Wincompatible-pointer-types] unregister_wide_hw_breakpoint(*bp_ptr); ^~~~~~~ /root/5.15-13/common/include/linux/hw_breakpoint.h:76:73: note: passing argument to parameter 'cpu_events' here extern void unregister_wide_hw_breakpoint(struct perf_event * __percpu *cpu_events); ^ /root/5.15-13/common/kernel/sys.c:3174:18: error: assigning to 'struct perf_event *' from incompatible type 'typeof (*(orig_bp))' (aka 'struct perf_event'); remove * info->sample_hbp = *this_cpu_ptr(orig_bp); ^ ~~~~~~~~~~~~~~~~~~~~~~ /root/5.15-13/common/kernel/sys.c:3334:31: error: incompatible pointer types passing 'struct perf_event *' to parameter of type 'struct perf_event **'; take the address with & [-Werror,-Wincompatible-pointer-types] unregister_wide_hw_breakpoint(bp); ^~ & /root/5.15-13/common/include/linux/hw_breakpoint.h:76:73: note: passing argument to parameter 'cpu_events' here extern void unregister_wide_hw_breakpoint(struct perf_event * __percpu *cpu_events); ^ /root/5.15-13/common/kernel/sys.c:3423:31: error: incompatible pointer types passing 'struct perf_event *' to parameter of type 'struct perf_event **'; take the address with & [-Werror,-Wincompatible-pointer-types] unregister_wide_hw_breakpoint(bp); ^~ & /root/5.15-13/common/include/linux/hw_breakpoint.h:76:73: note: passing argument to parameter 'cpu_events' here extern void unregister_wide_hw_breakpoint(struct perf_event * __percpu *cpu_events); ^ /root/5.15-13/common/kernel/sys.c:3499:4: error: incompatible pointer types assigning to 'struct perf_event *' from 'struct perf_event **'; dereference with * [-Werror,-Wincompatible-pointer-types] bp = register_wide_hw_breakpoint(&attr, hwbp_handler, tsk); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * /root/5.15-13/common/kernel/sys.c:3507:22: error: assigning to 'struct perf_event *' from incompatible type 'typeof (*(bp))' (aka 'struct perf_event'); remove * new_info->sample_hbp = *this_cpu_ptr(bp); // 关联断点句柄 ^ ~~~~~~~~~~~~~~~~~ 12 errors generated. make[2]: *** [/root/5.15-13/common/scripts/Makefile.build:287: kernel/sys.o] Error 1 make[1]: *** [/root/5.15-13/common/Makefile:1953: kernel] Error 2 make: *** [Makefile:244: __sub-make] Error 2 仔细检查问题修复好 5.15内核 安卓14 确保所有逻辑正常使用无任何编译报错后 完整发给我代码
最新发布
07-23
root@localhost:~/5.15-13# tools/bazel run //common:kernel_aarch64_dist --config=fast INFO: Analyzed target //common:kernel_aarch64_dist (0 packages loaded, 0 targets configured). INFO: Found 1 target... ERROR: /root/5.15-13/common/BUILD.bazel:52:22: Building kernel kernel_aarch64 failed: (Exit 2): bash failed: error executing command (from target //common:kernel_aarch64) /bin/bash -c ... (remaining 1 argument skipped) /root/5.15-13/common/kernel/sys.c:3009:31: error: incompatible pointer types passing 'struct perf_event *' to parameter of type 'struct perf_event **'; take the address with & [-Werror,-Wincompatible-pointer-types] unregister_wide_hw_breakpoint(bp); ^~ & /root/5.15-13/common/include/linux/hw_breakpoint.h:76:73: note: passing argument to parameter 'cpu_events' here extern void unregister_wide_hw_breakpoint(struct perf_event * __percpu *cpu_events); ^ /root/5.15-13/common/kernel/sys.c:3039:4: error: incompatible pointer types assigning to 'struct perf_event *' from 'struct perf_event **'; dereference with * [-Werror,-Wincompatible-pointer-types] bp = register_wide_hw_breakpoint(&attr, hit_handler, NULL); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * /root/5.15-13/common/kernel/sys.c:3049:9: error: implicit declaration of function 'perf_event_set_target' [-Werror,-Wimplicit-function-declaration] perf_event_set_target(event, tsk); // 关联到目标进程 ^ 3 errors generated. make[2]: *** [/root/5.15-13/common/scripts/Makefile.build:287: kernel/sys.o] Error 1 make[1]: *** [/root/5.15-13/common/Makefile:1953: kernel] Error 2 make: *** [Makefile:244: __sub-make] Error 2 Target //common:kernel_aarch64_dist failed to build Use --verbose_failures to see the command lines of failed build steps. ERROR: /root/5.15-13/common/BUILD.bazel:52:22 Middleman _middlemen/common_Skernel_Uaarch64_Udist-runfiles failed: (Exit 2): bash failed: error executing command (from target //common:kernel_aarch64) /bin/bash -c ... (remaining 1 argument skipped) INFO: Elapsed time: 45.356s, Critical Path: 44.43s INFO: 4 processes: 4 internal. FAILED: Build did NOT complete successfully FAILED: Build did NOT complete successfully root@localhost:~/5.15-13# 继续仔细修复 完整发给我代码
07-20
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值