Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/125.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在Linux上以发布/优化的二进制文件在信号处理程序中打印回溯_C++_C_Stack Trace_Backtrace_Signal Handling - Fatal编程技术网

C++ 在Linux上以发布/优化的二进制文件在信号处理程序中打印回溯

C++ 在Linux上以发布/优化的二进制文件在信号处理程序中打印回溯,c++,c,stack-trace,backtrace,signal-handling,C++,C,Stack Trace,Backtrace,Signal Handling,问题是如何用优化的二进制文件以编程方式打印有意义的stacktrace。 例如 我们可以使用backtrace,backtrace\u symbols,abi::\uuuucxa\u demangle打印堆栈跟踪。 但据我所知,我们需要使用编译器标志-g,而不是高于-O1优化标志来构建二进制文件。我可以做到这一点 我期待在发布二进制文件中生成具有适当函数名的回溯跟踪,例如使用-O3标志编译 它可行吗? 我对此做了很多研究,但没有得到任何实质性的结果 更新1: 有没有一种方法可以让我们拥有一个包含

问题是如何用优化的二进制文件以编程方式打印有意义的stacktrace。 例如 我们可以使用
backtrace
backtrace\u symbols
abi::\uuuucxa\u demangle
打印堆栈跟踪。 但据我所知,我们需要使用编译器标志
-g
,而不是高于
-O1
优化标志来构建二进制文件。我可以做到这一点

我期待在发布二进制文件中生成具有适当函数名的回溯跟踪,例如使用
-O3
标志编译

它可行吗? 我对此做了很多研究,但没有得到任何实质性的结果

更新1: 有没有一种方法可以让我们拥有一个包含一些符号的辅助文件,并且可以从优化的二进制进程中引用它来生成堆栈跟踪

在信号处理程序中打印回溯

无论优化级别如何,在信号处理程序中调用
backtrace
1、
backtrace\u符号
1或
abi::\uuucxa\u demangle
都是不安全的。它们不是异步安全函数,如果在信号处理程序中使用,可能会导致程序崩溃、内存损坏或冻结。关于打印,如果您计划使用任何
printf
函数系列,请知道它们在信号处理程序中使用也不安全(至少是POSIX指定的所有函数)

还有一些库/函数承诺信号安全,并且使这成为可能

1根据手册页,只要事先加载了共享的libgcc,就可以使用
backtrace
backtrace\u symbols
有一个更安全的选择
backtrace\u symbols\u fd
,它与libgcc具有相同的警告


有没有一种方法可以让一个包含一些符号的辅助文件

您可以使用
objcopy
从可执行文件中复制调试符号,并使用
strip
从可执行文件中删除调试符号

GDB支持外部符号文件,但我不知道是否/如何在程序中使用它们。我曾经从二进制文件中挖掘符号;这可能也适用于外部符号文件。但据我所知,那个图书馆并不保证信号安全。也就是说,不清楚为什么需要分离;调试符号不会影响性能


只有当进程崩溃时,我才会打印堆栈

在这种情况下,一种可能更好的方法可能是简单地让操作系统生成一个核心转储,并让一个单独的进程监听文件系统事件,一旦创建了一个核心转储,就生成一个回溯跟踪并写入一些日志。无需担心信号安全,无需在生成跟踪时延迟原始进程的重新启动,也无需额外依赖服务器进程



就优化级别而言,无论使用何种方法生成跟踪,您都可以尝试忽略帧指针,并希望达到最佳效果,但通常最好不要使用高于
-O2
的方法进行调试<代码>-Og是理想的,但没有那么快。

只是翻拍而已。我认为使用
-O3
编译可以省略帧指针,从而更难获得堆栈跟踪。gcc对此有一个标志。例如,
-O3-fno省略帧指针
@BiagioFesta谢谢让我试试,它会对性能产生任何影响吗?当然,它不是完全免费的。从技术上讲,省略帧指针使编译器有机会保存一个寄存器。“如果函数不需要堆栈帧指针,-fomit frame pointer选项,则指示编译器不要存储堆栈帧指针。您可以使用此选项来减小代码映像大小。”积极的优化可能会导致函数内联,这使得调用堆栈的一部分似乎丢失。您想要实现的目标不兼容。想象一下基本上任何模板代码,比如。有这么多函数只是为了调用另一个函数。最后,语句的操作可能非常简单,但很可能扩展到10项的深层跟踪。这就是
-O3
通过攻击性内联所防止的。如果您想保留呼叫链的每个链接,请使用
-O2
-Og
。感谢您花时间回答,我知道这一点。要求如下:仅当进程崩溃时,我才打印堆栈。在这种情况下,我可以咬紧牙关,只要我收到信号,我就取消注册信号处理程序,继续打印堆栈跟踪和其他一些诊断细节。我们可以使用写系统调用,但是回溯是我必须使用的东西。所以,这不是100%正确的做法,但可以创造奇迹而没有任何伤害。而且“快”的要求是不可阻挡的。这是一个延迟非常低的服务器。@Yogesh注意到,在信号处理程序中,您不能真正安全地请求符号<代码>\uuucxa\u demangle()使用
malloc()
-家族调用,如果堆损坏,则来自
malloc()
/
free()
等内部的
SIGSEGV
非常常见。如果您尝试在信号处理程序中使用demangle,可能会使进程死锁。以我的经验来看,
backtrace()
没有那么危险。@AndrewHenle谢谢andrew,我知道这个事实。事实上,我浏览了你在评论中发布的同一篇文章。因此,即使我使用eerorika建议的库,我也不想与O3标志妥协。这是我的担忧。@eerorika感谢您的深思熟虑,“一旦创建了一个内核转储,生成一个回溯跟踪并写入一些日志”-但是这个内核将没有必要的信息进行调试,因为二进制文件是一个O3标志编译的。虽然这是一个不错的选择,但事实上我不仅希望转储堆栈跟踪,而且在这个过程中收集了太多其他信息,比如连接、数据库相关信息、注册表中的信息