我尝试根据现实生活场景编写一段示例代码。场景如下:
- 程序正在调用递归函数
- 堆栈被使用
- 程序崩溃,只有操作系统上的核心转储作为有用信息
我正在尝试编写自己的崩溃处理程序以获得更好的故障排除信息。我还认为,如果在当前阶段,并非所有堆栈溢出异常都被捕获和处理,这可能会很有用。我正在使用 SA_ONSTACK 为信号处理创建一个新堆栈。但是它只允许打印 1 行错误消息 "sig_handler: signal 11" 。但是我无法打印出使用 libunwind 崩溃的调用堆栈(同一段代码适用于堆损坏导致的信号 11——例如空指针)。
有人可以建议在编程SIGSEGV时如何打印调用堆栈,因为stackovflow?
我的测试代码如下:
#define UNW_LOCAL_ONLY
#include <execinfo.h>
#include <cstdlib> // free, exit
#include <unistd.h> // _exit
#include <csignal> // sigaction, signal type sigemptyset
#include <stdio.h>
#include <cxxabi.h>
#include <string.h>
#include <libunwind.h>
#include <errno.h>
#include <err.h>
#include <execinfo.h>
#define sigsegv_outp(x, ...) fprintf(stderr, x "\n", ##__VA_ARGS__)
void unwind() {
printf("start unwinding\n");
unw_cursor_t cursor;
unw_context_t context;
// Initialize cursor to current frame for local unwinding.
unw_getcontext(&context);
unw_init_local(&cursor, &context);
// Unwind frames one by one, going up the frame stack.
while (unw_step(&cursor) > 0) {
unw_word_t offset, pc;
unw_get_reg(&cursor, UNW_REG_IP, &pc);
if (pc == 0) {
break;
}
printf("ip 0x%lx:", pc);
char sym[256];
if (unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) == 0) {
printf(" (%s+0x%lx) ", sym, offset);
char* demangle_ptr = sym;
int ret_state;
char* demangled = abi::__cxa_demangle(sym, nullptr, nullptr, &ret_state);
if (ret_state == 0) {
demangle_ptr = demangled;
}
printf(" -> %s+0x%lx\n", demangle_ptr, offset);
free(demangled);
} else {
printf(" Error: unable to obtain symbol name for this frame\n");
}
}
}
static void sig_handler(int signum, siginfo_t *si, void *ctx)
{
static const char *si_codes[3] = {"", "SEGV_MAPERR", "SEGV_ACCERR"};
// unw_context_t *context = ctx;
printf("%s: signal %d\n", __FUNCTION__, signum);
sigsegv_outp("Segmentation Fault!");
sigsegv_outp("info.si_signo = %d", signum);
sigsegv_outp("info.si_errno = %d", si->si_errno);
sigsegv_outp("info.si_code = %d (%s)", si->si_code, si_codes[si->si_code]);
sigsegv_outp("info.si_addr = %p", si->si_addr);
switch(signum ) {
case SIGSEGV:
printf("%s:ninatest: sigsegv %d\n", __FUNCTION__, signum);
unwind();
break;
default:
break;
}
_exit(1);
}
void endless_stackFrames(void) {
while (true) {
endless_stackFrames();
}
}
}
static uint8_t alternate_stack[SIGSTKSZ];
void set_signal_handler()
{
{
stack_t ss = {};
ss.ss_sp = (void*)alternate_stack;
ss.ss_size = SIGSTKSZ;
ss.ss_flags = 0;
if (sigaltstack(&ss, NULL) != 0) { err(1, "sigaltstack"); }
}
{
struct sigaction sig_action = {};
sig_action.sa_sigaction = sig_handler;
sigemptyset(&sig_action.sa_mask);
sig_action.sa_flags = SA_SIGINFO | SA_ONSTACK;
if (sigaction(SIGSEGV, &sig_action, NULL) != 0) { err(1, "sigaction"); }
}
}
int main(int argc, char **argv) {
set_signal_handler();
endless_stackFrames();
return 0;
}
之后可以通过 g++ stack_overflow_test1.cpp -o stack_overflow_test1 -g -lunwind -Wall -std=c++11 构建并通过 $LD_LIBRARY_PATH=/usr/local/lib ./stack_overflow_test1 执行