【问题标题】:Exception backtrace from a core dump来自核心转储的异常回溯
【发布时间】:2016-06-29 23:17:23
【问题描述】:

我的 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 对核心转储进行事后调试会话,则堆栈跟踪位于 HandleHttpRequestcreate_dump() 行。

如果我有一个catch 块的核心转储,有没有办法查看引发异常的堆栈跟踪?

或者有没有更好的方法来实现我的目标(自动将未捕获的异常转换为 HTTP 500 错误代码,同时为它们捕获完整的调试信息)?

【问题讨论】:

  • 您真的需要核心转储,还是可以运行自定义展开器来收集回溯?这应该是用于调试的大量信息。
  • @KerrekSB - 核心转储是理想的,但自定义展开器肯定比没有好。您是否有任何关于编写可以从 catch 块访问异常堆栈跟踪的信息的起点? (我尝试了简短的 Google 搜索,但不清楚如何继续。)
  • 如果您能够并且愿意更改抛出的异常类型,那么我会研究 boost 异常,请参阅 stackoverflow.com/questions/691719/…
  • 还要记住,堆栈跟踪可能在优化的构建中因为帧指针遗漏而无用
  • 我想到了像 libunwind 这样的东西......

标签: c++ linux exception gdb core


【解决方案1】:

没有可移植的方式来实现您想要的。

不可移植的方法是从libstdc++.so插入extern "C" void __cxa_throw(void *, void *, void *)函数,并在调用libstdc++.so的原始函数之前从中转储你的核心。

有关如何执行此类插入的更多信息是here

注意事项:

  1. 仅当您链接到 libstdc++.so(无论如何您通常都应该这样做)而不是 libstdc++.a 时,这才有效。
  2. 您不必使用LD_PRELOAD,您可以将interposer 放入主可执行文件中。
  3. 使用fork() 转储内核的重量非常重,并且对于多线程程序来说效果不佳(嗯,根本不工作)。您最好使用 Google ELF coredumper

【讨论】:

    【解决方案2】:

    自去年年底以来,我一直在开发一个可以在运行时附加到 C++ 程序的库,最近开源了它here。它适用于 Linux。

    巧合的是,它的作用主要由 Employed Russian 解释;它插入 throw 和 catch 语句并从那里打印回溯。无需重新编译或链接目标应用程序。只需在运行应用程序时使用 LD_PRELOAD 加载它即可。

    它也是可扩展的。您可以使用少量插入代码将回溯打印添加到 C/C++ 函数。不过,您需要知道自己在做什么。

    它不会破坏 C++ 函数名称或调用 addr2line,因为这会增加目标应用程序的额外开销并可能影响执行时间。毕竟程序退出后可以手动使用c++filt或者addr2line。

    我编写这个库是为了解决一个棘手的核心转储问题,其中 SEGFAULT 涉及到 catch-all 块。只出现在客户的实验室环境中,挂上gdb后问题就消失了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-17
      • 2011-10-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多