如何在SIGSEGV上使用_Unwind_Backtrace获取fullstacktrace

我通过代码处理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调用时显示。 是否有可能使用_Unwind_Backtrace获取导致SIGSEGV信号的代码堆栈跟踪?

日Thnx

您想要从信号触发function中回溯,但是您从信号处理函数中回溯。 这是两个不同的堆栈。 (注意,sigaction中的SA_ONSTACK标志与您的问题无关。)

要查找触发函数的堆栈指针,请使用处理程序的第三个参数,即void * rserved。 您可以在这个问题中引用答案: 从信号处理程序获取保存的指令指针地址

如果你想特别使用_Unwind_Context() ,你可以这样做(代码是32位ARM特定的):


 struct BacktraceState { const ucontext_t* signal_ucontext; size_t address_count = 0; static const size_t address_count_max = 30; uintptr_t addresses[address_count_max] = {}; BacktraceState(const ucontext_t* ucontext) : signal_ucontext(ucontext) {} bool AddAddress(uintptr_t ip) { // No more space in the storage. Fail. if (address_count >= address_count_max) return false; // Reset the Thumb bit, if it is set. const uintptr_t thumb_bit = 1; ip &= ~thumb_bit; // Ignore null addresses. // They sometimes happen when using _Unwind_Backtrace() // with the compiler optimizations, // when the Link Register is overwritten by the inner // stack frames. if (ip == 0) return true; // Ignore duplicate addresses. // They sometimes happen when using _Unwind_Backtrace() // with the compiler optimizations, // because we both add the second address from the Link Register // in ProcessRegisters() and receive the same address // in UnwindBacktraceCallback(). if (address_count > 0 && ip == addresses[address_count - 1]) return true; // Finally add the address to the storage. addresses[address_count++] = ip; return true; } }; void ProcessRegisters( _Unwind_Context* unwind_context, BacktraceState* state) { assert(state); assert(unwind_context); const ucontext_t* signal_ucontext = state->signal_ucontext; assert(signal_ucontext); const sigcontext* signal_mcontext = &(signal_ucontext->uc_mcontext); assert(signal_mcontext); _Unwind_SetGR(unwind_context, REG_R0, signal_mcontext->arm_r0); _Unwind_SetGR(unwind_context, REG_R1, signal_mcontext->arm_r1); _Unwind_SetGR(unwind_context, REG_R2, signal_mcontext->arm_r2); _Unwind_SetGR(unwind_context, REG_R3, signal_mcontext->arm_r3); _Unwind_SetGR(unwind_context, REG_R4, signal_mcontext->arm_r4); _Unwind_SetGR(unwind_context, REG_R5, signal_mcontext->arm_r5); _Unwind_SetGR(unwind_context, REG_R6, signal_mcontext->arm_r6); _Unwind_SetGR(unwind_context, REG_R7, signal_mcontext->arm_r7); _Unwind_SetGR(unwind_context, REG_R8, signal_mcontext->arm_r8); _Unwind_SetGR(unwind_context, REG_R9, signal_mcontext->arm_r9); _Unwind_SetGR(unwind_context, REG_R10, signal_mcontext->arm_r10); _Unwind_SetGR(unwind_context, REG_R11, signal_mcontext->arm_fp); _Unwind_SetGR(unwind_context, REG_R12, signal_mcontext->arm_ip); _Unwind_SetGR(unwind_context, REG_R13, signal_mcontext->arm_sp); _Unwind_SetGR(unwind_context, REG_R14, signal_mcontext->arm_lr); _Unwind_SetGR(unwind_context, REG_R15, signal_mcontext->arm_pc); // Program Counter register aka Instruction Pointer will contain // the address of the instruction where the crash happened. // UnwindBacktraceCallback() will not supply us with it. state->AddAddress(signal_mcontext->arm_pc); // UnwindBacktraceCallback() does not always supply us with // the return address of the frame where the crash happened. // Sometimes Link Register will contain this address // (noticed when compiling with Clang without optimization), // but LR may also contain address of some previously visitied frame // (noticed when compiling with GCC without optimization), // or LR may contain null address // (noticed when compiling with Clang with optimization). // These heuristics are unreliable. #if __clang__ state->AddAddress(signal_mcontext->arm_lr); #endif } _Unwind_Reason_Code UnwindBacktraceCallback( struct _Unwind_Context* unwind_context, void* state_voidp) { assert(unwind_context); assert(state_voidp); BacktraceState* state = (BacktraceState*)state_voidp; assert(state); // On the first UnwindBacktraceCallback() call, // set registers to _Unwind_Context and BacktraceState. if (state->address_count == 0) { ProcessRegisters(unwind_context, state); return _URC_NO_REASON; } uintptr_t ip = _Unwind_GetIP(unwind_context); bool ok = state->AddAddress(ip); if (!ok) return _URC_END_OF_STACK; return _URC_NO_REASON; } void CaptureBacktrace(BacktraceState* state) { assert(state); _Unwind_Backtrace(UnwindBacktraceCallback, state); } void SigActionHandler(int sig, siginfo_t* info, void* ucontext) { const ucontext_t* signal_ucontext = (const ucontext_t*)ucontext; assert(signal_ucontext); BacktraceState backtrace_state(signal_ucontext); CaptureBacktrace(&backtrace_state); // Do something with the backtrace - print, save to file, etc. } 

但我建议你不要使用_Unwind_Context() ,而是使用预编译的libunwind用于32位ARM,与现代Android NDK捆绑在一起(在sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libunwind.a ) 。 您将不得不使用libc ++(LLVM STL)。 怎么做,在我的答案中certificate:

https://stackoverflow.com/a/50027799/1016580

如果您使用libstdc ++(GNU STL),请使用Dar Hoo的解决方案:

https://stackoverflow.com/a/48593413/1016580

最好使用backtrace和backtrace_symbols_fd从信号处理程序获取堆栈跟踪。

您可以改用__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(&(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; }