了解PDB(Program database file)文件

来源:互联网 发布:怎么样提升淘宝流量 编辑:程序博客网 时间:2024/05/17 00:54

原文出处:http://www.codeproject.com/Articles/349076/Know-Program-Database-file-PDB

译文如下:

简介:

这篇文章对“不了解PDB文件的重要性,不知道为什么需要PDB文件”的初中级开发人员有帮助。

PDB文件是什么?

PDB是Program database file的首字母简略词,直译为程序数据文件。就是记录程序中的一些数据的文本。

PDB文件是在程序编译期从源文件中生成的。它将一个模块里所有的符号信息储存为一个列表,这些信息包括符号的地址和文件的名字,还有符号在程序中被申明的行号。(来自维基百科)

为什么PDB要单独作为一个文件?

这些符号信息可以很好的嵌入到二进制文件中,但是它们会导致文件变得很大(有时是几M)。为了避免额外的空间消耗,现代的编译器和早期的大型调试系统会将符号信息输出到一个单独的文件中。对于微软的编译器,这个文件就叫作PDB文件。

PDB文件中包含哪些信息?

下面的是储存在PDB文件中的一部分重要信息

1.本地变量名-为了验证PDB文件保护本地变量名,我们将利用Reflector反编译与PDB在相同文件夹下的组件。Reflector有个叫作“Show PDB symbols”的选项,如下截图所示。当你选中这个选项后你可以看到反编译后的代码里的变量名和你实际的代码里变量名一样。如果没有PDB文件或者这个选项没有被选中,反编译后的代码中的变量名会被替代。比如string变量被str替代,数值类型被num替代等。


2.源文件名字

3.源文件的行号

4.源文件的索引(稍后的章节介绍)

为了展示PDB文件包含源文件名和源文件的行号(第二点和第三点)。分别运行下面的控制台程序两次。一次是有PDB文件,另一次是删掉PDB文件。

namespace UnderstandingPDBs{    class Program    {        static void Main(string[] args)        {            try            {                int sum = Add(5, 10);                decimal value = Divide(10, 0);            }             catch            {            }        }         private static int Add(int i, int j)        {            return i + j;        }         private static decimal Divide(int i, int j)        {            try            {                return i / j;            }            catch (Exception ex)            {                LogError(ex);                throw ex;            }                  }         private static void LogError(Exception ex)        {            using (var txtWriter = new StreamWriter(@"dump.txt",true))            {                string error = "Exception:" + ex.Message +                 Environment.NewLine + "StackTrace:" + ex.StackTrace                if(ex.InnerException!=null)                    error=error+"INNER EXCEPTION:"+ex.InnerException;                txtWriter.WriteLine(error);            }        }            }}  
有PDB运行的程序会抛出下面的异常:

Exception:Attempted to divide by zero.
StackTrace:   at UnderstandingPDBs.Program.Divide(Int32 i, Int32 j) in C:\Users\Rishi\Documents\Visual Studio 2010\Projects\UnderstandingPDBs\Program.cs:line 33

没有PDB运行的程序会显示下面的信息:

Without PDB exception shows following message.

Exception:Attempted to divide by zero.
StackTrace:   at UnderstandingPDBs.Program.Divide(Int32 i, Int32 j)
---------

有PDB运行的那次,当程序抛出异常时,可以清楚的显示异常代码的行号,类的名字。

调试器是如何加载PDB文件的?

Visual Studio调试器期望PDB文件和相应的dll/exe在相同的文件夹下。对于每次编译代码,为相应组件产生的PDB文件都是独特的,这意味着你不能将之前编译产生的PDB文件和之后编译的组件组合到一起,即使代码没有改变也不行。调试器通过PDB文件和二进制文件中的GUID来进行确认。GUID是在编译器嵌入到二进制和PDB中的,从而将两者联系起来。

Visual Studio中不同的编译设置项

Visual Studio有三个不同的编译选项,控制调试符号的生成。

1.none:PDB文件不会被生成。

2.pdb-only:调试符号只存在于PDB中,而不会存在于对于二进制文件中。

3.Full:和PDB里符号一样,二进制文件也会包含调试符号。

Full是Visual Studio默认的选项。

引自msdn

“如果你使用/debug:full,需要注意这会对JIT优化的代码造成速度和大小方面的影响,对代码质量也有一定的小影响。我们推荐/debug:pdbonly或者对release版本的代码禁止生成PDB。”


我们应该在二进制文件中部署PDB吗?

如果产品的大小不需要关心的话,在二进制文件中部署PDB是个好主意,它会提供更多的异常信息,就像我们再上面的例子中看到的。这些PDB在用户端偶发的程序崩溃的时候非常有用,如果这时候没有PDB,定位问题会非常困难。

但也并不是说你必须要在二进制文件中嵌入调试符号来获取额外的异常信息。通过使用符号服务器和源文件索引也可以达到相同的目的,这些会在之后的主题中讨论。

PDB有安全隐患吗?任何能够访问dll/exe的人都可以很容易的通过逆向工程来生成源代码,无论有没有PDB文件。比如使用reflector工具。因此这种情况下PDB没有安全隐患。

如果PDB被部署了,但是用户没有权限访问二进制文件。那么给他们展示堆栈信息,让他们知道程序的内部结构就不是好主意了。

符号服务器

符号服务器是用来储存对调试器已知的pdb文件,能够用来发现更多描述调用栈的信息。

我们可以通过symstore.exe来设置自己的符号服务器,这样当出现问题时调试器可以去发现实际的PDB文件。symstore.exe工具包含在微软官方包的调试工具中。

微软也维护符号服务器,我们可以从微软的符号服务器上加载PDB文件。

当你运行到断点处,打开Modules窗口(如下所示),你将会发现截止到断点之前所有被加载的dll(内部的或外部的)。但是默认的符号状态显示为“Cannot find or open pdb file”除了你的PDB文件。这些是微软BCL二进制文件,因为调试器无法找到相应的PDB,所以不能加载。


为了加载这些符号,点击Debugging->Symbols,然后选择Microsoft Symbol Servers,并且在Cache symbols in this directory提供一个共享文件夹供所有开发者使用。

由于这些二进制文件对你的程序而言是外部的,你需要取消Debugging->General菜单中的“Enable just my Code”选项。


以上设置有什么用处呢?

在没有符号加载的前提下,你可以在你的代码里打断点,然后看调用栈。

下面的图像展示了没有符号加载的情况下的调用栈。它只是显示了我的方法和BCL'的方法。


当符号被加载了,调用栈会显示断点处之前的所有方法的调用层次(看下图)。在我们想知道外部被调用的方法是什么的时候,这会非常有用。我们可以通过reflector或者调试器来分析这些信息,从而把出错的地方和某些外部代码导致的行为改变联系起来,帮助我们定位问题。


和符号服务器一样,这里有个用来返回源文件的准备版本的源文件服务器。它用来编译任何特定的应用程序。二进制文件在编译的时候可以被索引,这些信息储存在PDB里面。这可以帮助源文件服务器发现准确的源文件。

想了解更多关于符号和源文件储存的信息可以查阅msdn。

0 0
原创粉丝点击