控制异常和事件

可以通过各种方法捕获和处理用户模式和内核模式应用程序中的异常。 活动调试器、事后调试器或内部错误处理例程都是处理异常的常见方法。

有关这些各种异常处理程序的优先顺序的详细信息,请参阅 启用事后调试

当 Microsoft Windows 操作系统允许调试器处理异常时,生成异常的应用程序 会中断调试 器。 也就是说,应用程序停止,调试器变为活动状态。 然后,调试器可以以某种方式处理异常或分析情况。 然后,调试器可以结束进程或让它继续运行。

如果调试器忽略异常并允许应用程序继续运行,则操作系统会查找其他异常处理程序,就好像没有调试器一样。 如果异常得到处理,应用程序将继续运行。 但是,如果异常仍未处理,则调试器会获得第二次处理这种情况的机会。

使用调试器分析异常

当异常或事件闯入调试器时,可以使用调试器检查正在执行的代码和应用程序正在使用的内存。 通过更改某些数量或跳转到应用程序中的不同点,可以消除异常的原因。

可以通过发出 gh (Go with Exception Handled) gn (Go with Exception Not Handled) 命令来恢复执行。

如果在调试器处理异常的第二次机会中发出 gn 命令,应用程序将结束。

内核模式异常

内核模式代码中发生的异常比用户模式异常更严重。 如果未处理内核模式异常,则会发出 bug 检查并停止系统。

与用户模式异常一样,如果内核模式调试器附加到系统,则会在 bug 检查屏幕 (也称为蓝屏) 出现之前通知调试器。 如果未附加调试器,则显示 bug 检查屏幕。 在这种情况下,操作系统可能会创建 故障转储文件

从调试器控制异常和事件

可以将调试器配置为以特定方式响应指定的异常和事件。

