backtrace
,backtrace_symbols
,abi::__cxa_demangle
来打印堆栈跟踪。
但据我所知,我们需要使用编译器标志-g
构建二进制文件,而不是高于-O1
的优化标志。我可以做到这一点。我希望能够在发布二进制文件(例如使用
-O3
标志进行编译)中生成具有正确函数名称的回溯。
这可行吗?
我对此进行了大量研究,但没有得到实质性的东西。更新1: 是否有一种方法可以有一个包含某些符号的辅助文件,可以从优化二进制进程内部引用以生成堆栈跟踪?
backtrace
,backtrace_symbols
,abi::__cxa_demangle
来打印堆栈跟踪。
但据我所知,我们需要使用编译器标志-g
构建二进制文件,而不是高于-O1
的优化标志。我可以做到这一点。-O3
标志进行编译)中生成具有正确函数名称的回溯。
这可行吗?
我对此进行了大量研究,但没有得到实质性的东西。在信号处理程序中打印回溯信息
无论优化级别如何,在信号处理程序中调用 backtrace
1, backtrace_symbols
1, 或者 abi::__cxa_demangle
都不是安全的。它们不是异步安全函数,如果在信号处理程序中使用可能会导致程序崩溃、内存损坏或冻结。关于打印,如果您计划使用任何 printf
函数族,则需知道它们在信号处理程序中也不安全(至少 POSIX 指定的所有函数都是如此)。
有些库/函数承诺提供信号安全的栈展开、符号重组、格式化和输出,从而实现这一目标。
1 根据 man 手册,只要加载了共享的 libgcc,使用 backtrace
理应是安全的。 backtrace_symbols
有一个更安全的替代品 backtrace_symbols_fd
,它在 libgcc 方面有相同的注意点。
是否可以有一个包含一些符号的次要文件?
您可以使用 objcopy
将调试符号从可执行文件中复制出来并使用 strip
从可执行文件中删除符号。
GDB 支持外部符号文件,但我不知道 / 如何从程序内部使用它们。我使用过 SymtabAPI 从二进制文件中提取符号;这可能也适用于外部符号文件。但据我所知,该库不能承诺信号安全性。话虽如此,不清楚为什么需要分离;调试符号不影响性能。
如果进程崩溃,我只打算打印栈信息
在这种情况下,可能更好的方法是让操作系统生成一个核心转储文件,并有一个单独的进程监听文件系统事件,一旦创建了核心转储,则会生成回溯并写入某个日志。无需担心信号安全性,无需延迟生成跟踪信息时原始进程的重启,也无需对服务器进程进行额外的依赖。
在优化级别方面,无论您使用什么方法生成跟踪,都可以尝试使用-O3 -fno-omit-frame-pointer
进行优化,并期望最佳效果,但通常最好不要在调试时使用高于-O2
的级别。 -Og
是理想的选择,但速度较慢。
__cxa_demangle()
使用malloc()
系列调用,如果堆被破坏,malloc()
/free()
等函数中的SIGSEGV
异常非常常见。如果您尝试在信号处理程序中解码,可能会导致进程死锁。请参阅https://dev59.com/s3_aa4cB1Zd3GeqP67mG?noredirect=1&lq=1。根据我的经验,`backtrace()`不是那么危险。 - Andrew Henle
-O3
编译可以省略帧指针,使得获取堆栈跟踪更加困难。gcc有一个标志可以解决这个问题。例如,-O3 -fno-omit-frame-pointer
。 - BiagioF-O3
通过积极内联来防止的。如果您想保留每个调用链的链接,请使用-O2
或-Og
。 - The Vee