Подтвердить что ты не робот

Как получить fullstacktrace с помощью _Unwind_Backtrace на SIGSEGV

Я обрабатываю SIGSEGV по коду:

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());
}

Где код обработчика:

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);
}

Но trace_func, где вызывается только один раз, и отображается только на вызовы _Unwind_Backtrace. Возможно ли получить стоп-код кода, который вызывает сигнал SIGSEGV с помощью _Unwind_Backtrace?

Thnx

4b9b3361

Ответ 1

Вы хотите выполнить возврат из функции запуска сигнала, но вы возвращаетесь из функции обработчика сигнала. Это два разных стека. (Обратите внимание, что флаг SA_ONSTACK в sigaction не имеет отношения к вашему вопросу.)

Чтобы найти указатель стека функции запуска, используйте третий параметр обработчика, т.е. void * rserved. Вы можете ссылаться на ответ в этом вопросе: Получение адреса указателя сохраненной инструкции от обработчика сигнала

Ответ 2

лучше использовать backtrace и backtrace_symbols_fd для получения stacktrace из обработчика сигнала.

Ответ 3

Вместо этого вы можете использовать __gnu_Unwind_Backtrace. Пример для ARM32:

typedef struct
{
    uintptr_t r[16];
} core_regs;

typedef struct
{
    uintptr_t demand_save_flags;
    core_regs   core;
} phase2_vrs;

extern "C" _Unwind_Reason_Code __gnu_Unwind_Backtrace(_Unwind_Trace_Fn trace, void * trace_argument, phase2_vrs * entry_vrs);

int AndroidGetBackTraceWithContext(VOID **stack, UINT32 size, ucontext_t *ctx)
{
    ANDROID_UNWIND_STATE state;
    state.count = size;
    state.stack = stack;

    // First call stack is current pc
    state.stack[0] = (VOID *)ctx->uc_mcontext.arm_pc;
    state.stack++;
    state.count--;

    phase2_vrs pre_signal_state;
    pre_signal_state.demand_save_flags = 0;
    pre_signal_state.core = *reinterpret_cast<const core_regs*>(&(ctx->uc_mcontext.arm_r0));

    // Return value is of no use and might be wrong on some systems
    __gnu_Unwind_Backtrace(DmpAndroidUnwindCallback, &state, &pre_signal_state);

    return size - state.count;
}