How to get fullstacktrace using _Unwind_Backtrace on SIGSEGV

Henry Pootle picture Henry Pootle · Jun 6, 2011 · Viewed 11.5k times · Source

I handle SIGSEGV by code:

int C()
{
  int *i = NULL;
  *i = 10; // Crash there
}

int B()
{
  return C();
}

int A()
{
   return B();
}

int main(void)
{
  struct sigaction handler;
  memset(&handler,0,sizeof(handler));
  handler.sa_sigaction = handler_func;
  handler.sa_flags = SA_SIGINFO;
  sigaction(SIGSEGV,&handler,NULL);
  return(C());
}

Where handler code are:

static int handler_func(int signal, siginfo_t info, void* rserved)
{
  const void* stack[MAX_DEPTH];
  StackCrowlState state;
  state.addr = stack;
  state.count = MAX_DEPTH;

  _Unwind_Reason_Code code = _Unwind_Backtrace(trace_func,&state);
  printf("Stack trace count: %d, code: %d\n",MAX_DEPTH - state.count, code);

  kill(getpid(),SIGKILL);
}

static _Unwind_Reason_Code trace_func(void* context, void* arg)
{
  StackCrowlState *state = (StackCrowlState *)arg;
  if(state->count>0)
  {
     void *ip = (void *)_Unwind_GetIP(context);
     if(ip)
     {
       state->addr[0] = ip;
       state->count--;
       state->addr++;
     }
  }
  return(_URC_NO_REASON);
}

But trace_func where called only once, and shows only on _Unwind_Backtrace calls. Is it possible to get stacktrace of code which cause SIGSEGV signal using _Unwind_Backtrace?

thnx

Answer

Wu Yongzheng picture Wu Yongzheng · Nov 1, 2012

You want to backtrace from the signal triggering function, but you backtrace from the signal handler function. That's two different stacks. (Note, the SA_ONSTACK flag in sigaction is irrelevant to your question.)

To find the stack pointer of the of the triggering function, use the third parameter of the handler, i.e. void *rserved. You can reference to the answer in this question: Getting the saved instruction pointer address from a signal handler