ARM v7 BKPT指令不';t无法在Linux 2.6.35上正常工作
我有一个问题与Linux 2.6.35上ARM v7上的BKPT指令有关。主要原因是故障指示(bkpt)地址不正确,与ARM v7手册不一致 以下是复制的步骤:ARM v7 BKPT指令不';t无法在Linux 2.6.35上正常工作,linux,arm,Linux,Arm,我有一个问题与Linux 2.6.35上ARM v7上的BKPT指令有关。主要原因是故障指示(bkpt)地址不正确,与ARM v7手册不一致 以下是复制的步骤: 将OS SIGBUS处理程序重新定义为我的SIGBUS处理程序: void InitSigBusHandler() { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_flags = SA_SIGINFO; sigf
void InitSigBusHandler() {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_flags = SA_SIGINFO;
sigfillset(&sa.sa_mask);
sa.sa_sigaction = SigBusHandler;
sigaction(SIGBUS, &sa, NULL);
}
int main(int argc, char **argv)
{
InitSigBusHandler();
__asm
(
"bkpt\n\t"
);
return 0;
}
void SigBusHandler(
int signum,
siginfo_t *pAct,
void *pOldAct
)
{
write(2,
(const char *)MSG_SIGBUS_IN_HANDLER,
strlen((const char *)MSG_SIGBUS_IN_HANDLER)
);
uint32_t faultAddr = (uint32_t)pAct->si_addr;
memcpy((void *)buffer,
(void *)MSG_SIGBUS_FAULT_ADDR,
strlen(MSG_SIGBUS_FAULT_ADDR)
);
write(2,
(const char *)MSG_SIGBUS_FAULT_ADDR,
strlen((const char *)MSG_SIGBUS_FAULT_ADDR)
);
sprintf(buffer, "%x\n", faultAddr);
write(2, buffer, strlen(buffer));
}
故障地址:86b0
在SIGBUS处理程序中:
故障地址:86c0
在SIGBUS处理程序中:
故障地址:86c0
在SIGBUS处理程序中:
故障地址:86c0
在SIGBUS处理程序中:
故障地址:86c0
在SIGBUS处理程序中:
故障地址:86b0
在SIGBUS处理程序中:
故障地址:86a8
在SIGBUS处理程序中:
故障地址:86f0
也许有人知道我做错了什么?对于断点陷阱而言,
si_addr
是精确的(即故障发生时操作的实际地址)这一假设不一定是正确的/可移植的
您确实需要检查保存的寄存器状态,即信号处理程序的第三个参数,它可以转换为ucontext\u t*
。该状态在CPU之间不可移植,因此通用接口只传递一个void*
;GDB检查它(以便info registers
工作)并从中提取故障的程序计数器,这就是为什么它能够将您指向断点指令的原因
您在ARM上遇到的情况与64位x86上遇到的情况类似,如果您尝试:
volatile char *ptr = (char*)0x1234567890abcdef;
char crashme = *ptr;
您希望si_addr
中的故障地址为0x1234567890abcdef
。情况并非如此,因为此访问地址将创建一个#GPF
非#PF
故障,并且前者不会在x86上设置故障地址寄存器。如果您查看保存为ucontext\u t
/struct sigcontext
(嵌入其中)一部分的程序计数器,您将看到错误的指令地址,这将是精确的
将信号处理程序更改为:
void SigBusHandler(
int signum,
siginfo_t *pAct,
void *context
)
{
struct sigcontext *ctx = &(((ucontext_t*)context)->uc_mcontext);
uintptr_t fault_address = ctx->arm_pc; /* that's what you'll see on ARM */
...
}
如前所述,问题在于,计算CPU寄存器状态必然会得到依赖于CPU的代码。您必须进行一些调整/包装以保持此便携性,例如:
#if defined(ARM)
#define GET_PC_FROM_CONTEXT(c) (((ucontext_t *)(c))->uc_mcontext.arm_pc)
#elsif defined(__i386__)
define GET_PC_FROM_CONTEXT(c) (((ucontext_t *)(c))->uc_mcontext.eip)
#elsif defined(__amd64__)
define GET_PC_FROM_CONTEXT(c) (((ucontext_t *)(c))->uc_mcontext.rip)
#endif
uintptr_t instr_address = GET_PC_FROM_CONTEXT(context);
希望有帮助