0

我尝试根据现实生活场景编写一段示例代码。场景如下:

  • 程序正在调用递归函数
  • 堆栈被使用
  • 程序崩溃,只有操作系统上的核心转储作为有用信息

我正在尝试编写自己的崩溃处理程序以获得更好的故障排除信息。我还认为,如果在当前阶段,并非所有堆栈溢出异常都被捕获和处理,这可能会很有用。我正在使用 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 执行

4

0 回答 0