如何从崩溃中提取调试信息
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”
【讨论】:
以上是关于如何从崩溃中提取调试信息的主要内容,如果未能解决你的问题,请参考以下文章