如何展开堆栈以获取指定堆栈指针(SP)的回溯?

我正在为Android编写(仅限ARM),但我相信通用Linux的原理也是一样的。

我试图从信号处理程序捕获堆栈跟踪,以便我的应用程序崩溃时可以logging它。 这就是我使用<unwind.h>
初始化:

 struct sigaction signalhandlerDescriptor; memset(&signalhandlerDescriptor, 0, sizeof(signalhandlerDescriptor)); signalhandlerDescriptor.sa_flags = SA_SIGINFO; signalhandlerDescriptor._u._sa_sigaction = signalHandler; sigaction(SIGSEGV, &signalhandlerDescriptor, 0); 

代码本身:

 struct BacktraceState { void** current; void** end; void* pc; }; inline _Unwind_Reason_Code unwindCallback(struct _Unwind_Context* context, void* arg) { BacktraceState* state = static_cast<BacktraceState*>(arg); state->pc = (void*)_Unwind_GetIP(context); if (state->pc) { if (state->current == state->end) return _URC_END_OF_STACK; else *state->current++ = reinterpret_cast<void*>(state->pc); } return _URC_NO_REASON; } inline size_t captureBacktrace(void** addrs, size_t max, unsigned long pc) { BacktraceState state = {addrs, addrs + max, (void*)pc}; _Unwind_Backtrace(unwindCallback, &state); personality_routine(); return state.current - addrs; } inline void dumpBacktrace(std::ostream& os, void** addrs, size_t count) { for (size_t idx = 0; idx < count; ++idx) { const void* addr = addrs[idx]; const char* symbol = ""; Dl_info info; if (dladdr(addr, &info) && info.dli_sname) { symbol = info.dli_sname; } int status = -3; char * demangledName = abi::__cxa_demangle(symbol, 0, 0, &status); os << "#" << idx << ": " << addr << " " << (status == 0 ? demangledName : symbol) << "\n"; free(demangledName); } } void signalHandler(int sig, siginfo_t *siginfo, void *uctx) { ucontext * context = (ucontext*)uctx; unsigned long PC = context->uc_mcontext.arm_pc; unsigned long SP = context->uc_mcontext.arm_sp; Logger() << __PRETTY_FUNCTION__ << "Fatal signal:" << sig; const size_t maxNumAddresses = 50; void* addresses[maxNumAddresses]; std::ostringstream oss; const size_t actualNumAddresses = captureBacktrace(addresses, maxNumAddresses, PC); dumpBacktrace(oss, addresses, actualNumAddresses); Logger() << oss.str(); exit(EXIT_FAILURE); } 

问题:如果通过在unwindCallback调用_Unwind_GetIP(context)来获得PC寄存器,那么我将得到信号处理器堆栈的完整跟踪。 这是一个单独的堆栈,这显然不是我想要的。 所以我尝试从信号处理程序中的ucontext提供PC,并得到一个奇怪的结果:我得到一个堆栈条目,它是正确的条目 – 导致信号的function在第一位。 但它logging了两次(即使地址是一样的,所以它不是一个符号名称查找错误)。 显然,这不够好 – 我需要整个堆栈。 我想知道这个结果是不是偶然的(即它不应该在一般情况下工作。

现在,我读了我也需要提供堆栈指针,我显然可以从ucontext获得,和PC一样。 但我不知道该怎么办。 我是否必须手动_Unwind_Backtrace而不是使用_Unwind_Backtrace ? 如果是这样,你可以给我示例代码? 我一直在寻找更好的一天,仍然找不到任何我可以复制和粘贴到我的项目。

对于它的价值,这里是包含_Unwind_Backtrace定义的libunwind源代码。 如果我看到它的来源,我想我可以找出一些东西,但这比我想象的要复杂得多。

Solutions Collecting From Web of "如何展开堆栈以获取指定堆栈指针(SP)的回溯?"

首先,您需要阅读“异步信号安全”功能部分:

http://man7.org/linux/man-pages/man7/signal.7.html

这是一整套可以在信号处理程序中调用的安全函数。 关于你能做的最糟糕的事情就是调用任何调用malloc()/ free()的东西 – 或者自己动手。

其次,首先让它在信号处理器之外工作。

第三,这些可能是合适的:

如何在Android上获取C ++回溯

Android NDK:获得回溯