调试器可以为每个异常或事件设置中断状态:

  • 该事件在“第一次机会”) 发生 (,就可能导致调试器中断。

  • 在其他错误处理程序有机会响应 (“第二次机会”) 后,该事件可能会中断。

  • 事件还可以向调试器发送消息,但继续执行。

  • 调试器可以忽略 事件。

调试器还可以设置每个异常和事件的处理状态。 调试器可以将事件视为已处理的异常或未经处理的异常。 (当然,实际上不是错误的事件不需要任何处理。)

可以通过执行以下操作之一来控制中断状态和处理状态:

  • “调试器命令”窗口中使用 SXESXDSXNSXI 命令。

  • (CDB 和 NTSD) 在命令行上使用 -x-xe-xd-xn-xi 选项。

  • (CDB、NTSD 和 KD)Tools.ini文件中使用 sxesxd 关键字 (keyword)

  • (WinDbg 仅) “调试”菜单上的“选择事件筛选器”打开“事件筛选器”对话框,然后选择所需的选项。

SX\* 命令、-x\* 命令行选项和 sx\* Tools.ini 关键字 (keyword) 通常设置指定事件的中断状态。 可以添加 -h 选项,以便改为设置处理状态。

有四个特殊事件代码 (cchcbpecssec) ,它们始终指定处理状态而不是中断状态。

可以使用 .lastevent (显示 最后一个事件) 命令来显示最近的异常或事件。

控制中断状态

设置异常或事件的中断状态时,可以使用以下选项。

命令 状态名称 说明

SXE-xe

休息

已启用 ()

发生此异常时,目标会立即中断调试器。 此中断发生在激活任何其他错误处理程序之前。 此方法称为 第一次机会处理

SXD-xd

第二次机会休息

(禁用)

尽管) 显示消息,但调试器不会针对此类第一次发生异常 (中断。 如果其他错误处理程序无法解决此异常,则执行将停止,目标将中断调试器。 此方法称为 第二次机会处理

SXN-xn

输出

(通知)

发生此异常时,目标应用程序根本不会中断调试器。 但是,将显示一条消息,通知用户此异常。

SXI-xi

忽略

发生此异常时,目标应用程序不会中断调试器,并且不会显示任何消息。

如果 SX* 设置未预料到异常,则目标应用程序在第二次机会中中断调试器。 本主题的以下“事件定义和默认值”部分列出了事件的默认状态。

若要使用 WinDbg 图形界面设置中断状态,“调试”菜单上的事件筛选器从“事件筛选器”对话框的列表中选择所需的事件,然后选择“启用”、“禁用”、“输出”或“忽略”。

控制处理状态

所有事件都被视为未经处理,除非使用 gh (Go with Exception Handled) 命令。

所有异常都被视为未经处理,除非将 sx\* 命令与 -h 选项一起使用。

此外, SX* 选项可以为无效句柄、STATUS_BREAKPOINT中断指令和单步异常配置处理状态。 (此配置与其中断配置分开。) 配置中断状态时,这些事件分别命名为 chbpesse。 配置其处理状态时,这些事件分别命名为 hcbpecssec。 (有关事件的完整列表,请参阅以下“事件定义和默认值”部分。)

可以配置 CTRL+C 事件的处理状态 (cc) ,但不能配置其中断状态。 如果应用程序收到 CTRL+C 事件,则应用程序始终会中断调试器。

cchcbpecssec 事件上使用 SX* 命令时,或者在异常时将 SX* 命令与 -h 选项一起使用时,将发生以下操作。

命令 状态名称 说明

SXE

已处理

恢复执行时,该事件被视为已处理。

SXD、SXN、SXI

未处理

恢复执行时,该事件被视为未处理。

若要使用 WinDbg 图形界面设置处理状态,请在“调试”菜单中选择“事件筛选器”,从“事件筛选器”对话框的列表中选择所需的事件,然后选择“已处理”或“未处理”。

自动命令

调试器还允许设置在事件或异常导致中断调试器时自动执行的命令。 可以为第一次机会中断设置命令字符串,为第二次机会中断设置命令字符串。 可以使用 SX\* 命令或 Debug | 设置这些字符串事件筛选器 命令。 每个命令字符串可以包含多个用分号分隔的命令。

无论中断状态如何,都会执行这些命令。 也就是说,如果中断状态为“忽略”,则仍会执行该命令。 如果中断状态为“第二次机会中断”,则会在异常首次发生时执行第一次机会命令,然后再涉及任何其他异常处理程序。 命令字符串可以以执行命令结尾,例如 g (Go) gh (Go 与异常处理) ,或 gn (Go with Exception Not Handled)

事件定义和默认值

可以更改以下异常的中断状态或处理状态。 指示其默认中断状态。

以下异常的默认处理状态始终为“未处理”。 请小心更改此状态。 如果将此状态更改为“已处理”,则此类型的所有第一次和二次机会异常都被视为已处理,并且此配置将绕过所有异常处理例程。

事件代码 含义 默认中断状态

asrt

断言失败

中断

av

访问冲突

中断

Dm

数据未对齐

中断

Dz

整数除以零

中断

c000008e

浮点除以零

中断

C++ EH 异常

第二次机会休息

Gp

保护页冲突

中断

第二

非法指令

第二次机会休息

iov

整数溢出

中断

ip

页内 I/O 错误

中断

Isc

系统调用无效

中断

lsq

锁序列无效

中断

sbo

堆栈缓冲区溢出

中断

苏联

堆栈溢出

中断

wkd

唤醒调试器

中断

aph

应用程序挂起

如果 Windows 操作系统认为某个进程已停止响应, (挂起 ) ,则会 触发此异常。

中断

3c

子应用程序终止

第二次机会休息

chhc

无效句柄

中断

数字

任何编号异常

第二次机会休息

注意可以使用 ah (断言处理) 命令替代特定地址的 asrt 中断状态。 chhc 事件代码引用相同的异常。 控制中断状态时,请使用 sx* ch。 控制其处理状态时,请使用 sx* hc

可以更改以下异常的中断状态或处理状态。 指示其默认中断状态。

以下异常的默认处理状态始终为“已处理”。 由于这些异常用于与调试器通信,因此通常不应将其状态更改为“未处理”。 如果调试器忽略异常,此状态会导致其他异常处理程序捕获这些异常。

应用程序可以使用 DBG_COMMAND_EXCEPTION (dbce) 与调试器通信。 此异常类似于断点,但可以在发生此异常时使用 SX* 命令以特定方式做出反应。

事件代码 含义 默认中断状态

dbce

特殊调试器命令异常

忽略

vcpp

特殊 Visual C++ 异常

忽略

wos

WOW64 单步异常

中断

wob

WOW64 断点异常-

中断

Sse
ssec

单步异常

中断

Bpe
bpec

断点异常

中断

Cce
Cc

Ctrl+C 或 CTRL+BREAK

如果目标是控制台应用程序,并且向其传递 CTRL+C 或 CTRL+BREAK,则会触发此异常。

中断

注意 上表中最后三个例外具有两个不同的事件代码。 控制中断状态时,请使用 ssebpecce。 控制其处理状态时,请使用 ssecbpeccc

调试托管代码时,以下异常非常有用。

事件代码 含义 默认状态

clr

公共语言运行时异常

第二次机会休息

未处理

clrn

公共语言运行时通知异常

第二次机会休息

已处理

可以更改以下事件的中断状态。 由于这些事件不是例外,因此其处理状态无关紧要。

事件代码 含义 默认中断状态

ser

系统错误

忽略

cpr[Process]

进程创建

设置此事件的中断状态仅适用于用户模式调试。 此事件不会在内核模式下发生。

仅当已通过 -o命令行选项 或通过 .childdbg ( 调试子进程) 命令激活 CDB 或 WinDbg 中的子进程的调试时,才能控制此事件。

进程名称可以包含可选的文件扩展名和星号 () 或问号 (?) 作为通配符。 调试器仅记住最新的 cpr 设置。 不支持单独进程的单独设置。 在 cprProcess 之间包括冒号或空格。

如果省略 Process ,则该设置将应用于任何子进程创建。

忽略

epr[Process]

进程退出

设置此事件的中断状态仅适用于用户模式调试。 此事件不会在内核模式下发生。

仅当已通过 -o命令行选项 或通过 .childdbg ( 调试子进程) 命令激活 CDB 或 WinDbg 中的子进程的调试时,才能控制此事件。

进程名称可以包含可选的文件扩展名和星号 () 或问号 (?) 作为通配符。 调试器仅记住最新的 epr 设置。 不支持单独进程的单独设置。 在 eprProcess 之间包括冒号或空格。

如果省略 Process ,则该设置将应用于任何子进程退出。

忽略

ct

线程创建

忽略

et

线程退出

忽略

ld[Module]

加载模块

如果指定 Module,则加载具有此名称的模块时会发生中断。 模块 可以指定模块的名称或地址。 如果使用名称, 模块 可能包含各种通配符和说明符。 (有关语法的详细信息,请参阅 字符串通配符语法。)

调试器仅记住最新的 ld 设置。 不支持单独模块的单独设置。 在 ldModule 之间包括冒号或空格。

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

输出

ud[Module]

卸载模块

如果指定 Module,则卸载具有此名称的模块或此基址处的模块时,将发生中断。 模块 可以指定模块的名称或地址。 如果使用名称, 则 Module 可以是确切的名称,也可以包含通配符。 如果 Module 是确切的名称,则会使用当前调试器模块列表立即将其解析为基址,并将其存储为地址。 如果 Module 包含通配符,则会保留模式字符串,以便在发生卸载事件时进行匹配。

在极少数情况下,调试器没有卸载事件的名称信息,并且仅按基址匹配。 因此,如果 Module 包含通配符,则调试器无法在此特定卸载情况下执行名称匹配,并在卸载任何模块时中断。

调试器仅记住最新的 ud 设置。 不支持单独模块的单独设置。 在 udModule 之间包括冒号或空格。

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

输出

out[Output]

目标应用程序输出

如果指定 Output,则仅当收到与指定模式匹配的输出时,才会发生中断。 输出 可以包含各种通配符和说明符。 (有关语法的详细信息,请参阅 字符串通配符语法。) 但是, 输出 不能包含冒号或空格。 匹配时不区分大小写。 在 outOutput 之间包括冒号或空格。

忽略

ibp

初始断点

(此事件在调试会话开始时和重新启动目标计算机后发生。)

在用户模式下: 打破。 可以使用 -g命令行选项将此状态更改为“忽略”。

在内核模式下: 忽略。 可以通过各种方法将此状态更改为“已启用”。 有关如何更改此状态的详细信息,请参阅 崩溃和重新启动目标计算机

iml

初始模块加载

仅 (内核模式)

忽略。 可以通过各种方法将此状态更改为“中断”。 有关如何更改此状态的详细信息,请参阅 崩溃和重新启动目标计算机