避免调试器搜索不需要的符号

上次更新时间:

  • 2007 年 5 月 27 日

调试驱动程序时,你到达了一个有趣的断点,只是让调试器暂停很长一段时间,而它尝试加载你不拥有的驱动程序的符号,甚至对手头调试任务并不重要。 这是怎么回事?

默认情况下,调试器会根据需要加载符号。 (这称为延迟符号加载或延迟符号加载。) 调试器在执行调用符号显示命令时查找符号。 如果在当前上下文中设置了无效的监视变量(例如当前堆栈帧中不存在的函数参数或局部变量),则此变量在断点上可能会发生这种情况,因为它们在上下文更改时变得无效。 如果只是错误键入符号名称或执行无效的调试器命令,调试器开始查找匹配的符号,则也可能发生这种情况。

为什么这有时需要这么长的时间? 这取决于符号名称是限定还是不限定。 限定符号名称前面有包含符号的模块的名称,例如 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_DEBUG) 的干扰符号;如果调试器正在运行,请使用 .symopt+0x80000000!sym 干扰调试器扩展命令。 SYMOPT_DEBUG 指示调试器显示有关其搜索符号的信息,例如加载每个模块的名称;如果调试器找不到文件,则显示错误消息。
  2. 指示调试器评估不存在的符号 (例如,键入 ?asdasdasd) 。 调试器在搜索不存在的符号时应报告大量错误。
  3. 使用 .symopt+0x100 激活SYMOPT_NO_UNQUALIFIED_LOADS
  4. 重复步骤 2。 调试器应仅搜索未存在的符号的已加载模块,并且应更快地完成任务。
  5. 若要禁用 SYMOPT_DEBUG,请使用 .symopt-0x80000000!sym quiet 调试器扩展命令。

许多选项可用于控制调试器加载和使用符号的方式。 有关符号选项的完整列表以及如何使用它们,请参阅 Windows 调试工具提供的联机文档中的“设置符号选项”。 最新版本的 Windows 调试工具包可从 Web 免费下载,也可以从 Windows DDK、平台 SDK 或客户支持诊断 CD 安装该包。

该怎么办?

  • 若要加快符号搜索速度,请尽可能在断点和调试器命令中使用限定的名称。 如果想要查看已知模块中的符号,请使用模块名称限定该符号;如果不知道符号的位置,请使用不限定的名称。 对于局部变量和函数参数,请使用 $ 模块名称 (例如 $!MyVar) 。
  • 若要诊断符号加载缓慢的原因,请使用 -n 命令行选项激活干扰符号加载 (SYMOPT_DEBUG) ,或者,如果调试器已在运行,请使用 .symopt+0x80000000!sym noisy 调试器扩展命令。
  • 若要防止调试程序在卸载的模块中搜索符号,请使用 -snul 命令行选项激活SYMOPT_NO_UNQUALIFIED_LOADS;如果调试器已在运行,请使用 .symopt+0x100
  • 若要显式加载调试会话所需的模块,请使用调试器命令,例如 .loadld

下载 WDK

下载 Windows 调试工具

Windows 调试入门