我感兴趣的是在arm64 (aarch64)中生成一个断点异常,使用LiteOS作为工作操作系统。为了不弄清楚,每当处理器元素试图从特定地址执行指令时,都会生成断点异常(这不应与“断点指令异常”(指令bkpt
或int
,如这个问题中的指令)混淆)。
AARCH64手册的断点例外处理我想要达到的目标(以及这个问题,但它没有解决我的问题)。
在解释我的问题之前,让我说一下,我验证了我的CPU支持硬件断点:寄存器ID_AA64DFR0_EL1
(手动这里)的15:12位是支持0b1010
= 5-1 = 4
断点的。
在我的用户空间中,我有一个简单的函数:
void justAFunction()
{
printf("justAFunction has been called, did you block?\n");
}
在调用此函数之前,userland进程“设置一个断点”:
[...]
setBreakpoint((void *)justAFunction); /* this is a system call to the kernel */
[...]
justAFunction();
[...]
setBreakpoint
是一个系统调用,我按照如下方式实现了内核代码(就像kvm代码一样,我在这方面找到的唯一引用,这里):
void setBreakpoint(void *addr)
{
AARCH64_SYSREG_WRITE(DBGBVR0_EL1, addr);
AARCH64_SYSREG_WRITE(DBGBCR0_EL1, (AARCH64_SYSREG_READ(DBGBCR0_EL1) | DBGBCR_E | DBGBCR_LEN8 | DBGBCR_EXEC | DBGBCR_EL1));
isb();
asm volatile("msr daifclr, #8");
AARCH64_SYSREG_WRITE(mdscr_el1, (AARCH64_SYSREG_READ(mdscr_el1) | MDSCR_KDE | MDSCR_MDE));
isb();
}
DBGBCR0_EL1
和DBGBVR0_EL1
的描述:这里。
具体地说:
#define DBGBCR_LEN8 (0xff << 5)
#define DBGBCR_EXEC (0x0 << 3)
#define DBGBCR_EL1 (0x1 << 1)
#define DBGBCR_E (0x1 << 0)
#define MDSCR_KDE (1 << 13)
#define MDSCR_MDE (1 << 15)
在尝试将addr
(即justAFunction
虚拟地址)写入DBGBVR0_EL1
之后,我尝试重新读取相同的寄存器,并且内容是正确的。
我所期望的是,一旦用户进程尝试执行bkpt
,就会引发一个调试异常(在内核中启用这个异常,因为我能够引发像justAFunction
这样的断点指令或单步执行justAFunction
)。
不幸的是,什么都没发生。执行justAFunction
并没有触发异常向量(我已经用gdb验证过)。
我的感觉是我错过了什么,但我找不到什么。
发布于 2022-02-24 17:03:20
您希望在EL0上命中断点,但将其配置为EL1。删除DBGBCR_EL1
标志。
另外,您可能不想阅读DBGBCR0_EL1
的当前内容,而是完全覆盖它们。
代之以:
AARCH64_SYSREG_WRITE(DBGBCR0_EL1, (AARCH64_SYSREG_READ(DBGBCR0_EL1) | DBGBCR_E | DBGBCR_LEN8 | DBGBCR_EXEC | DBGBCR_EL1));
在这方面:
AARCH64_SYSREG_WRITE(DBGBCR0_EL1, (DBGBCR_E | DBGBCR_LEN8 | DBGBCR_EXEC));
https://stackoverflow.com/questions/71254937
复制相似问题