【问题标题】:Debugging a release build client-side crash: what are the possible ways of geting call stack?调试发布版本客户端崩溃:获取调用堆栈的可能方法是什么?
【发布时间】:2011-11-22 08:56:40
【问题描述】:

我有一个本机 C++ 应用程序在办公室中运行良好(我们当然会进行测试),但客户会遇到许多不同的崩溃。我知道可以使用 windbg(它是一个跨平台应用程序 - Win、Linux 和 Mac,但在所有平台上都会发生崩溃,因此调试任何一个都是有用的),但操作客户端的机器(例如,安装和注册 windbg)不是选项。我想知道是否还有其他方法可以获取调用堆栈。是否有任何工具可以检测二进制文件以提供此类信息?

P。 S. 我想我可以将 .pdb 文件与二进制文件一起发送,但我不想这样做。

【问题讨论】:

  • 第一步是在应用程序崩溃时向客户端询问详细信息,即场景、输入和内容。客户端会崩溃应用程序,而您曾认为(这是一个很大的错误)是不可崩溃的。
  • 我从没想过它不会崩溃,我根本无法重现崩溃。

标签: c++ debugging crash


【解决方案1】:

在 Windows 上,您可以在客户端计算机上配置 Dr.Watson,这样如果您的应用程序崩溃,它将创建所谓的“小型转储文件”,然后可以由调试器使用适当的 PDB 打开。

您还可以向您的应用程序添加一个未处理的异常过滤器并自己生成小型转储,以防出现不可恢复的错误。

编辑:

如果您想在(未处理的)异常情况下生成转储文件 - 不要在 C++ catch (...) 块内执行此操作,因为它是在展开发生后调用的,并且原始调用堆栈不可用。

为了捕获和转储调用堆栈,您应该在堆栈展开之前转储它。像这样:

int HandleMyException(EXCEPTION_POINTERS* pExc)
{
    // dump it
    MiniDumpWrite(...);

    // Unless you decide to terminate your process, return EXCEPTION_EXECUTE_HANDLER, so that the execution
    // continues normally after the __except block.
    return EXCEPTION_EXECUTE_HANDLER;
}

__try
{
    // Do something...
}
__except (/* stack still not unwound */ HandleMyException(GetExceptionInformation()))
{
    // unwind already took place here, nothing to dump
}

【讨论】:

  • 感谢您的建议,这样做了,但遇到了问题。请参阅我对 Luchian Grigore 的回答的评论。
  • 您必须配置调试器以使用故障转储 PDB 文件,前者包含所有符号(函数名称等)。注意:PDB 文件应该来自您的 EXE 的同一构建会话。
  • 我明白这一点。崩溃转储像魅力一样工作,但我不知道如何获取真正的堆栈跟踪,因为我从 catch (...)(或 `__except())调用 MiniDumpWriteDump,而完整的堆栈跟踪不可用。
  • 非常感谢!它在调试构建中完美运行。然而,在发布时,我只得到 5 个条目的调用堆栈。第一个是神秘记录 054f0000(),第二个是 dbghelp.dll!Win32LiveSystemProvider::OpenMapping()。我检查了项目设置 - pdb 生成良好。可能是什么原因?
  • 不看代码就很难准确判断出什么问题。值得注意的是,如果您有无效的内存写入错误,则故障转储可能并不总是可读的。例如,如果堆栈内存被严重覆盖,您将看不到有效的调用堆栈。除此之外,我只能猜测它可能与 PDB 文件的某些不一致(例如未配置发布 PDB 文件的调试器路径等)有关。还要考虑到,在发布版本中,代码可能会被积极优化,因此您会在调用堆栈中看到更少的函数
【解决方案2】:

对于 Windows,您可以使用 structured exception handling。 windows api 允许您在程序崩溃时生成堆栈跟踪。将生成一个dmp 文件。您可以检索该文件并在调试环境中进行调试。无需发送调试二进制文件或pdb 文件。

对于跨平台,您可以使用google breakpad。该工具会生成跟踪,并可以自动发送它们或随后发送用户生成的报告。

【讨论】:

  • 很好的建议(我的意思是 SEH),谢谢!但是有一个问题:我试过在异常处理程序中使用MiniDumpWriteDump,发现堆栈中不存在导致错误的函数调用链,我的主要愿望是得到一个调用堆栈。跨度>
  • @VioletGiraffe 它可能还在那里,但在不同的线程上。你试过检查每个线程的调用堆栈吗?
  • @VioletGiraffe 你怎么知道的?您实际上是在监视线程还是您的程序只有一个线程。仅仅因为你只启动一个线程,并不意味着 SEH 或其他东西不能产生新线程。
  • 有道理。我的意思是说只有一个线程会崩溃。我检查了所有其他线程。据我了解,调用堆栈在执行流到达异常处理程序时根本不可用(展开?我不太了解异常)。
  • @VioletGiraffe 你在开发机器上试过这个吗?在您实际调试转储文件的机器上,您需要拥有 pdb 才能真正看到任何内容。 dmp 文件说加载了哪些模块?你的模块在吗?他们有加载 pdb 的吗?在此处发布所有线程的所有调用堆栈或上传 dmp 文件将很有帮助。我可以看看它,也许它有帮助。
猜你喜欢
  • 2011-06-26
  • 2011-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-05
  • 1970-01-01
  • 1970-01-01
  • 2010-09-08
相关资源
最近更新 更多