如何从崩溃中提取调试信息

Posted

技术标签:

【中文标题】如何从崩溃中提取调试信息【英文标题】:How to extract debugging information from a crash 【发布时间】:2010-10-25 10:29:15 【问题描述】:

如果我的 C++ 应用程序在 Windows 上崩溃,我想将有用的调试信息发送到我们的服务器。

在 Linux 上,我会使用 GNU backtrace() 函数 - 是否有适用于 Windows 的等效函数?

有没有办法在程序崩溃后提取有用的调试信息?还是只在流程内部?

(类似“测试你的应用程序以使其不会崩溃”的建议没有帮助!-所有非平凡的程序都会有错误)

【问题讨论】:

【参考方案1】:

Stackwalk64 函数可用于在 Windows 上捕捉堆栈跟踪。

如果您打算使用此功能,则应确保在禁用 FPO 的情况下编译您的代码 - 如果没有符号,StackWalk64 将无法正确遍历 FPO 的帧。

您可以通过调用 SetUnhandledExceptionFilter 来通过*** __try/__except 块让一些代码在崩溃时运行在进程中。这有点不可靠,因为它要求您在崩溃的进程中运行代码。 或者,您可以只使用内置的 Windows 错误报告来收集崩溃数据。这更可靠,因为它不需要您添加在受损、崩溃的进程中运行的代码。唯一的成本是获得代码签名证书,因为您必须向服务提交签名的二进制文件。 https://sysdev.microsoft.com/en-US/Hardware/signup/ 有更多详情。

【讨论】:

您的二进制文件无需签名即可检索 WER 崩溃数据。相反,您运行一个特殊的工具来扫描您的二进制文件并收集文件名、时间戳、CRC 等。该工具将此信息保存到您上传到 Winqual 的 XML 文件中。 签名二进制是为了建立身份。来自microsoft.com/whdc/winlogo/maintain/StartWER.mspx:为了保护公司免受假冒并确保错误报告发送给正确公司的代表,Winqual 网站要求您的公司拥有有效的 VeriSign ID。【参考方案2】:

如果您想推出自己的代码,可以使用 Windows API 调用 MiniDumpWriteDump。 Windows XP 和 Vit 都会自动执行此过程,您可以在 https://winqual.microsoft.com 注册以访问错误报告。

还可以查看http://kb.mozillazine.org/Breakpad 和http://www.codeproject.com/KB/debug/crash_report.aspx 了解其他解决方案。

【讨论】:

【参考方案3】:

这个网站提供了一个非常详细的关于在 C++ 异常后在 Win32 上检索堆栈的概述:

http://www.eptacom.net/pubblicazioni/pub_eng/except.html

当然,这只会在进程内部起作用,所以如果进程终止或崩溃到它在代码运行之前终止的地步,它就不会起作用。

【讨论】:

【参考方案4】:

生成一个小型转储文件。然后,您可以在 windbg 或 Visual Studio 中加载它并检查发生崩溃的整个堆栈。

Here's 一个开始阅读的好地方。

【讨论】:

不幸的是 MiniDumpWriteDump 需要某些特权,我不能假设我的用户有这些【参考方案5】:

将当前堆栈帧地址转储到日志文件中非常简单。您所要做的就是在程序错误(即 Windows 中的中断处理程序)或断言时调用这样的函数。这也可以在发布的版本中完成。然后可以将日志文件与映射文件匹配,从而生成带有函数名称的调用堆栈。

几年前我发表了一篇关于此的文章。

见http://www.ddj.com/architect/185300443

【讨论】:

【参考方案6】:

让我描述一下我如何处理我的 C++/WTL 应用程序中的崩溃。

首先,在主函数中,我调用_set_se_translator,并传入一个将引发C++ 异常而不是使用结构化Windows 异常的函数。这个函数得到一个错误代码,你可以通过FormatMessage得到一个Windows错误信息,以及一个PEXCEPTION_POINTERS参数,你可以用它来写一个minidump (code here)。您还可以检查某些“崩溃”错误的异常代码,您应该避免这些错误,例如 EXCEPTION_NONCONTINUABLE_EXCEPTION 或 EXCEPTION_STACK_OVERFLOW :)(如果它是可恢复的,我会提示用户通过电子邮件向我发送此 minidump 文件。)

minidump 文件本身可以像普通项目一样在 Visual Studio 中打开,如果您为可执行文件创建了 .pdb 文件,您可以运行该项目,它会跳转到崩溃的确切位置,连同调用堆栈和寄存器,可以从调试器中检查。

【讨论】:

【参考方案7】:

如果您想获取运行时崩溃的调用堆栈(以及其他有用的信息),甚至在现场发布版本中,那么您需要设置 Dr Watson(运行 DrWtsn32.exe)。如果您选中“生成故障转储”选项,当应用崩溃时,它会向指定的路径(称为 user.dmp)写入一个小型转储文件。

您可以使用它,将它与您在构建服务器时创建的符号结合起来(在您的编译器/链接器中设置它以生成 pdb 文件 - 将这些安全地放在家里,您可以使用它们来匹配转储,以便它们可以工作找出崩溃发生的源头)

获取windbg,打开它并使用菜单选项“加载故障转储”。加载完所有内容后,您可以键入“~#kp”来获取每个线程的调用堆栈(或单击当前线程顶部的按钮)。

网上有很多关于如何做到这一点的好文章,This one 是我最喜欢的,你会想read this 了解如何帮助自己真正轻松地管理符号。

【讨论】:

【参考方案8】:

你必须在你的应用程序中设置一个转储生成框架,here 是你可以做到的。

然后,您可以将转储文件上传到服务器,以便使用 windbg 等转储分析器进行进一步分析。

【讨论】:

【参考方案9】:

您可能希望使用 adplus 来捕获崩溃调用堆栈。

您可以下载并安装适用于 Windows 的调试工具。

这里提到了adplus的用法: Adplus usage

这会创建完整的崩溃或挂起转储。一旦你有了转储,Windbg 就会来救援。映射正确的 pdb 和符号,您就可以开始分析转储了。首先使用命令“!analyze -v”

【讨论】:

以上是关于如何从崩溃中提取调试信息的主要内容,如果未能解决你的问题,请参考以下文章

如何调试从后台返回时发生的崩溃

使用 rebase.exe 从 msys/mingw gcc 构建的 dll 中提取调试信息?

如何调试仅在发布版本中发生的崩溃[关闭]

iOS崩溃调试的使用和技巧总结

iOS崩溃调试的使用和技巧总结

如何调试导致python崩溃的python脚本