【发布时间】:2012-09-03 01:47:11
【问题描述】:
我只是想知道如何报告分段错误。
- 进程会死掉,所以显然不能报告。
- 除非进程传递信号,否则 shell 将无法确定,但情况不一定如此。
- 操作系统可能会做一些事情,但我不确定如何做。
其中哪一个报告分段错误(仅作为示例),以及如何报告?
【问题讨论】:
标签: c++ bash ubuntu segmentation-fault
我只是想知道如何报告分段错误。
其中哪一个报告分段错误(仅作为示例),以及如何报告?
【问题讨论】:
标签: c++ bash ubuntu segmentation-fault
进程会死掉,所以显然它不能报告它。
这实际上是错误的。 是可以安装一个SIGSEGV 处理程序来替换默认的处理程序,它只是转储核心并死掉。预加载库可以这样做以捕获分段违规并使用可用的有限设施来通知在系统上运行的另一个进程在退出之前发生了什么。
【讨论】:
如果您查看函数wait() or waitpid(),您会发现退出状态中的一位表示核心转储。 POSIX 规范提到 WIFSIGNALED [原文如此] 和 WTERMSIG 以获取终止进程的信号。 POSIX 规范没有提到它,但在 Mac OS X (10.7.4) 上,例如,有一个 WCOREDUMP() 宏来测试是否创建了核心文件。
【讨论】:
你可以有一些像this这样的代码,它会调用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);
}
Here 是一个支持更多平台的实现。
【讨论】:
好的,首先,当 CPU 尝试访问进程无权访问的地址时,会发生分段错误。在最低级别,内存映射的实现必须检测到这一点,这通常会产生中断。内核接收到该中断,并有一个其他代码段的地址表,每个代码段都用于处理该中断。
当内核接收到该中断时,它会将其转换为特定值(我之所以含糊,是因为确切的细节会因硬件架构和内核实现而异)。 SIGSEGV 通常被定义为值为 11,但确切的值并不重要;它在signal.h 中定义。
此时,信号值被传递到内核内部的另一个表,其中包含“信号处理程序”的地址。其中一个处理程序位于SIGSEGV 表示的偏移量处。除非您已更改它,否则该地址通常是导致核心转储的例程,假设适当的限制允许,但您可以将其替换为您自己的例程的地址,它可以做任何您喜欢的事情。
【讨论】: