关于 PDB 文件你需要知道什么?
引言
大多数人知道 PDB 文件是用来帮助我们 debug 的,但也仅此而已。
本文主要介绍当你遇到 PDB 文件时(windows 开发中),你必须要知道的内容。
重要的事情说三遍
PDB 文件和源代码一样重要!!!
PDB 文件和源代码一样重要!!!
PDB 文件和源代码一样重要!!!
开始之前
首先定义两个概念:
- 本地编译:在你本机开发环境中的编译。
- 官方编译:在编译服务器上的编译。
这两种编译的区分很重要,因为调试本地编译往往很简单,但是问题往往出现在官方编译中。
官方编译至少需要有一个地方(Symbol Server)来存放编译出来的二进制及 PDB 文件。这样当某个版本发现任何问题,我们可以获取到对应的 PDB 文件进行调试。
没有匹配的 PDB 文件,调试器几乎不可能完成调试任务,或者你将付出高昂的代价才能解决问题。
更多关于 Symbol Server 的内容,参考 https://docs.microsoft.com/en-us/archive/msdn-magazine/2002/june/bugslayer-symbols-and-crash-dumps
Visual Studio 和 WinDBG 知道如何访问 Symbol Server 并且如果二进制文件来自官方编译,那么调试器能够自动加载匹配的 PDF 文件。
在将 PDB 文件放在 Symbol Server 上之前,还需要做一件事:在官方编译出来的 PDB 文件上,通过 Source Server 工具,进行源文件索引(source indexing)。索引过程会嵌入版本控制命令用于拉取当前版本编译的源文件。这样,当你调试当前版本时,你就不用担心找不到版本的源文件。
更多关于 Source Server 的内容,参考 https://docs.microsoft.com/en-us/archive/msdn-magazine/2006/august/source-server-helps-you-kill-bugs-dead-in-visual-studio-2005
什么是 PDB 文件?
现在,我们可以开始介绍什么是 PDB 文件,以及调试器是如何查找 PDB 文件了。
实际的 PDB 文件格式是加密的,但是微软提供了 API,为调试器提供 PDB 文件的数据。
非托管的 C++ PDB 文件包含了以下信息:
- 公有函数,私有函数和静态函数的地址
- 全局变量的名称和地址
- 参数和局部变量的名称以及栈上的偏移量
- 类,结构体以及数据定义的类型信息
- FPO(Frame Pointer Omission) 数据
- 源文件的文件名及行信息。
而 .NET 的 PDB 文件只包含了两项内容:
- 源文件的文件名及行信息
- 局部变量的名称
其他所有信息已经存放在 .NET 元数据中,所以没有必要再 PDB 文件中冗余。
PDB 文件的加载
当模块被加载到进程的地址空间后,调试器会使用两种信息找到匹配的 PDB 文件。首先,当然是文件名。如果你加载 ZZZ.DLL,那么调试器就会查找 ZZZ.PDB。
更重要的是,调试器如何知道这就是匹配的 PDB 文件?这是通过比对内嵌于 PDB 文件和二进制文件中的 GUID 来确认的。
负责将 GUID 嵌入二进制和 PDB 文件的是编译器(.NET)或者链接器(C++)。想想,历史编译的版本如果没有保存 PDB 文件,你还能调试吗?答案是否定的,哪怕你没有修改源文件!你可能会想是否可以修改 PDB 文件的 GUID?很遗憾,答案也是否定的。
你可以查看二进制文件中的 GUID。使用 Visual Studio -> DUMPBIN 的命令行工具,你可以列出所有的 PE(Portable Executable) 文件内容。可以在 Visual Studio 的命令行工具中调用 DUMPBIN。
更多关于 DUMPBIN 的内容参考:https://docs.microsoft.com/en-us/archive/msdn-magazine/2002/february/inside-windows-win32-portable-executable-file-format-in-detail 和 https://docs.microsoft.com/en-us/archive/msdn-magazine/2002/march/inside-windows-an-in-depth-look-into-the-win32-portable-executable-file-format-part-2
DUMPBIN 有很多命令行指令,其中显示 GUID 的指令是 /HEADERS。在输出内容中,对我们来说重要的是 Debug Directories 部分的内容:
Debug Directories
Time Type Size RVA Pointer
-------- ------- -------- -------- --------
6045C20E cv 60 00541AC8 5408C8 Format: RSDS, {DC80D058-127B-4379-B859-3F9F6978A4DB}, 1, C:ZZZ.pdb
知道了调试器如何确定匹配的 PDB 文件,下一步我们讨论调试器从哪里查找 PDB 文件。首先,调试器会在加载二进制文件的目录查找对应的 PDB 文件,如果没有找到,那么就查找PE 文件中 Debug Directories 内容里硬编码的 PDB 文件路径,在上面的输出示例中是 "C:ZZZ.pdb"(.NET 应用编译工具 MSBUILD会将 PDB 文件编译到 OBJ<Debug/Relase/...> 目录下,如果编译成功,再拷贝到 DEBUG 或者 RELEASE 目录)。如果在上述两个位置都没有找到,但是建立了 Symbol Server,那么调试器会在 Symbol Server 的缓存目录里继续查找。这种查找顺序也保证了本地编译和官方编译不会有冲突。
在 Visual Studio 中调试的时候,你可以在窗口 Modules 中的列 Symbol File 里看到 PDB 文件的位置。
对大多数应用来讲这种加载方式都没有问题。但是对于需要将程序集放入 GAC(Global Assembly Cache)的 .NET 应用,PDB 的加载就会变得有趣了。对于本地编译,调试器会在编译目录找到 PDB 文件,所以没什么问题。问题来源于当你想要在其他机器上调试本地编译版本。
在其他机器上调式,很多人会用 Gacutil.exe 将程序集放入 GAC,然后打开命令行在 "C:WINDOWSASSEMBLY" 下查找程序集的物理位置。但是基于 Any CPU 编译的程序集实际上会放入类似 "C:WindowsassemblyGAC_MSILExample1.0.0.0__682bc775ff82796a" 的路径。
上述路径中,Example 是程序集名称,1.0.0.0 是版本号,682bc775ff82796a 是公有秘钥令牌值(public key token value)。当你推断出这个路径后,你可以将 PDB 文件拷入这个目录然后调试器会加载它。
PDB 文件的内容
对于官方编译,因为有源文件索引工具,所以 PDB 文件中会存储版本控制命令,用于将源文件放入你配置的源文件缓存池。对于本地编译,PDB 文件中存储的是二进制文件对应的源文件的完整路径。换句话说,如果你使用 C:FOO 中的源文件 MYCODE.CPP,那么 PDB 文件中存储的就是 C:FOOMYCODE.CPP。
理论上,所有的官方编译会自动立马进行源文件索引,并将内容存储于 Symbol Server,以至于你都不用考虑源文件在哪。然而,有些开发团队在测试及其他环节中会考量编译结果是否满足使用的要求,在此之前,不会对 PDB 文件进行源文件索引。如果你确实需要调试未索引的版本,最好将源代码下载到本地时保证和编译服务器相同的磁盘和目录,否则,你可能会在调试时遇到麻烦。尽管 Visual Studio 调试器和 WinDBG 有配置源文件搜索路径的选项,但要配置正确并不容易。
引用
https://www.wintellect.com/pdb-files-what-every-developer-must-know/
关于 PDB 文件你需要知道什么?的更多相关文章
- Microsoft Visual Studio PDB文件相关事宜
Microsoft Visual Studio PDB:调试的符号文件,程序数据库 (PDB) 文件保存着调试和项目状态信息,使用这些信息可以对程序的调试配置: 当以 /ZI 或 /Zi(用于 C/C ...
- Visual Studio 不生成.vshost.exe和.pdb文件的方法【转】
Visual Studio 不生成.vshost.exe和.pdb文件的方法[转] 使用Visual Studio编译工程时,默认设置下,即使选择了「Release」时也会生成扩展名为「.vshost ...
- windbg不识别pdb文件符号
一开始配置完毕后 输入reload 但不识别 输入reload -f 还是不识别 输入reload -f 模块名 继续不识别 !sym noisy 查看 输入reload 发现有了一堆的查找路径 把 ...
- Visual Studio无法查找或打开 PDB 文件解决办法
Visual Studio无法查找或打开 PDB 文件解决办法 用VS调试程序时,有时会在VS底部的“输出”框中提示“无法查找或打开 PDB 文件”.这该怎么解决呢? 下面,我们以VS2013为例,来 ...
- .pdb文件的使用方法
1.Demo1:用DLL_01生成my.dll.my.pdb.my.lib文件. 2.Demo2:在DLL_01_APP_02中使用DLL_01的dll. 步骤: 1.vs2008打开DLL_01_A ...
- 2016-07-07: 重新编译时vc90.pdb不是创建此预编译头时使用的pdb文件
使用VS2008在一个解决方案中包含多个项目时,当设置多个项目的中间目录为同一个目录时,在增量编译时出现"重新编译时vc90.pdb不是创建此预编译头时使用的pdb文件,请重新创建预编译头问 ...
- VS2013 编译程序时提示 无法查找或打开 PDB 文件
"Draw.exe"(Win32): 已加载"C:\Users\YC\Documents\Visual Studio 2013\Projects\Draw\Debug\ ...
- PDB文件:每个开发人员都必须知道的
PDB Files: What Every Developer Must Knowhttp://www.wintellect.com/CS/blogs/jrobbins/archive/2009/05 ...
- Visual Studio 不生成.vshost.exe和.pdb文件的方法
使用Visual Studio编译工程时,默认设置下,即使选择了「Release」时也会生成扩展名为「.vshost.exe」和「.pdb」的文件. 一.先解释一下各个文件的作用: .pdb文件: 程 ...
- 解决“C:\Windows\System32\ntdll.dll”。无法查找或打开 PDB 文件问题
这些提示的问题完全没有必要去理会,因为一般情况下你点击本地windows调试,会报出这样问题很正常. 网上一些介绍什么要去选项卡栏勾选window连接器什么鬼,不建议用该方式,一旦你勾选那个方式虽然不 ...
随机推荐
- 网易云音乐JS逆向解析歌曲链接
Request URL: https://music.163.com/weapi/song/enhance/player/url?csrf_token= FormData : params: BV ...
- Leetcode(25)- k个一组翻转链表
给出一个链表,每 k 个节点一组进行翻转,并返回翻转后的链表. k 是一个正整数,它的值小于或等于链表的长度.如果节点总数不是 k 的整数倍,那么将最后剩余节点保持原有顺序. 示例 : 给定这个链表: ...
- In_array()函数弱比较
0x01 定义 (PHP 4, PHP 5, PHP 7) in_array - 检查数组中是否存在某个值 说明 in_array ( mixed $needle , array $haystack ...
- 将从摄像头即时读入的人像放入背景视频中_with_OpenCV_in_Python
import cv2 import numpy as np import time cap = cv2.VideoCapture(0) background_capture = cv2.VideoCa ...
- calendar merge date
calendar merge date componentDidMount () { const { monthDays, // monthDates, } = this.props; const d ...
- TypeScript 如何编写类库声明文件 .d.ts
TypeScript 如何编写类库声明文件 .d.ts how to write a d.ts file declaration-files/ https://www.typescriptlang.o ...
- XML & XPath & XQuery
XML & XPath & XQuery full XPath demo https://www.w3.org/TR/xpath-full-text-30/ https://www.w ...
- APC体育公司重视“女性经济 ”深度挖掘女性市场
据消费者追踪服务调查数据显示,从2020年1月到8月,a private company体育公司(公司编号:08703733)品牌下的女性运动服装的在线销售额较上一年增长了77%. 女性市场已然成为A ...
- 基于nginx实现上游服务器动态自动上下线——不需reload
网上关于nginx的介绍有很多,这里讲述的是上游服务(如下图的Java1服务)在没有"网关"的情况下,如何通过nginx做到动态上下线. 传统的做法是,手动修改nginx的upst ...
- spring扩展点整理
本文转载自spring扩展点整理 背景 Spring的强大和灵活性不用再强调了.而灵活性就是通过一系列的扩展点来实现的,这些扩展点给应用程序提供了参与Spring容器创建的过程,好多定制化的东西都需要 ...