【C++】了解PDB

2024-09-05 00:32
文章标签 c++ 了解 pdb

本文主要是介绍【C++】了解PDB,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

What is the use of PDB file?

Introduction

本文帮助那些处于初级或中级水平,对PDBs格式文件的重要性和为什么需要PDBs格式文件了解不多的开发人员。

What is PDB

PDB是程序数据库文件的缩写。
PDB文件通常是在编译期间从源文件创建的。它将所有符号的列表存储在一个模块中,包含它们的地址以及可能的文件名和声明该符号的行。(来自维基)

Why PDB as a Separate File?

这些符号可以很好地嵌入二进制中,但这又会导致文件大小显著增加(有时是几兆字节)。为了避免这种额外的大小,现代编译器和早期的大型机调试系统将符号信息输出到一个单独的文件中;对于微软编译器来说,这个文件被称为PDB文件。

What Does the PDB File Contain

以下是PDB文件存储的一些重要信息:

    

    1. Local variable name - 局部变量名-为了证明PDB包含本地变量名,我们将使用反射器来反汇编程序集,其PDB存在于与程序集相同的文件夹中。反射器有一个选项,称为“显示PDB符号”,如截图所示,当选中时,也为该程序集加载相应的PDB。当您检查选项时,您可以看到反编译代码具有与实际代码相同的变量名,但是在没有PDB的情况下,或者当该选项未选中时,您的反编译代码中的本地变量将被替换为字符串变量的“STR”和“Num”。十进制等。

    2. 源文件名
    3. 信源的行号
    4. 源索引(稍后说明)

为了显示PDB包含源文件名和源代码行数(点2和3),首先运行以下控制台应用程序,其中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.StackTraceif(ex.InnerException!=null)error=error+"INNER EXCEPTION:"+ex.InnerException;txtWriter.WriteLine(error);}}}
}  

With PDB, this is the exception thrown by the application:

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

Without PDB, exception shows the following message:

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

Clearly, the one with PDB shows line number and file name of the class where exception is thrown.

How PDB is Loaded by Debugger?

VisualStudio调试器期望PDB文件处于与DLL或EXE相同的文件夹之下。为程序集生成的PDB文件对于每个生成都是唯一的,这意味着即使在没有代码更改的情况下,也不能使用以前生成的PDB与在任何其他构建中创建的程序集一起使用。调试器通过将PDB中的特定GUID与二进制的GUID进行比较来找出PDB是否为二进制。这个GUID在编译过程中嵌入二进制和PDB,它们紧密地将PDB与其二进制连接起来。

Different Build Settings in Visual Studio

Visual Studio has 3 different Build Options which control the debug symbols generation:

  1. none: PDB files will not be generated.PDB文件将不会生成。
  2. pdb-only: The debug symbols will be only in PDB files and not in Binary仅PDB:调试符号只在PDB文件中,而不是二进制文件。
  3. Full: Along with symbols in PDB binary will also contain some debug symbols完整的:连同PDB二进制中的符号也将包含一些调试符号。

Full is the default option set in Visual Studio.

According to MSDN:

"If you use /debug:full, be aware that there is some impact on the speed and size of JIT optimized code and a small impact on code quality with /debug:full. We recommend /debug:pdbonly or no PDB for generating release code."“如果您使用/Debug:FULL,请注意,JIT优化代码的速度和大小会有一些影响,对代码质量的影响也会很小。我们建议/调试:PDBUN或无PDB生成发布代码。


Should We Deploy PDBs Along with Binaries?


如果交付物的大小不是一个问题,那么PDB与其他二进制文件一起部署是很好的,因为它有助于提供更多关于异常的信息,正如我们在上面的例子中看到的。这些PDBS在某些断断续续发生的某些崩溃中是非常有用的,对于某些用户来说,如果没有PDB,将使生命变得困难。
并不是必须部署PDB和二进制部署来获得关于异常的额外信息。同样可以使用符号服务器和源索引来实现,我将在下面的主题中进行讨论。

Security Risk with PDB?
任何有权访问DLL/EXE的人都可以很容易地做逆向工程,使用诸如反射器之类的工具生成或不使用PDB的源代码。因此,在这种情况下,不提供PDB将没有多大帮助。
如果部署了PDB并且用户不能访问二进制文件,那么向他们展示堆栈跟踪信息并让他们知道应用程序的内部结构不是一个好主意。

Symbol Server

符号服务器用于存储调试器已知的PDB文件,并可用于查找更多描述性的调用堆栈信息。

