boost stacktrace堆栈打印

最近3年一直在做手游开发, cocos+lua跨平台win,安卓,ios

在windows下最方便的是minidump,其他2个平台麻烦不少,google-breakpad使用起来又太麻烦.

最近boost1.65版本出了个stacktrace使用起来简单方便,只是无法看实际数据,对于快速定位BUG还是很有帮助的.

要注意的是异常的处理需要写文件,应用重启之后再读取查看~  用其他应用读取或者修改应用之后读取都会无法正确显示!!!

 1 #pragma once
 2 //异常生成dump时立刻查看会死锁,只能重启应用后才能查看
 3 
 4 #ifndef BOOST_ENABLE_ASSERT_DEBUG_HANDLER
 5 #define BOOST_ENABLE_ASSERT_DEBUG_HANDLER
 6 #endif
 7 
 8 #include <string>
 9 #include <boost/noncopyable.hpp>
10 #include <boost/function.hpp>
11 #include <boost/stacktrace.hpp>
12 
13 class plugin_dump : 
14     private boost::noncopyable
15 {
16 public:
17     plugin_dump();
18     ~plugin_dump();
19 
20     //显示dump信息回调
21     typedef boost::function1<void, const boost::stacktrace::stacktrace&> ON_DUMP;
22 
23     void set_handler(ON_DUMP _handler);
24 
25     static std::string gen_filename();
26 private:
27     void show_last_dump();
28     ON_DUMP m_handler;
29 };
plugin_dump.h
 1 #include "stdafx.h"
 2 #include "plugin_dump.h"
 3 
 4 #include <signal.h>     // ::signal, ::raise
 5 #include <strstream>
 6 #include <stdexcept>    // std::logic_error
 7 #include <iostream>     // std::cerr
 8 #include <boost/filesystem.hpp>
 9 #include <enable_process_info.hpp>
10 
11 void g_signal_handler(int signum) {
12     ::signal(signum, SIG_DFL);    
13     std::string filename = plugin_dump::gen_filename();
14     if (boost::filesystem::exists(filename.c_str()))
15         boost::filesystem::remove(filename.c_str());
16     boost::stacktrace::safe_dump_to(3, boost::stacktrace::detail::max_frames_dump, filename.c_str());
17     ::raise(SIGABRT);
18 }
19 
20 plugin_dump::plugin_dump()
21 {
22     ::signal(SIGSEGV, &g_signal_handler);
23     ::signal(SIGABRT, &g_signal_handler);
24     if (!boost::filesystem::exists("./dumps"))
25         boost::filesystem::create_directory("./dumps");
26 }
27 
28 plugin_dump::~plugin_dump()
29 {    
30     
31 }
32 
33 void plugin_dump::set_handler(ON_DUMP _handler)
34 {
35     m_handler = _handler;
36     show_last_dump();
37 }
38 
39 void plugin_dump::show_last_dump()
40 {
41     std::string filename = plugin_dump::gen_filename();
42     if (boost::filesystem::exists(filename.c_str())) {
43 
44         std::ifstream ifs(filename.c_str());
45         boost::stacktrace::stacktrace st = boost::stacktrace::stacktrace::from_dump(ifs);
46 
47         if (!m_handler.empty())
48             m_handler(st);
49         else
50             std::cout << st;
51 
52         ifs.close();
53         std::getchar();
54     }
55 }
56 
57 std::string plugin_dump::gen_filename()
58 {
59     std::string file = "./dumps/" + enable_process_info::get_processname() + ".dump";
60     return file;
61 }
62 
63 //////////////////////////////////////////////////////////////////////////
64 // BOOST_ENABLE_ASSERT_DEBUG_HANDLER is defined for the whole project
65 namespace boost {
66     inline void assertion_failed_msg(char const* expr, char const* msg, char const* function, char const* /*file*/, long /*line*/) {
67         std::cerr << "Expression '" << expr << "' is false in function '" << function << "': " << (msg ? msg : "<...>") << ".\n"
68             << "Backtrace:\n" << boost::stacktrace::stacktrace() << '\n';
69         std::abort();
70     }
71 
72     inline void assertion_failed(char const* expr, char const* function, char const* file, long line) {
73         ::boost::assertion_failed_msg(expr, 0 /*nullptr*/, function, file, line);
74     }
75 } // namespace boost
plugin_dump.cpp

 

 

 

 

转载于:https://www.cnblogs.com/zhangchengxin/p/7767213.html

