我必须使用没有源代码的第三方组件。我有发布 DLL 和发布 PDB 文件。我们称它为“CorporateComponent.dll”。我自己的代码从此 DLL 创建对象并调用这些对象的方法。
CorpObject o = new CorpObject();
Int32 result = o.DoSomethingLousy();
调试时,“DoSomethingLousy”方法会引发异常。PDB 文件对我有什么作用?如果它做得很好,我怎么能确定我正在使用它?
要确认您是否在使用提供的 PDB,CorporateComponent.pdb,在 Visual Studio IDE 中进行调试期间,请查看输出窗口并找到指示 CorporateComponent.dll 已加载并后跟字符串的行Symbols loaded
。
从我的一个项目中说明:
The thread 0x6a0 has exited with code 0 (0x0).
The thread 0x1f78 has exited with code 0 (0x0).
'AvayaConfigurationService.vshost.exe' (Managed): Loaded 'C:\Development\Src\trunk\ntity\AvayaConfigurationService\AvayaConfigurationService\bin\Debug \AvayaConfigurationService.exe', Symbols loaded.
'AvayaConfigurationService.vshost.exe' (Managed): Loaded 'C:\Development\Src\trunk\ntity\AvayaConfigurationService\AvayaConfigurationService\bin\Debug\IPOConfigService.dll', No symbols loaded.
Loaded 'C:\Development\src...\bin\Debug\AvayaConfigurationService.exe', Symbols loaded.
这表明 IDE 调试器找到并加载了 PDB。
正如其他人所指出的 在检查应用程序中的堆栈帧时,您应该能够看到 CorporateComponent.pdb 中的符号。如果您不这样做,那么第三方可能没有在发布 PDB 构建中包含符号信息。
pdb 包含调试器正确读取堆栈所需的信息。您的堆栈跟踪将包含您拥有 pdb 的模块内的堆栈帧的行号和符号名称。
我将给出两个用法示例。第一个是显而易见的答案。第二个解释源索引 pdb。
第一个用法示例...
根据调用约定和编译器使用的优化,调试器可能无法通过您没有 pdb 的模块手动展开堆栈。某些第三方库甚至操作系统的某些部分都可能发生这种情况。
考虑在 Windows 操作系统内部遇到访问冲突的场景。堆栈跟踪不会展开到您自己的应用程序中,因为该操作系统组件使用了一种特殊的调用约定,这会使调试器感到困惑。如果您将符号路径配置为下载公共 OS pdb,那么堆栈跟踪很有可能会展开到您的应用程序中。这使您能够准确地看到您自己的代码传递给操作系统系统调用的参数。(以及 3rd 方库内部甚至您自己的代码内部的 AV 的类似示例)
第二个使用示例...
Pdb 有另一个非常有用的属性——它们可以使用微软称之为“源索引”的功能与一些源代码控制系统集成。源索引 pdb 包含源控制命令,这些命令指定如何从源控制获取用于构建组件的确切文件版本。Microsoft 的调试器了解如何在调试会话期间执行命令以自动获取文件。这是一个强大的功能,它使调试工程师不必手动将源代码树同步到给定构建的正确标签。它对于远程调试会话和事后分析崩溃转储特别有用。
“windows 调试工具”安装 (windbg) 包含一个名为 srcsrv.doc 的文档,该文档提供了一个示例,演示如何使用 srctool.exe 来确定在给定 pdb 中哪些源文件被源索引。
要回答您的问题“我怎么知道”,调试器中的“模块”功能可以告诉您哪些模块具有相应的 pdb。在windbg 中使用“lml”命令。在 Visual Studio 中,从调试菜单中的某处选择模块。(抱歉,我手边没有当前版本的 Visual Studio)
PDB 是一个数据库文件,它将指令映射到原始代码中的行号,因此当您获得堆栈跟踪时,您将获得代码的行号。如果它是非托管 DLL,那么 PDB 文件还将为您提供堆栈跟踪中函数的名称,而该信息通常仅适用于没有 PDB 的托管 DLL。
我从 pdb 获得的主要信息是堆栈跟踪的行号和真实方法名称。