【发布时间】:2009-01-15 12:34:49
【问题描述】:
我现在正在调试一个使用许多不同线程的程序。
有一个不时抛出的异常。问题是没有办法知道是什么线程导致了问题...
有谁知道抛出异常后获取堆栈跟踪的简单方法?我想过简单地编写一个调试消息,但这将是一个巨大的:-) 我想有比这个更好的技术......
我正在使用 Visual Studio 2008 - 本机 C++ 项目....
【问题讨论】:
标签: c++ visual-studio-2008 debugging
我现在正在调试一个使用许多不同线程的程序。
有一个不时抛出的异常。问题是没有办法知道是什么线程导致了问题...
有谁知道抛出异常后获取堆栈跟踪的简单方法?我想过简单地编写一个调试消息,但这将是一个巨大的:-) 我想有比这个更好的技术......
我正在使用 Visual Studio 2008 - 本机 C++ 项目....
【问题讨论】:
标签: c++ visual-studio-2008 debugging
除非我弄错了,否则您需要知道哪个线程触发了异常才能使用 Visual Studio 调试器的调用堆栈视图,这显然是您目前所处的 catch-22 情况。
我会尝试的一件事是查看在抛出异常时是否可以让调试器中断(使用“调试”>“异常”)。您必须显式启用此功能,但如果您知道抛出什么类型的异常,这可能会让您知道它是在哪里抛出的。
除此之外,在异常的构造函数中放置一个断点(如果它是您自己的)也应该允许您确定它是从哪里触发的。
如果这些方法对您不起作用,我会按照您的建议查看调试消息。
【讨论】:
这对于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 的 Debugging Applications for Microsoft .Net and Microsoft Windows。这是一本关于调试的好书,即使它是几年前的。你可以以大约 20.00 美元的价格从亚马逊购买它。
【讨论】:
这个库看起来很符合要求:
http://www.codeproject.com/KB/threads/StackWalker.aspx
Jochen Kalmbach 看起来在封装低级 dbghelp.dll 接口的复杂性方面做得非常彻底。
【讨论】:
您可以在异常构造函数(即您将要抛出的对象)中放置一个断点。
这当然假设您有一个共同的异常层次结构。
【讨论】:
您能否使用“异常”对话框(Debug | Exceptions... 菜单项,或Ctrl+Alt+E 或Ctrl+D E,取决于您的键盘绑定)在抛出特定异常时将正在运行的代码中断为调试?
【讨论】:
如果您无法让调试器捕捉正在发生的事情...并且您无法打印堆栈跟踪和线程...
我的猜测是,您将不得不付出一些努力工作。从了解系统开始。了解系统后,尝试将系统分成两半。有效的部分和无效的部分。然后继续尝试这样做,直到您深入解决问题。
当您深入研究时,尝试使用 try/catch 包围可疑代码...希望您可以使用调试器停止执行并查看发生了什么。
【讨论】:
异常本身具有 StackTrace... 属性,因此您只需返回 ToString( )。
但我相信您的问题更像是如何捕获随机异常。如果是这样,我所做的就是将所有主要代码放在 try/catch 中。我真的不确定是否在其他线程中引发了异常,这种技术是否有效。
您还应该捕获不是从 Exception 派生的 ApplicationExeption。
【讨论】: