type
status
date
slug
summary
tags
category
icon
password
Property
Sep 8, 2023 12:19 PM
参考
ARMv8-A Architecture Reference Manual
内核源码:
- include/linux/hw_breakpoint.h
- kernel/events/hw_breakpoint.c
- arch/arm64/include/asm/hw_breakpoint.h
- arch/arm64/kernel/hw_breakpoint.c
前置知识
ARM64 异常简介
异常等级
ARM64 包含4个异常等级:
- EL0:非特权模式,应用层
- EL1:特权模式,内核
- EL2:虚拟化程序,比如 Hypervisor
- EL3:安全监视器,比如 Secure Monitor
硬件断点简介
硬件断点(Hardware Breakpoint)是一种调试技术,它可以帮助程序员在程序运行时监视内存地址和数据。它是通过在处理器中设置特殊寄存器来实现的,当指定的内存地址被访问时,处理器会触发一个中断,从而停止程序的执行。与软件断点相比,硬件断点的优势在于处理器可以在硬件级别上检测到中断,因此无需在程序中插入中断指令,从而减少对程序的影响(难以检测)。
硬件断点相关的寄存器
ID_AA64DFR0_EL1:AArch64 Debug Feature Register 0
该寄存器包含了调试相关的信息,其中有关的是两个字段:
- WRPs:Watchpoint 个数,Android上一般4个(读写断点)
- BRPs: Breakpoint 个数,Android上一般6个(执行断点)
DBGBCR<n>_EL1:Breakpoint Control Register
具体信息请参考 Reference Manual D13.3.2
该寄存器包含断点的控制信息,比如是否开启。
E:Enable 开关
为0时禁用
为1时启用
PMC:Privilege mode control
BAS:Byte address select
HMC:Higher mode control
SSC:Security state control
LBN:Linked breakpoint number
BT:Breakpoint Type 断点类型
值 | 说明 |
0b0000 | Unlinked instruction address match. DBGBVR<n>_EL1 is the address of an
instruction. |
0b0001 | As 0b0000, but linked to a Context matching breakpoint |
0b0010 | Unlinked Context ID match. When FEAT_VHE is implemented, EL2 is using
AArch64, and the Effective value of HCR_EL2.E2H is 1, if either the PE is executing
at EL0 with HCR_EL2.TGE set to 1 or the PE is executing at EL2, then
DBGBVR<n>_EL1.ContextID must match the CONTEXTIDR_EL2 value. Otherwise,
DBGBVR<n>_EL1.ContextID must match the CONTEXTIDR_EL1 value |
0b0011 | As 0b0010, with linking enabled |
0b0110 | Unlinked CONTEXTIDR_EL1 match. DBGBVR<n>_EL1.ContextID is a Context ID
compared against CONTEXTIDR_EL1. |
0b0111 | As 0b0110, with linking enabled. |
0b1000 | Unlinked VMID match. DBGBVR<n>_EL1.VMID is a VMID compared against
VTTBR_EL2.VMID. |
0b1001 | As 0b1000, with linking enabled. |
0b1010 | Unlinked VMID and Context ID match. DBGBVR<n>_EL1.ContextID is a Context ID
compared against CONTEXTIDR_EL1, and DBGBVR<n>_EL1.VMID is a VMID
compared against VTTBR_EL2.VMID. |
0b1011 | As 0b1010, with linking enabled. |
0b1100 | Unlinked CONTEXTIDR_EL2 match. DBGBVR<n>_EL1.ContextID2 is a Context ID
compared against CONTEXTIDR_EL2. |
0b1101 | As 0b1100, with linking enabled. |
0b1110 | Unlinked Full Context ID match. DBGBVR<n>_EL1.ContextID is compared against
CONTEXTIDR_EL1, and DBGBVR<n>_EL1.ContextID2 is compared against
CONTEXTIDR_EL2. |
0b1111 | As 0b1110, with linking enabled. |
DBGBVR<n>_EL1:Breakpoint Value Register
具体信息请参考 Reference Manual D13.3.3
该寄存器包含断点的值信息,可以是:
- 指令虚拟地址
- Context ID值
- VMID值
- VMID值与Context ID值的组合
DBGBCR<n>_EL1 与 DBGBVR<n>_EL1 成对使用,来控制断点。<n>为断点序号
DBGWCR<n>_EL1:Watchpoint Control Register
具体信息请参考 D13.3.11
该寄存器包含观察点的控制信息
MASK:地址掩码,最大监控2GB
DBGWVR<n>_EL1:Watchpoint Value Register
具体信息请参考 D13.3.12
该寄存器包含观察点匹配的虚拟地址
DBGWCR<n>_EL1 与 DBGWVR<n>_EL1 成对使用,来控制断点。<n>为断点序号
硬件断点的实现流程
配置好硬件断点相关的寄存器后,CPU会在触发断点后产生一个同步异常,然后从 Linux 设置的异常向量表中找到处理同步异常的服务程序(el1_sync),转过去执行它。Linux 内核会在异常处理函数(el1_sync_handler)中根据异常类型(ESR_ELx_EC_BREAKPT_CUR/ESR_ELx_EC_WATCHPT_CUR)来交给对应异常类型的函数(el1_dbg)处理,处理完成后,CPU继续运行。
Linux 内核中的硬件断点
在 Linux 内核之中,内核断点是和 perf 子系统紧密结合的。想要分析内核的硬件断点,我们可以参考
samples/hw_breakpoint/data_breakpoint.c
也可以从 ptrace 注册硬件断点开始分析。了解硬件断点API
我们从 sample 和 ptrace 入手,初步了解内核硬件断点的API设计。
从代码片段中可以了解到内核创建硬件断点的一个流程:
- hw_breakpoint_init:初始化 attr
- register_wide_hw_breakpoint:注册内核空间硬件断点
- unregister_wide_hw_breakpoint:取消注册内核空间硬件断点
再去看看 ptrace 相关的接口:
一直往下跟 hw_break_set → ptrace_hbp_set_addr/ptrace_hbp_set_ctrl → ptrace_hbp_get_initialised_bp → ptrace_hbp_create → register_user_hw_breakpoint
我们可以知道,ptrace是使用
- register_user_hw_breakpoint:注册用户空间硬件断点
- unregister_hw_breakpoint:取消注册用户空间硬件断点
分析硬件断点相关源码
硬件断点的初始化
按照顺序来说,首先是 perf_event 的初始化
perf_event_init()
,其次才是 arch_initcall(arch_hw_breakpoint_init)
perf_event的初始化
硬件断点相关的初始化在
perf_event_init
→ init_hw_breakpoint
arch_hw_breakpoint_init的初始化
这里是架构相关的初始化硬件断点
硬件断点的注册
这里我们只关注架构方面的实现,与 perf_event 接口相关的自己查找一下引用即可。
arch_install_hw_breakpoint
→ hw_breakpoint_control
硬件断点的触发
- 硬件断点触发
- CPU 查找异常向量表,执行 el1_sync (汇编)
- 跳转到 el1_sync_handler 处理(C层)
- 事件类型为 ESR_ELx_EC_BREAKPT_CUR / ESR_ELx_EC_WATCHPT_CUR
- 跳到 el1_dbg 处理
- 执行 do_debug_exception
- 从 esr_to_debug_fault_info 获取到 arch_hw_breakpoint_init 注册的 handler
- 执行 breakpoint_handler / watchpoint_handler
- 跳到 perf_bp_event
- 跳到 perf_swevent_event
- 跳到 perf_swevent_overflow
- 跳到 __perf_event_overflow
- 在 READ_ONCE(event->overflow_handler)(event, data, regs); 执行我们注册的逻辑
Android 上的硬件断点应用
stackplz
Android_Kernel_hwBreakPoint
KernelSU 将在未来加入硬件断点功能(s♾️️n)