抛出异常时获取堆栈跟踪

问题描述 投票:0回答:7

我现在正在调试一个使用许多不同线程的程序。

时不时会抛出异常。问题是没有办法知道哪个线程导致了问题......

有没有一种简单的方法可以在抛出异常后获取堆栈跟踪?

我想过简单地编写一条调试消息,但这将是一个巨大的:-)我想有比这个更好的技术......

我正在使用 Visual Studio 2008 - 本机 C++ 项目....

c++ visual-studio-2008 debugging
7个回答
5
投票

除非我大错特错,否则您需要知道哪个线程触发了异常,才能使用 Visual Studio 调试器的调用堆栈视图,这显然是您目前所处的 catch-22 情况。

我要尝试的一件事是看看是否可以让调试器在引发异常时中断(使用“调试”>“异常”)。您必须显式启用此功能,但如果您知道抛出什么类型的异常,这可能会让您找出抛出异常的位置。

除此之外,在异常的构造函数中放置一个断点(如果它是你自己的)也应该允许你找出它是从哪里触发的。

如果这些方法对您不起作用,我会按照您的建议查看调试消息。


3
投票

使用 Microsoft 免费提供的 WinDBG,这非常简单。如果您还没有安装适合您的 Windows 版本的符号,您还需要安装它们。

只需将 WinDBG 设置为故障转储工具即可。我使用此注册表设置:(您可能希望编辑路径

样品:
CrashDumpSettings.reg

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug]
"Auto"="1"
"Debugger"="C:\\progra~1\\debugg~1\\cdb.exe -p %ld -e %ld -g -y SRV*c:\\mss*http://msdl.microsoft.com/download/symbols -c \"$<c:\\Dumps\\CrashDump.cdbscript\""

您的

CrashDump.cdbscript
可能如下所示:(这基本上是我使用的...根据需要编辑路径。

样品:
CrashDump.cdbscript

.sympath+ c:\windows\symbols;c:\some\path\to\symbols\for\your\project

as /c CrashFirstModule .printf "%mu", @@c++((*(ntdll!_LDR_DATA_TABLE_ENTRY**)&@$peb->Ldr->InLoadOrderModuleList.Flink)->BaseDllName.Buffer) 

.logopen /t c:\dumps\${CrashFirstModule}_process.log
.kframes 100
!analyze -v
~*kv
lmv
.logclose

.dump /mhi /u /b c:\dumps\${CrashFirstModule}_mini.cab
.dump /mhia /u /b c:\dumps\${CrashFirstModule}_full.cab

q

您会得到一个不错的日志文件和一些转储,您可以使用它们来查看 WinDBG 发生异常时进程的状态。日志文件将对发生的错误进行分析,包括导致错误的代码行。它还会列出每个线程的调用堆栈。在调用堆栈列表中,编号旁边带有

#
的线程是导致异常的线程。这些文件中有大量信息。我建议选择 John Robbins 撰写的调试 Microsoft .Net 和 Microsoft Windows 的应用程序。这是一本关于调试的好书,即使它是几年前的书。您可以从亚马逊购买,价格约为 20.00 美元。


1
投票

这个库看起来很符合要求:

http://www.codeproject.com/KB/threads/StackWalker.aspx

Jochen Kalmbach 看起来在封装低级 dbghelp.dll 接口的复杂性方面做了非常彻底的工作。


1
投票

您可以在异常构造函数中放置一个断点(即您要抛出的对象)。

这当然假设您有一个通用的异常层次结构。


0
投票

如果您无法让调试器捕获正在发生的事情...并且您无法打印堆栈跟踪和线程...

我的猜测是,你必须付出一些努力和努力。从了解系统开始。一旦了解了系统,请尝试将系统分成两半。有效的部分和无效的部分。然后继续尝试这样做,直到深入解决问题。

当您向下钻取足够远时,尝试使用 try/catch 包围可疑代码...希望您可以使用调试器停止执行并查看发生了什么。


0
投票

您可以使用“例外”对话框(

Debug
|
Exceptions...
菜单项,或 Ctrl + Alt + ECtrl + DE,具体取决于您的键盘绑定)在抛出特定异常时将正在运行的代码分解为调试。


-2
投票

异常本身具有 StackTrace 属性...所以你只需要返回 ToString( ) 即可。

但我相信你的问题更像是如何捕获随机异常。如果是这样,我所做的就是将所有主要代码放在 try/catch 中。我真的不太确定异常是否在其他线程中抛出,这种技术是否有效。

您还应该捕获一个不是从 Exception 派生的 ApplicationException。

© www.soinside.com 2019 - 2024. All rights reserved.