DebugBreak在非托管和混合(非托管+托管)应用程序之间有所不同?
采用以下简单的源代码(将其命名为test.cpp):
#include <windows.h> voidmain()
{
DebugBreak();
}
Visual C++中的异常处理
简介
本文介绍了在Windows中运行的VisualC++程序中处理异常和错误的标准技术。
异常(或严重错误或崩溃)通常意味着程序停止正常工作,需要停止执行。例如,由于程序访问无效的内存地址(如空指针)、无法分配内存缓冲区(内存不足)、C运行时库(CRT)检测到错误并请求程序终止等,可能会发生异常。
C++程序可以处理几种例外:SEH异常,通过操作系统的结构化异常处理机制产生,由C运行库产生的CRT错误,最后是信号。每种错误类型都需要安装异常处理程序函数,该函数将截获异常并执行一些错误恢复操作。
如果应用程序有多个执行线程,事情可能会更复杂。有些异常处理程序可用于整个进程,但有些仅用于当前线程。所以必须在每个线程中安装异常处理程序。
应用程序中的每个模块(EXE或DLL)都链接到CRT库(静态或动态)。异常处理技术在很大程度上依赖于CRT链接类型。
错误类型的多样性、在多线程程序中处理异常的差异,以及异常处理对CRT链接的依赖性,需要大量的工作来处理应用程序允许处理的所有异常。本文旨在帮助您更好地理解异常处理机制,并在C++应用程序中有效地使用异常处理。
本文附带了一个小型控制台演示应用程序ExceptionHandler。演示程序可以引发和捕获不同类型的异常,并生成一个崩溃小型转储文件,允许查看发生异常的代码行。
背景
不久前,我需要一种方法来拦截我的一个开源项目CrashRpt的异常,CrashRpt是一个用于Windows应用程序的崩溃报告库。CrashRpt库处理应用程序中发生的异常,收集有关错误的技术信息(如崩溃小型转储、错误日志、桌面截图),并提供用户通过Internet发送错误报告(图1)。
图1-CrashRpt库的错误报告窗口和错误报告详细信息对话框
也许您已经看到Windows错误报告窗口(图2)突然出现在您的桌面上,CrashRpt库也做了同样的事情,只是它将错误报告发送到您自己的web服务器,而不是Microsoft的服务器。
浏览MSDN时,我得到了SetUnhandledExceptionFilter()函数,该函数用于处理访问冲突。但很快我发现我的应用程序中的一些异常不知怎么地没有被处理,而Watson博士的窗口仍然出现,而不是崩溃的窗口。我又浏览了MSDN,发现许多其他CRT提供的函数可以用来处理CRT错误。下面是此类函数的一些示例:set_terminate(),_set_invalid_parameter_handler(),_set_purecall_handler()。然后我发现有些CRT处理程序只对当前线程有效,但有些处理程序对进程的所有线程都有效。继续我的研究,我发现开发人员必须理解许多细微差别才能有效地使用异常处理。我的研究结果如下。
关于例外的几句话
如您所知,异常或严重错误通常意味着程序停止正常工作,需要停止其执行。例如,可能由于以下原因发生异常:
- 程序访问无效的内存地址(例如空指针)
- 无限递归导致堆栈溢出
- 大数据块被写入一个小缓冲区
- C++类的纯虚方法称为C++类。
- 无法分配内存缓冲区(内存不足)
- 无效参数传递给C++系统函数
- C运行时库检测错误并请求程序终止
有两种例外,它们有不同的性质:SEH异常(结构化异常处理、SEH)和类型化C++异常。操作系统提供结构化异常处理机制(这意味着所有Windows应用程序都可以引发和处理SEH异常)。SEH例外最初是为C语言设计的,但它们也可以用在C++中。SEH异常是使用_try{}_except(){}构造处理的。程序的main()函数由这样的构造保护,因此默认情况下,所有未处理的SEH异常都会被捕获并调用Dr.Watson。SEH异常是VisualC++编译器特有的。如果编写可移植代码,则应使用#ifdef/#endif保护结构化异常处理构造。
下面是一个代码示例:
int* p = NULL; //pointer to NULL __try
{//Guarded code *p = 13; //causes an access violation exception }
__except(EXCEPTION_EXECUTE_HANDLER)//Here is exception filter expression {//Here is exception handler//Terminate program ExitProcess(1);
}
在WinDBG中高亮你输入的命令
在WinDBG的Command窗口中, 默认情况下, 你输入的命令很容易和该命令以及附近命令的输出混杂在一起. 在寻找之前命令的结果的时候, 眼睛看起来会很累.
WinDBG提供了一个选项, 通过这个选项, 你可以把命令输入与输出的颜色进行设置.
选项名:
- Prompt level command window text
- Prompt level command windows text background
结果如下:
windbg使用的一些技巧
怎样打印某函数调用关系
命令 | 功能 | 适用范围 |
---|---|---|
uf /c /D 地址 | 打印当前函数对其他函数的调用 | 用户态/内核态 |
# 函数名 起始地址 l长度 | 打印在某段地址范围内代码对该函数的引用 | 内核态/用户态 |
分析一个dump的一般步骤
- 看清楚是何种异常导致的崩溃.
- 对齐symbol, 找到发生崩溃的函数名字, 以及对应的汇编代码和源代码.
- 列出callstack
- 检查callstack是否合理
- 检查发生崩溃的函数是否得到了正确的参数.
- 检查发生崩溃的函数使用的数据是否正确.
- 结合上面的信息, 构思来龙去脉, 然后用资料来证明, 或者反驳自己的猜想.
- 通过进一步的操作来获取更有意义的资料. 比如激活pageheap后, 重新抓取dump, 或者干脆进行Live debug