我只是想知道如何报告分段错误。
- 进程将直接死亡,因此显然无法报告它。
- 除非进程传递信号,否则shell不能确定,这可能并不一定发生。
- 操作系统可能能够做些什么,但我不确定如何做。
这些方法中哪一个可以报告分段错误(仅作为示例),以及如何报告?
我只是想知道如何报告分段错误。
这些方法中哪一个可以报告分段错误(仅作为示例),以及如何报告?
进程会直接退出,所以显然它不能报告它。
实际上这是错误的。可以安装一个SIGSEGV
处理程序来替换默认处理程序,该处理程序仅仅将核心转储并退出。通过预加载库可以捕获分段违规事件,并在退出之前使用有限的工具通知运行在系统上的另一个进程发生了什么。
您可以使用像这样的代码,它会调用GDB命令来转储函数调用跟踪:
void BacktraceOnSegv() {
struct sigaction action = {};
action.sa_handler = DumpBacktrace;
if (sigaction(SIGSEGV, &action, NULL) < 0) {
perror("sigaction(SEGV)");
}
}
void DumpBacktrace(int) {
pid_t dying_pid = getpid();
pid_t child_pid = fork();
if (child_pid < 0) {
perror("fork() while collecting backtrace:");
} else if (child_pid == 0) {
char buf[1024];
sprintf(buf, "gdb -p %d -batch -ex bt 2>/dev/null | "
"sed '0,/<signal handler/d'", dying_pid);
const char* argv[] = {"sh", "-c", buf, NULL};
execve("/bin/sh", (char**)argv, NULL);
_exit(1);
} else {
waitpid(child_pid, NULL, 0);
}
_exit(1);
}
这里有一个支持更多平台的实现。
wait()
或 waitpid()
函数,您会发现退出状态中的一个位表示核心转储。POSIX规范提到了WIFSIGNALED
[sic]和WTERMSIG
用于获取终止进程的信号。虽然POSIX规范没有提到,但例如在Mac OS X(10.7.4)上,有一个WCOREDUMP()
宏用于测试是否创建了核心文件。首先,当CPU尝试访问进程无权访问的地址时,会发生分段错误。在最低层次上,内存映射的实现必须检测到这一点,通常会产生中断。内核接收该中断,并具有其他代码段的地址表,每个代码段都旨在处理该中断。
当内核接收到该中断时,它将其转换为特定值(我之所以含糊其辞,是因为确切的细节因硬件架构和内核实现而异)。SIGSEGV
通常被定义为值11,但确切的值并不重要;它在signal.h
中定义。
此时,信号值传递给内核内部的另一个表,其中包含“信号处理程序”的地址。其中一个处理程序位于由SIGSEGV
表示的偏移量处。除非您已经采取措施更改它,否则该地址通常是导致核心转储的例程地址,假设适当的限制允许,但您可以将其替换为自己的例程地址,该地址可以执行任何您想要的操作。