Debugging Tools for Windows

控制异常和事件

在用户模式和内核模式应用程序中有很多方法用于截获和处理异常。激活的调试器、即时调试器或内部的错误处理程序都是异常处理的通常方法。

关于这些错误处理方式优先等级的更多信息,查看启用即时调试

当Microsoft Windows操作系统允许由调试器来处理异常时,产生异常的程序会中断到调试器。即应用程序停止运行而调试器被激活。之后,调试器可以用各种方式处理掉异常或者分析情况。最后,调试器可以结束进程或恢复它的执行。

如果调试器跳过异常并继续程序执行,操作系统如同没有附加调试器一样会查找其他异常处理器。如果异常被处理掉,则程序继续运行。但是,如果异常仍然没有处理,系统会给予调试器第二次处理机会。

使用调试器分析异常

当异常或事件中断到调试器时,可以用调试器检查被执行的代码或者查看进程内存。通过修改某些值或者跳转到程序的另一个位置,可能可以解决掉这个异常。

使用gh (Go with Exception Handled)gn (Go with Exception Not Handled)命令恢复程序执行。

如果在调试器的第二次异常处理机会时使用gn命令,则程序被终止。

内核模式异常

内核模式代码产生的异常比用户模式异常要更加严重。如果内核模式异常没有被处理,则会产生bug check 并且系统停止。

和用户模式异常一样,如果有内核调试器附加到系统上,在错误检查屏幕(即蓝屏)产生前,会先通知调试器。如果没有附加调试器,则直接蓝屏。这种情况下,系统可能会创建崩溃转储文件

从调试器控制异常和事件

可以设置调试器处理异常和事件的方式。

调试器可以为每个异常或事件设置中断方式

调试器也可以为每个异常和事件设置处理方式。调试器可以将事件当作已处理异常或未处理异常来对待。(当然,并不是实际出错的事件是不需要处理的。)

可以用如下方法来控制中断方式和处理方式:

SX*命令、-x* 命令行选项和sx* Tools.ini 关键字用于设置特定事件的中断方式。添加-h 选项来设置事件的处理方式。

有4个特殊的事件代码(cc, hc, bpec ssec)只能指定处理方式。

使用.lastevent (Display Last Event)命令显示最近一次异常或事件。

控制中断方式

为异常或事件设置中断方式可以使用以下选项。

命令 方式 说明
SXE

-xe
Break

(Enabled)

当异常发生时,目标立即中断到调试器。该中断在其他任何错误处理器被调用之前。这种方法称为第一次异常处理
SXD

-xd
Second chance break

(Disabled)

调试器不会在第一次异常处理机会时中断(虽然会显示一条信息)。如果其他错误处理其不能处理异常,则目标停止执行并中断到调试器。这种方法称为第二次异常处理
SXN

-xn
Output

(Notify)

当异常产生时,目标应用程序不会中断到调试器。但是,调试器中会显示一条有关的信息。
SXI

-xi
Ignore 异常发生时,目标程序不会中断带调试器,并且不会显示信息。

如果某个异常预先没有使用SX* 设置过,则目标进程在第二次机会时中断到调试器。所有事件的默认方式在下面的”事件定义和默认设置”主题中列出。

使用WinDbg图形界面设置中断方式,可以在Debug菜单打开Event Filters,并在Event Filters 对话框中点击要设置的事件,并选择EnabledDisabledOutputIgnore

控制处理方式

除非使用gh (Go with Exception Handled)命令,否则所有事件都不会被处理。

所有异常都不会被处理,除非使用了sx*命令和-h选项。

另外,SX* 选项可以配置非法句柄、STATUS_BREAKPOINT 中断指令和单步异常的处理方式。 (这个配置和他们的中断配置是分开的。)配置中断方式时,这些事件分别名为 chbpesse。在配置异常处理方式时,他们分别名为hcbpecssec (完整的事件列表,查看下面的"事件定义和默认设置"节。)A

CTRL+C 事件(cc)可以配置处理方式,但是没有中断方式。如果程序接收到了CTRL+C事件,总是会中断到调试器。

当为cchcbpec ssec 事件使用SX*命令,或对某个异常将SX* -h 选项一起使用时,会遇到下面一些情况。

命令 方式 说明
SXE Handled 重新开始执行时事件已被处理。
SXD,
SXN,
SXI
Not Handled 重新开始执行时事件未被处理。

使用WinDbg图形界面设置中断方式,可以在Debug菜单打开Event Filters ,并在Event Filters 对话框中点击要设置的事件,并选择HandledNot Handled

自动命令

调试器允许设置一些命令用于当事件或异常中断到调试器时自动执行。可以分别为第一次异常处理和第二次异常处理设置一个命令字符串。使用SX*命令或Debug | Event Filters菜单命令设置。每个命令字符串可以包含用分号隔开的数条命令。

不管中断方式如何,这些命令都会被执行。换句话说,即使中断方式为"Ignore",命令仍然会被执行。如果中断方式为”第二次处理机会”,则第一次处理机会的命令在异常第一次发生时,调用任何其他处理程序前被执行。命令字符串可以以运行命令结尾,如g (Go), gh (Go with Exception Handled)gn (Go with Exception Not Handled)

事件定义和默认设置

可以修改以下这些异常的中断方式和处理方式。下表同时指明了他们的默认中断方式。

以下异常的默认处理方式都是"Not Handled"。修改这些方式时要特别小心。如果将方式修改为"Handled",则所有第一次异常和第二次异常都被认为是已处理,原有的所有异常处理函数都会被跳过。

