我在Linux2.6.35上与ARM v7上的BKPT指令有关联。其主要原因是故障指令地址(bkpt)不正确,不符合ARM v7手册。
以下是复制的步骤:
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)契约->si_addr;memcpy((void *)缓冲区,(void *)MSG_SIGBUS_FAULT_ADDR,strlen(MSG_SIGBUS_FAULT_ADDR) );写(2,(const char *)MSG_SIGBUS_FAULT_ADDR,strlen((const char *)MSG_SIGBUS_FAULT_ADDR );sprintf(缓冲器,"%x\n",faultAddr);
在SIGBUS处理程序中:
故障地址: 86b0
在SIGBUS处理程序中:
故障地址: 86c0
在SIGBUS处理程序中:
故障地址: 86c0
在SIGBUS处理程序中:
故障地址: 86c0
在SIGBUS处理程序中:
故障地址: 86c0
在SIGBUS处理程序中:
故障地址: 86b0
在SIGBUS处理程序中:
故障地址: 86a8
在SIGBUS处理程序中:
故障地址: 86f0
在x86体系结构上,此示例正确工作。在ARM v7体系结构上,这个示例有一个奇怪的行为。
如果我在ARM v7上使用GDB,他会用正确的地址捕获我的BKPT指令。
也许有人知道我做错了什么?
发布于 2011-05-11 15:14:15
假定si_addr是精确的(即故障发生时操作的实际地址)对于断点陷阱来说不一定是真/可移植的。
您确实需要检查保存的寄存器状态,即信号处理程序的第三个参数,该参数可以转换为ucontext_t*。状态在CPU之间是不可移植的,因此泛型接口只传递一个void *;GDB检查它(以便info registers工作),并从那里提取故障的程序计数器,这就是它能够指向断点指令的原因。
您在ARM上遇到的情况与在64位x86上尝试的情况类似:
volatile char *ptr = (char*)0x1234567890abcdef;
char crashme = *ptr;您希望si_addr中的故障地址是0x1234567890abcdef。情况并非如此,因为access上的这个地址将创建一个#GPF而不是#PF错误,而前者不会在x86上设置故障地址寄存器。如果您查看保存为ucontext_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);希望这能帮上忙!
https://stackoverflow.com/questions/5964642
复制相似问题