我是C编程的新手,在进行练习时仅使用标志的地址来增加分段故障信号处理程序的PC时会遇到问题。通过引用标志符号,我已经获得了代码堆栈中的标志地址,但是我怎么知道应该将它增加多少到PC存储指令指针以手动推进程序计数器的位置?
void segf_handler(int signum)
{
int address=&signum;
}
int main()
{
int n = 0;
signal(SIGSEGV, segment_fault_handler);
n = *( (int *) 0 );
printf("recover from segfault\n");
return 0;
}
谢谢!
答案 0 :(得分:1)
为了能够访问已保存PC的位置,您必须使用sigaction
和三参数信号处理程序:
#include <stdio.h>
#include <signal.h>
#include <ucontext.h>
void segf_handler(int sig, siginfo_t *info, void *cx_)
{
ucontext_t *cx = cx_;
/* Extremely OS- and architecture-specific manipulation
of the data pointed to by `cx` goes here */
}
int *volatile cause_crash = 0;
int main(void)
{
struct sigaction sa;
sigfillset(&sa.sa_mask);
sa.sa_sigaction = segf_handler;
sa.sa_flags = SA_RESTART | SA_SIGINFO;
if (sigaction(SIGSEGV, &sa, 0)) {
perror("sigaction");
return 1;
}
*cause_crash = 0;
puts("recovered from segfault");
return 0;
}
保存的PC将在cx
指向的数据中某处,您可以操纵它来更改正常控制将恢复的位置。 info
指向的数据还将包含尝试执行此类操作的程序的有用详细信息,例如(对于SIGSEGV)错误指令尝试访问的错误地址。
不幸的是,我无法告诉您在哪里可以找到PC,因为ucontext_t
的内容并非标准化 ,并且与CPU和操作系统,你没有告诉我们任何一个。
请注意,sigaction
不是任何C标准版本的一部分。除了ucontext_t
的内容之外,上述代码使用的所有内容都是POSIX.1-1996的一部分,因此您可以指望它可以处理您可能正在使用的任何内容除外< / em>适用于某些嵌入式操作系统和Windows。特别是,在Windows上,你需要做一些完全不同的,我不能很好地理解这些
另请注意,如果您的导师告诉您可以使用signal
和/或单参数信号处理程序访问已保存的PC,那么他们就错了,如果他们需要你做这个练习的一部分,然后这是一个不正确的要求,在这两种情况下你都可以告诉他们我这么说。