事件代码 含义 默认中断方式
asrt 断言错误(Assertion failure) Break
av 访问违例(Access violation) Break
dm 数据未对齐(Data misaligned) Break
dz 除零(Divide by zero) Break
eh C++ EH异常(C++ EH exception) Second-chance break
gp 页保护违例(Guard page violation) Break
ii 非法指令(Illegal instruction) Second-chance break
iov 整数溢出(Integer overflow) Break
ip 页面I/O错误(In-page I/O error) Break
isc 非法系统调用(Invalid system call) Break
lsq 非法加锁次序(Invalid lock sequence) Break
sbo 栈缓冲区溢出(Stack buffer overflow) Break
sov 栈溢出(Stack overflow) Break
wkd 唤醒调试器(Wake debugger) Break
aph 应用程序挂起(Application hang)

这个异常在Windows操作系统结束停止相应的进程时触发(即挂起)。

Break
3c 子程序终止(Child application termination) Second-chance break
ch
hc
非法句柄(Invalid handle) Break
Number 所有编号的异常(Any numbered exception) Second-chance break

注意 可以使用ah (Assertion Handling)命令覆盖指定地址的asrt 中断方式。chhc 事件是同一个异常。控制中断方式时,使用sx* ch;控制异常处理方式时,使用sx* hc

可以修改以下这些异常的中断方式和处理方式。下表同时指明了他们的默认中断方式。

以下异常的默认处理方式都是"Handled"。由于这些异常是用来和调试器通信的,所以一般不能把它们设置为"Not Handled",否则调试器会跳过这些异常并由其他异常处理器来处理。

应用程序可以使用DBG_COMMAND_EXCEPTION (dbce) 来和调试器通信。这个异常类似断点,但是可以使用SX*命令来指定该异常发生时的对待方式。

事件代码 含义 默认中断方式
dbce 专用调试器命令异常(Special debugger command exception) 跳过(Ignore)
vcpp 专用Virtual C++异常(Special Visual C++ exception) Ignore
wos WOW64单步异常(WOW64 single-step exception) Break
wob WOW64断点异常(WOW64 breakpoint exception) Break
sse
ssec
单步异常(Single-step exception) Break
bpe
bpec
断点异常(Breakpoint exception) Break
cce
cc
CTRL+C CTRL+BREAK

当目标程序是控制台程序并输入了CTRL+C或CTRL+BREAK。

Break

注意 上表中最后三个异常有两个不同的事件代码。控制中断方式时,使用 sse, bpe, 和cce。控制异常处理方式时,使用ssec, bpeccc

可以修改下面这些事件的中断方式。由于他们不是异常,所以和异常处理方式无关。

事件代码 含义 默认中断方式
ser 系统错误(System error) Ignore
cpr[:Process] 创建进程(Process creation)

当通过CDB的-o 命令行选项或 WinDbg .childdbg (Debug Child Processes) 命令启用子进程调试时,该事件才可控制。

进程名可以包含一个可选的文件扩展名和星号(*)或问号(?)作为通配符。调试器只保存最近一次的cpr设置。支持对不同进程进行分开设置。在cpr 和 Process 之间需要有一个冒号或者空格。

如果省略Process ,则该设置应用于所有创建出来的子进程。

Ignore
epr[:Process] 进程退出(Process exit)

当通过CDB的-o 命令行选项或 WinDbg.childdbg (Debug Child Processes) 命令启用子进程调试时,该事件才可控制。

进程名可以包含一个可选的文件扩展名和星号(*)或问号(?)作为通配符。调试器只保存最近一次的cepr 设置。支持对不同进程进行分开设置。在cepr Process 之间需要有一个冒号或者空格。如果省略Process ,则该设置应用于所有子进程退出的事件。

Ignore
ct 线程创建(Thread creation) Ignore
et 线程退出(Thread exit) Ignore
ld[:Module] 加载模块(Load module)

如果指定了Module,则当名字为指定值的模块加载时发生中断。Module可以指定模块的名字或地址。如果指定名字,Module可以包含通配符和说明。(关于该语法的更多信息,查看 字符串通配符语法。)

调试器只会记录最近一次的ld设置。不支持对多个模块多次设置。在ldModule之间需要加上一个冒号或者空格。

如果省略Module ,则任何模块加载都会触发事件。

Output
ud[:Module] 卸载模块(Unload module)  

如果指定了Module,则当名字为指定值的模块加载时发生中断。Module可以指定模块的精确名字或地址。如果Module是精确名字,调试器会使用保存的模块列表和地址将它立即转换为地址来记录。如果Module包含通配符,则字符串模板会被保存下来在之后的卸载事件发生时用来匹配。

极少数情况下,调试器没有卸载事件的名字信息,只能通过地址来进行匹配。因此,如果Module 包含通配符,这种情况下调试器无法确定被卸载模块的名字,所以任何模块被卸载都会中断。

调试器只会记录最近一次的ud设置。不支持对多个模块多次设置。在udModule之间需要加上一个冒号或空格。

如果没有指定Module,任何模块加载时都会触发事件。

Output
out[:Output] 目标程序输出(Target application output)

如果指定了Output,仅当接收到和模板字符串匹配的输出时才中断。Output 可以包含数个通配符和说明。 (关于该语法的更多信息,查看字符串通配符语法。) 但是,Output中不能包含冒号或者空格。匹配不是大小写敏感的。在outOutput之间应该加上一个冒号或者空格。

Ignore
ibp 初始断点(Initial break point)

(该事件在开始调试会话和重起目标机时发生。)

用户模式:Break。可以使用-g 命令行选项将这个方式修改为"Ignore"。

内核模式:Ignore 。可以通过几种方法设置为"Enabled" 关于修改该方式的更多信息,查看崩溃和重起目标机

iml 初始模块加载(Initial module load)

(仅内核模式)

Ignore。可以通过几种方法设置为"Break" 关于修改该方式的更多信息,查看崩溃和重起目标机

Build machine: CAPEBUILD