【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

相关文章

关于数据埋点,你需要了解这些基本知识

产品汪每天都在和数据打交道,你知道数据来自哪里吗? 移动app端内的用户行为数据大多来自埋点,了解一些埋点知识,能和数据分析师、技术侃大山,参与到前期的数据采集,更重要是让最终的埋点数据能为我所用,否则可怜巴巴等上几个月是常有的事。   埋点类型 根据埋点方式,可以区分为: 手动埋点半自动埋点全自动埋点 秉承“任何事物都有两面性”的道理:自动程度高的,能解决通用统计,便于统一化管理,但个性化定

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

【C++高阶】C++类型转换全攻略:深入理解并高效应用

📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C++ “ 登神长阶 ” 🤡往期回顾🤡:C++ 智能指针 🌹🌹期待您的关注 🌹🌹 ❀C++的类型转换 📒1. C语言中的类型转换📚2. C++强制类型转换⛰️static_cast🌞reinterpret_cast⭐const_cast🍁dynamic_cast 📜3. C++强制类型转换的原因📝

C++——stack、queue的实现及deque的介绍

目录 1.stack与queue的实现 1.1stack的实现  1.2 queue的实现 2.重温vector、list、stack、queue的介绍 2.1 STL标准库中stack和queue的底层结构  3.deque的简单介绍 3.1为什么选择deque作为stack和queue的底层默认容器  3.2 STL中对stack与queue的模拟实现 ①stack模拟实现

c++的初始化列表与const成员

初始化列表与const成员 const成员 使用const修饰的类、结构、联合的成员变量,在类对象创建完成前一定要初始化。 不能在构造函数中初始化const成员,因为执行构造函数时,类对象已经创建完成,只有类对象创建完成才能调用成员函数,构造函数虽然特殊但也是成员函数。 在定义const成员时进行初始化,该语法只有在C11语法标准下才支持。 初始化列表 在构造函数小括号后面,主要用于给