ARM64 hw watchpoint、breakpoint注册与注销
ARM64 hw watchpoint、breakpoint注册与注销
write_wb_reg()里的switch macro展开
4.19\arch\arm64\kernel\Hw_breakpoint.c
static void write_wb_reg(int reg, int n, u64 val) { switch (reg + n) { GEN_WRITE_WB_REG_CASES(AARCH64_DBG_REG_BVR, AARCH64_DBG_REG_NAME_BVR, val); GEN_WRITE_WB_REG_CASES(AARCH64_DBG_REG_BCR, AARCH64_DBG_REG_NAME_BCR, val); GEN_WRITE_WB_REG_CASES(AARCH64_DBG_REG_WVR, AARCH64_DBG_REG_NAME_WVR, val); GEN_WRITE_WB_REG_CASES(AARCH64_DBG_REG_WCR, AARCH64_DBG_REG_NAME_WCR, val); default: pr_warning("attempt to write to unknown breakpoint register %d\n", n); } isb(); } above switch expanding as below: switch (reg + n) { /* wvr(breakpoint value register) */ case (0): \ do {\ write_sysreg(val, dbgbvr0_el1);\ } while (0); \ break; case (1): \ do {\ write_sysreg(val, dbgbvr1_el1);\ } while (0); \ break; case (15): \ do {\ write_sysreg(val, dbgbvr15_el1);\ } while (0); \ break; /* wvr(breakpoint ctrl register) */ case (16 + 0): \ do {\ write_sysreg(VAL, dbgbcr0_el1);\ } while (0); \ break case (16 + 1): \ do {\ write_sysreg(VAL, dbgbcr1_el1);\ } while (0); \ break case (16 + 15): \ do {\ write_sysreg(VAL, dbgbcr15_el1);\ } while (0); \ break /* wvr(watchpoint value register) */ case (32 + 0): \ do {\ write_sysreg(VAL, dbgwvr0_el1);\ } while (0); \ break case (32 + 1): \ do {\ write_sysreg(VAL, dbgwvr1_el1);\ } while (0); \ break case (32 + 15): \ do {\ write_sysreg(VAL, dbgwvr15_el1);\ } while (0); \ break /* wvr(watchpoint ctrl register) */ case (48 + 0): \ do {\ write_sysreg(VAL, dbgwcr0_el1);\ } while (0); \ break case (48 + 1): \ do {\ write_sysreg(VAL, dbgwcr1_el1);\ } while (0); \ break case (48 + 15): \ do {\ write_sysreg(VAL, dbgwcr15_el1);\ } while (0); \ break }
bvr/bcr/wvr/wcr寄存器分别为breakpoint value register/breakpoint ctrl register/watchpoint value register/watchpoint ctrl register
这些寄存器描述见下面链接:
https://developer.arm.com/documentation/ddi0500/e/debug/memory-mapped-register-summary
注册watchpoint callstack
设置watchpoint、breakpoint需要设置CPU寄存器,设置寄存器是通过上述write_wb_reg()来设置的,它的示例设置callstack如下:
[ 28.809660] CPU: 1 PID: 34 Comm: kworker/1:1 Tainted: P O 4.19.116+ #49 [ 28.817581] Hardware name: test_mach (DT) [ 28.821261] Workqueue: events watch_point_delayed_work_func [ 28.826841] Call trace: [ 28.829293] dump_backtrace+0x0/0x4 [ 28.832786] dump_stack+0xf4/0x134 [ 28.836192] write_wb_reg+0x3c/0x284 [ 28.839769] hw_breakpoint_control+0x18c/0x264 [ 28.844216] hw_breakpoint_add+0x80/0x8c [ 28.848143] event_sched_in+0x44c/0x718 [ 28.851981] group_sched_in+0x6c/0x218 [ 28.855732] pinned_sched_in+0x158/0x264 [ 28.859656] visit_groups_merge+0x140/0x1fc [ 28.863842] ctx_sched_in+0x1a4/0x1ec [ 28.867507] ctx_resched+0xdc/0x1e4 [ 28.870998] __perf_event_enable+0x1d0/0x2c4 [ 28.875271] event_function.9346+0x128/0x224 [ 28.879543] remote_function+0x74/0xb4 [ 28.883297] generic_exec_single+0x7c/0x1a4 [ 28.887483] smp_call_function_single+0xc0/0x1e8 [ 28.892104] event_function_call+0x84/0x274 [ 28.896289] perf_event_enable+0xec/0x158 [ 28.900301] _register_wp_bp+0x408/0x4b8 [ 28.904228] watch_point_delayed_work_func+0x68/0xcc [ 28.909197] process_one_work+0x3c0/0x670 [ 28.913210] worker_thread+0x32c/0x6d0 [ 28.916962] kthread+0x130/0x140 [ 28.920194] ret_from_fork+0x10/0x18
arm64 CPU支持的watchpoint、breakpoint max num
4.19\arch\arm64\include\asm\Hw_breakpoint.h
/* Determine number of BRP registers available. */ static inline int get_num_brps(void) { u64 dfr0 = read_sanitised_ftr_reg(SYS_ID_AA64DFR0_EL1); return 1 + cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_BRPS_SHIFT); } /* Determine number of WRP registers available. */ static inline int get_num_wrps(void) { u64 dfr0 = read_sanitised_ftr_reg(SYS_ID_AA64DFR0_EL1); return 1 + cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_WRPS_SHIFT); }
确定CPU支持的watchpoint、breakpoint max num:
arch/arm64/kernel/hw_breakpoint.c
static int __init arch_hw_breakpoint_init(void) { int ret; core_num_brps = get_num_brps(); core_num_wrps = get_num_wrps(); pr_info("found %d breakpoint and %d watchpoint registers.\n", core_num_brps, core_num_wrps);
比如我这边平台CPU支持的max watchpoint、breakpoint num分别为4、6:
[ 1.399866] hw-breakpoint: found 6 breakpoint and 4 watchpoint registers.
以watchpoint为例,如果当前已经注册了4个,如果再继续注册,则会注册fail,返回-ENOSPC(-28)
arch/arm64/kernel/hw_breakpoint.c
static int hw_breakpoint_control(struct perf_event *bp, enum hw_breakpoint_ops ops) { struct arch_hw_breakpoint *info = counter_arch_bp(bp); struct perf_event **slots; struct debug_info *debug_info = ¤t->thread.debug; int i, max_slots, ctrl_reg, val_reg, reg_enable; enum dbg_active_el dbg_el = debug_exception_level(info->ctrl.privilege); u32 ctrl; if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) { /* Breakpoint */ ctrl_reg = AARCH64_DBG_REG_BCR; val_reg = AARCH64_DBG_REG_BVR; slots = this_cpu_ptr(bp_on_reg); max_slots = core_num_brps; reg_enable = !debug_info->bps_disabled; } else { /* Watchpoint */ ctrl_reg = AARCH64_DBG_REG_WCR; val_reg = AARCH64_DBG_REG_WVR; slots = this_cpu_ptr(wp_on_reg); max_slots = core_num_wrps; reg_enable = !debug_info->wps_disabled; } i = hw_breakpoint_slot_setup(slots, max_slots, bp, ops);
static int hw_breakpoint_slot_setup(struct perf_event **slots, int max_slots, struct perf_event *bp, enum hw_breakpoint_ops ops) { int i; struct perf_event **slot; for (i = 0; i < max_slots; ++i) { slot = &slots[i]; switch (ops) { case HW_BREAKPOINT_INSTALL: if (!*slot) { *slot = bp; return i; } break; case HW_BREAKPOINT_UNINSTALL: if (*slot == bp) { *slot = NULL; return i; } break; case HW_BREAKPOINT_RESTORE: if (*slot == bp) return i; break; default: pr_warn_once("Unhandled hw breakpoint ops %d\n", ops); return -EINVAL; } } return -ENOSPC; }
注销watch point callstack
注销一个watchpoint callstack如下,call到hw_breakpoint_control()将ctrl reg设置为0,ops为HW_BREAKPOINT_UNINSTALL:
[ 49.043918] hw-breakpoint: ops: 1, reg_enable: 1. [ 49.043925] CPU: 0 PID: 3237 Comm: mali-cmar-backe Tainted: P O 4.19.116+ #19 [ 49.043927] Hardware name: xxx_mach (DT) [ 49.043931] Call trace: [ 49.043942] dump_backtrace+0x0/0x4 [ 49.043949] dump_stack+0xf4/0x134 [ 49.043957] hw_breakpoint_control+0x184/0x29c [ 49.043963] hw_breakpoint_del+0x20/0x2c [ 49.043968] event_sched_out+0xe0/0x344 [ 49.043973] __perf_remove_from_context+0xfc/0x16c [ 49.043977] event_function.9234+0x128/0x224 [ 49.043981] remote_function+0x74/0xb4 [ 49.043988] generic_exec_single+0x7c/0x1a4 [ 49.043992] smp_call_function_single+0xc0/0x1e8 [ 49.043996] event_function_call+0x84/0x274 [ 49.044000] perf_event_release_kernel+0x1b8/0x794 [ 49.044004] unregister_wide_hw_breakpoint+0x90/0xf4 [ 49.044010] _unregister_wp_bp+0x10c/0x198 [ 49.044016] exit_files+0x1a0/0x1d8 [ 49.044020] do_exit+0x8ec/0x1420 [ 49.044024] do_group_exit+0x0/0x160 [ 49.044027] __se_sys_exit+0x0/0x20 [ 49.044031] el0_svc_common+0xb8/0x1b8 [ 49.044035] el0_svc_handler+0x74/0x90 [ 49.044040] el0_svc+0x8/0x340
4.19\arch\arm64\kernel\Hw_breakpoint.c
static int hw_breakpoint_control(struct perf_event *bp,
enum hw_breakpoint_ops ops)
case HW_BREAKPOINT_UNINSTALL: /* Reset the control register. */ write_wb_reg(ctrl_reg, i, 0); /* * Release the debug monitors for the correct exception * level. */ disable_debug_monitors(dbg_el); break;
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析