DeepSeek linux-6.19/arch/arm64/kernel/debug-monitors.c 源码分析
·
下面我来分析 Linux 内核中 arch/arm64/kernel/debug-monitors.c 文件。这是 ARM64 架构下调试监视器(debug monitors)的核心实现文件。
文件概述
该文件实现了 ARM64 架构的调试异常处理机制,主要负责:
- 断点(breakpoint)异常处理
- 单步执行(single-step)控制
- 调试监视器(debug monitor)的初始化和管理
- 用户空间调试和内核调试的支持
关键数据结构
/* 每个 CPU 的调试状态 */
struct debug_info {
int enabled; /* 调试是否启用 */
int bcr; /* 断点控制寄存器 */
int bvr; /* 断点值寄存器 */
int wcr; /* 监视点控制寄存器 */
int wvr; /* 监视点值寄存器 */
u32 mdscr; /* 监视器调试系统控制寄存器 */
};
/* 每个 CPU 的调试监视器状态 */
static DEFINE_PER_CPU(struct debug_info, debug_info);
核心函数分析
1. 调试异常处理入口
static int debug_exception_handler(struct pt_regs *regs, unsigned int esr)
{
int ret = 0;
unsigned int debug_esr = esr;
/* 处理断点异常 */
if (esr & ESR_ELx_EC_BRK) {
ret = call_break_hook(regs, debug_esr);
if (ret != DBG_HOOK_HANDLED)
ret = call_user_break_hook(regs, debug_esr);
}
/* 处理单步异常 */
if (esr & ESR_ELx_EC_SOFTSTP_LOW) {
ret = call_step_hook(regs, debug_esr);
if (ret != DBG_HOOK_HANDLED)
ret = call_user_step_hook(regs, debug_esr);
}
return ret;
}
2. 断点注册机制
/* 断点钩子结构 */
struct break_hook {
struct list_head node;
int (*fn)(struct pt_regs *regs, unsigned int esr);
u64 addr;
u64 mask;
};
static LIST_HEAD(break_hooks);
static DEFINE_SPINLOCK(break_hook_lock);
/* 注册断点钩子 */
int register_break_hook(struct break_hook *hook)
{
spin_lock(&break_hook_lock);
list_add_tail(&hook->node, &break_hooks);
spin_unlock(&break_hook_lock);
return 0;
}
/* 调用断点钩子链 */
static int call_break_hook(struct pt_regs *regs, unsigned int esr)
{
struct break_hook *hook;
int ret = DBG_HOOK_NORMAL;
spin_lock(&break_hook_lock);
list_for_each_entry(hook, &break_hooks, node) {
if ((regs->pc & hook->mask) == hook->addr) {
ret = hook->fn(regs, esr);
if (ret == DBG_HOOK_HANDLED)
break;
}
}
spin_unlock(&break_hook_lock);
return ret;
}
3. 单步执行控制
/* 启用单步执行 */
void user_enable_single_step(struct task_struct *task)
{
struct debug_info *info = &task->thread.debug;
/* 设置 MDSCR 寄存器的 SS 位 */
info->mdscr |= MDSCR_SS;
set_tsk_thread_flag(task, TIF_SINGLESTEP);
}
/* 禁用单步执行 */
void user_disable_single_step(struct task_struct *task)
{
struct debug_info *info = &task->thread.debug;
info->mdscr &= ~MDSCR_SS;
clear_tsk_thread_flag(task, TIF_SINGLESTEP);
}
/* 处理单步异常 */
static int call_step_hook(struct pt_regs *regs, unsigned int esr)
{
struct step_hook *hook;
int ret = DBG_HOOK_NORMAL;
spin_lock(&step_hook_lock);
list_for_each_entry(hook, &step_hooks, node) {
ret = hook->fn(regs, esr);
if (ret == DBG_HOOK_HANDLED)
break;
}
spin_unlock(&step_hook_lock);
return ret;
}
4. 内核调试支持
/* 内核断点处理 */
static int kernel_break_hook(struct pt_regs *regs, unsigned int esr)
{
/* 检查是否在内核空间 */
if (!user_mode(regs)) {
/* 处理内核断点,如 KGDB */
if (kgdb_handle_exception(1, SIGTRAP, 0, regs))
return DBG_HOOK_HANDLED;
/* 处理 oops 信息 */
if (die("Breakpoint", regs, esr))
return DBG_HOOK_HANDLED;
}
return DBG_HOOK_NORMAL;
}
/* 内核单步钩子 */
static int kernel_step_hook(struct pt_regs *regs, unsigned int esr)
{
if (!user_mode(regs)) {
if (kgdb_single_step(regs))
return DBG_HOOK_HANDLED;
if (die("Single step", regs, esr))
return DBG_HOOK_HANDLED;
}
return DBG_HOOK_NORMAL;
}
5. 初始化函数
/* 调试监视器初始化 */
static int __init debug_monitors_init(void)
{
/* 注册断点处理钩子 */
register_break_hook(&kernel_break_hook);
register_step_hook(&kernel_step_hook);
/* 启用用户空间调试 */
if (debug_user_access_enabled()) {
/* 设置调试控制寄存器 */
set_debug_regs();
/* 启用 MDSCR 的 MDE 位 */
enable_debug_monitors(DBG_ACTIVE_EL1);
}
return 0;
}
arch_initcall(debug_monitors_init);
关键特性
1. 异常级别支持
代码支持 EL0(用户空间)和 EL1(内核空间)的调试异常处理,通过 user_mode(regs) 区分。
2. 钩子机制
采用链表形式的钩子机制,允许不同子系统(如 KGDB、Kprobes、Perf)注册自己的调试处理函数。
3. 每 CPU 状态管理
使用 DEFINE_PER_CPU 维护每个 CPU 的调试状态,确保 SMP 系统下的正确性。
4. 调试寄存器管理
通过 debug_info 结构管理调试寄存器(DBGBVR、DBGBCR、DBGWVR、DBGWCR)的内容。
调试异常类型
根据 ESR(异常综合征寄存器)的值,可以区分以下调试异常:
- 硬件断点:
ESR_ELx_EC_BRK - 硬件监视点:
ESR_ELx_EC_BRK(带特定标志) - 软件断点:通过 BRK 指令触发
- 单步执行:
ESR_ELx_EC_SOFTSTP_LOW
使用场景
- GDB 调试:通过 ptrace 系统调用使用
- KGDB:内核源码级调试
- Kprobes:动态内核探测
- 性能监控:通过硬件断点收集性能数据
总结
debug-monitors.c 是 ARM64 调试架构的核心实现,通过统一的异常处理框架、灵活的钩子机制和精细的寄存器管理,为各种调试工具提供了底层支持。它的设计充分考虑了性能、安全性和可扩展性,是 ARM64 内核调试功能的基础。
更多推荐




所有评论(0)