如何不让调试器查找不需要的符号?
在调试驱动程序的过程中,您到达了一个有趣的断点,当它试图加载与您手头的调试任务无关的驱动程序符号时,会让调试器暂停很长一段时间。
默认情况下,调试器在需要时加载符号。(这被称为延迟符号加载。)调试器只要执行调用符号显示的命令,就会查找符号。如果您设置了一个在当前上下文中无效的观察变量(例如当前堆栈帧中不存在的函数参数或局部变量,因为它们在上下文改变时变得无效),那么可能在一个断点处发生这种情况。这也可能仅仅是因为您错误键入一个符号名或执行一个无效的调试器命令(调试器开始查找匹配的符号)而发生。
为什么这个过程有时会消耗如此长的时间?这取决于符号名合格与否。合格的符号名前面有包含符号的模块的名称(例如 myModule!myVar)。不合格的符号名未指定模块名(例如 myOtherVar)。
如果是合格的名称,那么调试器在指定的模块中查找符号,如果模块尚未加载,那么加载模块(假设模块存在并包含符号)。这个过程很快。
如果是不合格的名称,那么调试器不知道哪个模块包含符号,所以它必须在所有模块中查找。调试器首先检查该符号的所有加载模块,然后,如果它不能在任何加载的模块中匹配符号,则通过加载所有卸载的模块(从下游存储位置到符号服务器(如果使用的话))来继续搜索。显然,这会花费很长时间。
如何防止自动加载不合格的符号
SYMOPT_NO_UNQUALIFIED_LOADS 选项可以禁用或启用调试器在搜索不合格的符号时的模块自动加载功能。当设置了 SYMOPT_NO_UNQUALIFIED_LOADS 并且调试器试图匹配不合格的符号时,它只搜索已经被加载的模块,并在不能匹配符号时停止搜索(而不是加载卸载的模块来继续搜索)。这个选项不会影响到对合格名称的搜索。
在默认情况下,SYMOPT_NO_UNQUALIFIED_LOADS 是关闭的。要激活这个选项,请使用 -snul 命令行选项,或者在调试器运行时使用 .symopt+0x100 或 .symopt-0x100 来分别打开或关闭选项。
要查看 SYMOPT_NO_UNQUALIFIED_LOADS 的效果,请尝试这个试验:
1. | 通过使用 -n 命令行选项或者使用 .symopt+0x80000000 或 !sym noisy 调试器扩展命令激活详细符号加载 (noisy symbol loading)(SYMOPT_DEBUG)。 SYMOPT_DEBUG 指示调试器显示关于其搜索符号的信息,例如每个模块在加载时的名称或调试器无法找到文件时的错误消息。 |
2. | 指示调试器评估一个不存在的符号(例如,键入 ? asdasdasd)。 在搜索不存在的符号时,调试器应该会报告大量错误。 |
3. | 通过使用 .symopt+0x100 来激活 SYMOPT_NO_UNQUALIFIED_LOADS。 |
4. | 重复步骤 2。 调试器应该只在加载的模块中搜索不存在的符号,而且应该很快完成任务。 |
5. | 要禁用 SYMOPT_DEBUG,请使用 .symopt-0x80000000 或 !sym quiet 调试器扩展命令。 |
可以使用大量选项来控制调试器如何加载和使用符号。关于符号选项的完整列表以及如何使用它们的信息,请参见 Windows 调试工具中提供的在线文档中的“设置符号选项”。Windows 调试工具包的最新版本可以从网上免费下载,或者您可以从 Windows DDK、平台 SDK 或客户支持诊断光盘中安装。
您应该做什么?
| • | 要加快符号搜索,请尽可能在断点和调试器命令中使用合格的名称。如果您想要查看来自已知模块的查看符号,那么使用模块名来使其合格化;如果您不知道符号在哪里,那么使用不合格的名称。对于局部变量和函数参数,使用 $ 作为模块名称(例如 $!MyVar)。 |
| • | 要诊断符号加载缓慢的原因,请使用 -n 命令行选项来激活详细符号加载(SYMOPT_DEBUG),或者如果调试器已经在运行,那么使用 .symopt+0x80000000 或 !sym noisy 调试器扩展命令来激活详细符号加载。 |
| • | 要防止调试器在卸载的模块中搜索符号,请使用 -snul 命令行来激活 SYMOPT_NO_UNQUALIFIED_LOADS,或者如果调试器已经在运行,那么使用 .symopt+0x100 来激活它。 |
| • | 要显式加载调试会话所需的模块,请使用诸如 .reload 或 ld 等的调试器命令。 |
更多信息:
WHDC 上的调试资料:
Windows 调试工具 - 概述
调试工具和符号:入门
无效或丢失的符号
设置符号选项
使用断点
使用符号服务器和符号库