调试时 PDB 给我带来什么以及我如何知道它正在工作?
题
我必须使用没有源代码的第三方组件。我有发布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 操作系统内部遇到访问冲突。堆栈跟踪不会展开到您自己的应用程序中,因为该操作系统组件使用特殊的调用约定,这会使调试器感到困惑。如果您配置符号路径来下载公共操作系统 pdb,那么堆栈跟踪很有可能会展开到您的应用程序中。这使您能够准确地看到您自己的代码传递到操作系统系统调用中的参数。(以及第三方库内甚至您自己的代码内的 AV 的类似示例)
第二个使用示例...
Pdb 还有另一个非常有用的属性 - 它们可以使用微软称为“源索引”的功能与某些源控制系统集成。源索引 pdb 包含源控制命令,这些命令指定如何从源控制获取用于构建组件的确切文件版本。Microsoft 的调试器了解如何执行命令以在调试会话期间自动获取文件。这是一个强大的功能,可以让调试工程师不必手动将源树同步到给定构建的正确标签。它对于远程调试会话和事后分析故障转储特别有用。
“Windows 调试工具”安装 (windbg) 包含一个名为 srcsrv.doc 的文档,该文档提供了一个示例,演示如何使用 srctool.exe 确定给定 pdb 中哪些源文件已建立源索引。
为了回答您的问题“我怎么知道”,调试器中的“模块”功能可以告诉您哪些模块有相应的 pdb。在windbg中使用“lml”命令。在 Visual Studio 中,从调试菜单中的某个位置选择模块。(抱歉,我手头没有当前版本的 Visual Studio)
PDB 是一个数据库文件,它将指令映射到原始代码中的行号,因此当您获得堆栈跟踪时,您将获得代码的行号。如果它是非托管 DLL,则 PDB 文件还会为您提供堆栈跟踪中的函数名称,而该信息通常仅适用于没有 PDB 的托管 DLL。
我从 pdb 获得的主要信息是堆栈跟踪的行号和实际方法名称。