Как получить 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
Ответы
Ответ 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;
}