避免调试器搜索不需要的符号
上次更新时间:
- 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 的效果,请尝试以下试验:
- 使用 -n 命令行选项激活干扰符号加载(SYMOPT_DEBUG),或者,如果调试器正在运行,请使用 .symopt+0x80000000 或 !sym 调试器扩展命令。 SYMOPT_DEBUG 指示调试器显示有关其搜索符号的信息,例如加载每个模块的名称;如果调试器找不到文件,则显示错误消息。
- 指示调试器评估不存在的符号(例如,类型 ?asdasdasd)。 调试器在其搜索不存在的符号时应报告大量错误。
- 使用 .symopt+0x100 激活 SYMOPT_NO_UNQUALIFIED_LOADS。
- 重复步骤 2。 调试器应仅搜索加载的模块来查找不存在的符号,而且完成任务的速度应该会更快。
- 若要禁用 SYMOPT_DEBUG,请使用 .symopt-0x80000000 或 !sym quiet 调试器扩展命令。
许多选项可用于控制调试器加载和使用符号的方式。 有关符号选项的完整列表以及使用方法,请参阅 Windows 调试工具提供的联机文档中的“设置符号选项”。 最新版本的 Windows 调试工具包可从网页免费下载,也可以通过 Windows DDK、平台 SDK 或客户支持诊断 CD 安装包安装。
该怎么办?
- 若要加快符号搜索速度,请尽可能在断点和调试器命令中使用限定名称。 如果想要查看已知模块中的符号,请使用模块名称对其进行限定;如果不知道符号的位置,请使用非限定名称。 对于局部变量和函数参数,请使用 $ 模块名称(例如 $!MyVar)。
- 若要诊断符号加载缓慢的原因,请使用 -n 命令行选项激活干扰符号加载 (SYMOPT_DEBUG),或者,如果调试器已在运行,请使用.symopt+0x80000000 或 !sym noisy 调试器扩展命令。
- 若要防止调试器在卸载的模块中搜索符号,请使用 -snul 命令行选项激活 SYMOPT_NO_UNQUALIFIED_LOADS,或者,如果调试器已在运行,请使用 .symopt+0x100。
- 若要显式加载调试会话所需的模块,请使用 .reload 或 ld 等调试器命令。