我的 C++ 程序有一个嵌入式 Web 服务器(基于 CivetWeb)。如果在处理 HTTP 请求时发生异常,我不想崩溃,但我也想触发核心转储以供将来调试。
这是我目前的尝试。
// See http://stackoverflow.com/a/131539/25507
void create_dump(void)
{
if(!fork()) {
abort() || (*((void*)0) = 42);
}
}
void HandleHttpRequest(mg_conn *conn)
{
try {
// Lots of application-specific logic
} catch (std::exception& e) {
create_dump();
WriteHttp500(conn);
}
}
这基本上是有效的。 但是,如果我随后启动 gdb 使用核心转储进行事后调试会话,则堆栈跟踪位于
create_dump()
的 HandleHttpRequest
行。
如果我有
catch
块的核心转储,有什么方法可以查看引发异常的堆栈跟踪吗?
或者是否有更好的方法来实现我的目标(自动将未捕获的异常转换为 HTTP 500 错误代码,同时还捕获它们的完整调试信息)?
没有可移植的方法来实现你想要的。
不可移植的方法是插入
extern "C" void __cxa_throw(void *, void *, void *)
中的 libstdc++.so
函数,并在调用 libstdc++.so
中的原始函数之前从中转储核心。
有关如何执行此类插入的更多信息位于此处。
备注:
libstdc++.so
(通常您应该这样做)而不是 libstdc++.a
时,这才有效。LD_PRELOAD
,您可以将插入器放入主可执行文件中。fork()
转储核心的重量非常大,并且对于多线程程序效果不佳(好吧,根本不起作用)。您最好使用 Google ELF coredumper。
它也是可扩展的。您可以使用少量插入代码向 C/C++ 函数添加回溯打印。不过,您需要知道自己在做什么。
它不会分解 C++ 函数名称或调用 addr2line,因为这会增加目标应用程序的额外开销,并可能影响执行时间。毕竟,您可以在程序退出后手动使用 c++filt 或 addr2line 。
我编写这个库是为了解决一个棘手的核心转储问题,其中 SEGFAULT 涉及包罗万象的块。仅发生在客户的实验室环境中,附加gdb后问题消失。