我在ARM上使用C for Linux编写了一个小应用程序,它为SIGTRAP信号设置了一个信号处理程序,并且应该捕获bkpt
指令(通过TRAP_HWBKPT
代码)并有效地跳过它
处理程序只是在断点地址(这是下一条指令)之后通知断点被引发的位置并使用内联结尾将代码流重定向到4个字节(由于ARM的RISC架构)。我知道应该保留一些寄存器,但现在不是问题。
似乎发生的事情是,对包含断点的函数的第一次调用正常,但第二次调用不再被自定义sigtrap_handler
捕获,而是传递给默认处理程序(导致进程)终止):
有谁知道为什么会发生这种情况以及如何解决这个问题,以便我可以实现为每个bkpt
指令调用处理程序并继续正常执行的目标?
$ gcc -o break break.c
$ ./break
START
ENTER [0]!
SIGTRAP at 0x856c
EXIT [0]!
ENTER [1]!
Trace/breakpoint trap
这是有问题的代码:
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifndef TRAP_BRANCH
#define TRAP_BRANCH 3
#endif
#ifndef TRAP_HWBKPT
#define TRAP_HWBKPT 4
#endif
static void sigtrap_handler(int sig, siginfo_t* siginfo, void* ptr)
{
switch(siginfo->si_code)
{
case TRAP_HWBKPT:
{
printf("SIGTRAP at %p\n", (void*)siginfo->si_addr);
asm volatile("sub sp, r11, #4\n\t"
"pop {r11}\n\t"
"sub sp, #4\n\t"
"mov pc, %0"
:
: "r" (siginfo->si_addr + 4) // Proceed to instruction directly after breakpoint
);
}break;
// misc. SIGTRAP codes (fallthrough)
case TRAP_BRKPT:
case TRAP_TRACE:
case TRAP_BRANCH:
default:
{
exit(-1);
}break;
}
}
void dummy_routine(int n)
{
printf("ENTER [%d]!\n", n);
// Breakpoint
asm volatile("bkpt");
printf("EXIT [%d]!\n", n);
return;
}
int main (int argc, char *argv[])
{
int i;
struct sigaction act;
// Set up sigtrap handler
memset (&act, 0, sizeof(act));
act.sa_sigaction = sigtrap_handler;
act.sa_flags = SA_SIGINFO;
if (sigaction(SIGTRAP, &act, 0)) {
perror("Error: sigaction");
return 1;
}
printf("START\n");
// Trigger routine containing breakpoint multiple times
for(i = 0; i < 2; i++)
{
dummy_routine(i);
}
printf("END\n");
return 0;
}