我们可以使用SyStur.EXE设置自己的符号服务器,它允许调试器找到与所讨论的二进制相关联的实际PDB。SytSuff.EXE包含在Window包的调试工具中。
微软还维护符号服务器,我们可以通过从微软的符号服务器加载PDB来使用。

How and Why to load Microsoft Symbol Store

当您在调试点和打开模块窗口停止执行时(如下所示),您将发现所有的DLL(外部或内部)加载到该断点为止,但是默认情况下的符号状态将显示“除了PDB之外无法找到或打开PDB文件”。这些是微软BCL二进制文件,因为我们的调试器找不到相关的PDB,所以这些二进制二进制文件没有加载。


若要加载这些符号,请转到“调试”>符号并检查微软符号服务器,并将此目录中的缓存符号作为任何共享文件夹,以便其可由所有开发人员使用。
由于这些二进制文件在您的应用程序之外,还需要在“调试”>“常规”菜单中取消“启用仅我的代码”。


那么这怎么可能有用呢?


可以在代码中放置断点,并在加载和不加载符号的情况下查看调用堆栈。
下图显示了没有加载符号的调用堆栈,它只显示了我的方法和BCL的方法(只是外部代码)。
在下面的屏幕截图中,你可以看到我已经加载了符号,现在符号的状态显示了“符号加载”。

与符号服务器一样,还有一个叫做源服务器的东西,用来检索用于构建任何特定应用程序的源文件的精确版本。二进制文件可以在构建时被索引,并且这些信息存储在PDB文件中,这有助于源服务器找到确切的源文件。

Points of Interest

PDB文件是微软专有文件,最少是文档化的。









这篇关于【C++】了解PDB的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1137464

相关文章

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a

C++ vector的常见用法超详细讲解

《C++vector的常见用法超详细讲解》:本文主要介绍C++vector的常见用法,包括C++中vector容器的定义、初始化方法、访问元素、常用函数及其时间复杂度,通过代码介绍的非常详细,... 目录1、vector的定义2、vector常用初始化方法1、使编程用花括号直接赋值2、使用圆括号赋值3、ve

如何高效移除C++关联容器中的元素

《如何高效移除C++关联容器中的元素》关联容器和顺序容器有着很大不同,关联容器中的元素是按照关键字来保存和访问的,而顺序容器中的元素是按它们在容器中的位置来顺序保存和访问的,本文介绍了如何高效移除C+... 目录一、简介二、移除给定位置的元素三、移除与特定键值等价的元素四、移除满足特android定条件的元

Python获取C++中返回的char*字段的两种思路

《Python获取C++中返回的char*字段的两种思路》有时候需要获取C++函数中返回来的不定长的char*字符串,本文小编为大家找到了两种解决问题的思路,感兴趣的小伙伴可以跟随小编一起学习一下... 有时候需要获取C++函数中返回来的不定长的char*字符串,目前我找到两种解决问题的思路,具体实现如下:

C++ Sort函数使用场景分析

《C++Sort函数使用场景分析》sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变,如果某些场景需要保持相同元素间的相对顺序,可使... 目录C++ Sort函数详解一、sort函数调用的两种方式二、sort函数使用场景三、sort函数排序

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

C/C++错误信息处理的常见方法及函数

《C/C++错误信息处理的常见方法及函数》C/C++是两种广泛使用的编程语言,特别是在系统编程、嵌入式开发以及高性能计算领域,:本文主要介绍C/C++错误信息处理的常见方法及函数,文中通过代码介绍... 目录前言1. errno 和 perror()示例:2. strerror()示例:3. perror(

C++变换迭代器使用方法小结

《C++变换迭代器使用方法小结》本文主要介绍了C++变换迭代器使用方法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1、源码2、代码解析代码解析:transform_iterator1. transform_iterat

详解C++中类的大小决定因数

《详解C++中类的大小决定因数》类的大小受多个因素影响,主要包括成员变量、对齐方式、继承关系、虚函数表等,下面就来介绍一下,具有一定的参考价值,感兴趣的可以了解一下... 目录1. 非静态数据成员示例:2. 数据对齐(Padding)示例:3. 虚函数(vtable 指针)示例:4. 继承普通继承虚继承5.

C++中std::distance使用方法示例

《C++中std::distance使用方法示例》std::distance是C++标准库中的一个函数,用于计算两个迭代器之间的距离,本文主要介绍了C++中std::distance使用方法示例,具... 目录语法使用方式解释示例输出:其他说明:总结std::distance&n编程bsp;是 C++ 标准