<think>好的,我需要帮助用户找到在C++打印调用堆栈的方法或库。用户之前提供了跨平台的实现示例,但可能还需要更多的选项或更详细的解释。让我先回顾一下之前的回答和引用内容。 首先,用户提供的引用1提到了在JNI C++打印调用堆栈的方法,链接到一篇博客,这可能涉及使用Linux的backtrace或Windows的API。引用2讨论了使用WinDbg进行堆栈跟踪,但用户可能需要程序内自动打印,而不是外部工具。引用3是关于Android Native层的CallStack使用,可能与Android特定环境相关。 用户上一次的问题中,我给出了一个跨平台的实现,使用Windows的dbghelp和Linux的execinfo。现在用户可能希望了解其他方法或库,比如Boost.Stacktrace,或者更深入的解释不同方法的优缺点。 我需要考虑以下几点: 1. **跨平台支持**:用户可能需要适用于不同操作系统的解决方案,比如Windows、Linux、macOS。 2. **库的使用**:是否有现成的库可以简化实现,比如Boost或第三方库。 3. **调试符号和编译选项**:如何确保生成必要的调试信息,以便正确解析堆栈跟踪。 4. **异常处理集成**:如何在程序崩溃时自动打印堆栈,比如信号处理或结构化异常处理。 5. **性能影响**:某些方法可能在运行时带来额外开销,需要注意。 6. **移动平台**:如Android或iOS,可能需要不同的方法,比如Android NDK中的<unwind.h>。 根据这些考虑,我应该整理不同的方法,包括标准库、第三方库、平台特定API,并比较它们的优缺点。同时需要提到编译时的注意事项,如-g选项、-rdynamic等,以及如何处理demangling问题,特别是在C++中函数名会被修饰。 另外,用户之前的回答已经覆盖了基本的实现,现在可能需要补充其他方法,比如使用libunwind,或者GCC的内置函数如__builtin_return_address,但这些可能功能有限。Boost.Stacktrace是一个值得推荐的库,因为它提供了跨平台的接口,简化了实现。 还需要注意,在某些环境如嵌入式系统或没有调试信息的情况下,堆栈跟踪可能不可行,因此需要说明这些限制。此外,发布版本通常去除调试信息,因此堆栈跟踪在生产环境中可能不适用,除非特别处理。 最后,可能需要提供代码示例,比如使用Boost.Stacktrace的简单示例,以及如何集成到项目中。同时提醒用户相关依赖和编译选项,确保正确使用。</think>以下是在C++中实现调用堆栈打印的多种方法及详细分析,涵盖原生API、第三方库和跨平台方案: #### 一、原生API实现方案 $\boxed{1. Windows平台}$ ```cpp #include <windows.h> #include <dbghelp.h> #pragma comment(lib, "dbghelp.lib") void PrintStack() { void* stack[62]; HANDLE process = GetCurrentProcess(); SymInitialize(process, NULL, TRUE); USHORT frames = CaptureStackBackTrace(0, 62, stack, NULL); SYMBOL_INFO* symbol = (SYMBOL_INFO*)malloc(sizeof(SYMBOL_INFO) + 256); symbol->MaxNameLen = 255; symbol->SizeOfStruct = sizeof(SYMBOL_INFO); for (USHORT i = 0; i < frames; ++i) { SymFromAddr(process, (DWORD64)stack[i], 0, symbol); std::cout << i << ": " << symbol->Name << "\n"; } free(symbol); SymCleanup(process); } ``` $\textcolor{red}{关键点}$:需链接dbghelp.lib,调试版本需生成PDB文件[^3] $\boxed{2. Linux平台}$ ```cpp #include <execinfo.h> #include <cxxabi.h> void PrintStack() { void* array[10]; size_t size = backtrace(array, 10); char** strings = backtrace_symbols(array, size); for (size_t i = 0; i < size; ++i) { char* mangled = strchr(strings[i], '('); if(mangled) { int status; char* demangled = abi::__cxa_demangle(mangled+1,0,0,&status); std::cout << (demangled ? demangled : mangled) << "\n"; free(demangled); } } free(strings); } ``` $\textcolor{red}{编译要求}$:需添加`-rdynamic -g`编译选项[^1] #### 二、第三方库方案 $\boxed{1. Boost.Stacktrace}$ ```cpp #include <boost/stacktrace.hpp> void PrintStack() { std::cout << boost::stacktrace::stacktrace(); } ``` $\textcolor{red}{优势}$:跨平台支持,自动处理符号demangling $\boxed{2. Google Breakpad}$ ```cpp #include <client/linux/handler/exception_handler.h> bool DumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded) { std::cout << "生成dump文件: " << descriptor.path(); return succeeded; } void InitCrashHandler() { google_breakpad::MinidumpDescriptor descriptor("/tmp"); new google_breakpad::ExceptionHandler(descriptor, NULL, DumpCallback, NULL, true, -1); } ``` $\textcolor{red}{特点}$:适用于生产环境崩溃分析[^2] #### 三、移动平台方案 $\boxed{Android NDK}$ ```cpp #include <android/log.h> #include <unwind.h> #include <dlfcn.h> struct BacktraceState { void** current; void** end; }; static _Unwind_Reason_Code UnwindCallback(struct _Unwind_Context* context, void* arg) { BacktraceState* state = static_cast<BacktraceState*>(arg); uintptr_t pc = _Unwind_GetIP(context); if (pc && state->current != state->end) { *state->current++ = reinterpret_cast<void*>(pc); } return _URC_NO_REASON; } void PrintStack() { void* buffer[50]; BacktraceState state = {buffer, buffer + 50}; _Unwind_Backtrace(UnwindCallback, &state); int count = state.current - buffer; for (int i = 0; i < count; ++i) { Dl_info info; if (dladdr(buffer[i], &info)) { __android_log_print(ANDROID_LOG_DEBUG, "STACK", "#%02d: %p %s", i, buffer[i], info.dli_sname); } } } ``` #### 四、方法对比分析 | 方法 | 平台支持 | 依赖项 | 调试符号需求 | 生产环境适用性 | |---------------------|-------------|-----------------|------------|--------------| | DbgHelp API | Windows | dbghelp.lib | 必需PDB | 不推荐 | | backtrace | Linux/Mac | libc | 需要-g | 有限支持 | | Boost.Stacktrace | 跨平台 | Boost 1.65+ | 需要 | 推荐 | | Breakpad | 跨平台 | Breakpad库 | 可选 | 最佳 | | NDK Unwind | Android | NDK r21+ | 需要 | 推荐 | #### 五、工程实践建议 1. **调试符号管理** - Windows:确保生成PDB文件(/Zi编译选项) - Linux:编译时添加`-g -rdynamic`选项 - Android:在build.gradle中配置`externalNativeBuild { debuggable true }` 2. **生产环境处理** ```cpp // Windows异常处理 LONG WINAPI VectoredHandler(PEXCEPTION_POINTERS pExceptionInfo) { PrintStack(); return EXCEPTION_CONTINUE_SEARCH; } // Linux信号处理 void SignalHandler(int sig) { PrintStack(); signal(sig, SIG_DFL); raise(sig); } void RegisterHandlers() { #ifdef _WIN32 AddVectoredExceptionHandler(1, VectoredHandler); #else signal(SIGSEGV, SignalHandler); signal(SIGABRT, SignalHandler); #endif } ``` 3. **性能优化技巧** - 缓存符号解析结果(Windows下SymFromAddr调用成本较高) - 限制堆栈深度(通常保留最近30-50帧即可) - 异步输出机制(避免在信号处理函数中直接进行I/O操作) $\boxed{典型问题解决方案}$ **Q:打印结果出现`?? ??:0`未知符号?** A:检查以下配置: 1. Windows需确保PDB文件与可执行文件路径一致 2. Linux编译时缺少`-rdynamic`选项 3. 发布版本剥离了调试符号(使用`objcopy --only-keep-debug`保留符号) **Q:如何获取行号信息?** Windows示例: ```cpp IMAGEHLP_LINE64 line; line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); DWORD displacement; if (SymGetLineFromAddr64(process, address, &displacement, &line)) { std::cout << line.FileName << ":" << line.LineNumber; } ``` $\boxed{扩展阅读}$ 1. [LLVM Libunwind](https://libcxx.llvm.org/docs/DesignDocs/Unwinding.html) 跨平台unwinding实现 2. [DWARF调试格式](https://dwarfstd.org/) Linux调试信息标准 3. [PDB文件格式](https://github.com/Microsoft/microsoft-pdb) Windows符号文件解析 [^1]: Linux平台需注意编译时符号可见性问题 [^2]: Breakpad需要配置符号服务器进行离线分析 [^3]: Windows符号解析依赖正确的符号搜索路径设置
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值