如何窥探PDB的秘密?(How to Inspect the Content of a Program Database (PDB) File)

来源:互联网 发布:java split用法 空格 编辑:程序博客网 时间:2024/05/21 10:21

        How to Inspect the Content of a Program Database (PDB) File  翻译自:http://www.codeproject.com/Articles/37456/How-To-Inspect-the-Content-of-a-Program-Database-P

        标题写的不好,没有文学家的气质与修养,瞎看吧!

        简单点说就是查看PDB文件的内容,PDB是什么内容呢?使用VS系列编译器编译过程序的人都知道,生成一个PE文件的同时,编译器会生成对应的符号文件,符号文件的后缀名就是*.PDB。这个文件有什么用?使用VS或Windbg调试一个程序,尤其解决崩溃的bug时,有这个文件,会极大地降低调试的难度。废话不多说,如下为译文:

        ********************************华丽丽的分割线*****************************************

介绍

        作为Windows软件的开发者,Visual Studio 和/或 WinDbg等被我们广泛地用于源码单步调试,设置断点,观察变量以及其他相关的软件调试相关的任务中。我们设法了解使得调试器如何将源码映射到二进制PE文件上,以及单步进入很多运行时库的内部原理机制。为了达到这个目的,调试器使用程序数据库(PDB)文件用于托管以及非托管的代码的调试。对于托管的代码,由于很多调试信息被放到了PE文件的区段中,所以PDB包含较少的调试信息。

        文章有如下的几个目标:

                显示已存在的PDB文件,以及调试器如何使用它们。

                如何使用现有的技术获取PDB的内容。

                说明PDB文件在调试中的重要性,以及嵌入PDB文件的信息的种类。

                给出了一个工程,实现了一个DIA类的易用C++包装,以及一个PDB探测器前端。这是一系列关于PDB和对应执行PE的开始的部分。本篇文章主要是关于PDB文件,也即相关模块。

背景

        正如John Robbin在下面提到的文章中解释的一样,一个原生的C++ PDB文件包含了一些列的信息:

                public,private和static函数地址

                全局变量名字和地址

                参数和局部变量名字以及栈上的偏移

                源文件名字和代码行,等等信息

        .Net PDB文件仅仅包含了两种信息:(源自于John Robbin下面提到的文章中)

                源文件名字

                源文件源码行信息和变量名字

        所有的其他必要的信息都已将被编译到了.Net 的元数据中了,因此也没有在PDB文件中重复存放这些相同的信息了。

        对于不熟悉Windows Debug Interface Access,PDB以及本文中说的基本的思想,如下列出了一些必要的连接:

                PDB Files: What Every Developer Must Know (John Robbin) 
                Debug Interface Access SDK 
                Dia2dump Sample
                DIA SDK Question

        当编译调试信息时,一个可执行文件包含了两个与PDB相关的信息:

                GUID 与放在对应的PDB文件中的GUID匹配。

                PDB文件的路径,这个会在调试期间使用。

                

        当被调试的应用程序启动时,调试器会解析可执行文件,尝试获取对应的PDB文件来处理调试会话。上面的链接中解释了如何使用这些设置符号服务器。

如何使用代码

        本文的PDB工程中包含了三部分:

                PdbParser: C++ 工程,生成PdbParser.dll,它是DIA接口的封装

                PdbInspectorConsole:C++ Win32控制台工程,使用PdbParser 并且显示PDB文件对应的模块

                PdbInspector: C++ MFC 工程,使用PDBParser,并且显示PDB文件中所对应的模块,以及与模块相关的细节信息。

环境

        工程是在Windows Vista Ultimate 32bit上开发并测试通过。

类继承

        之前已经提到,微软的DIA SDK是一个基于COM的接口,用于处理PDB文件。使用这个SDK的问题是它包含了大量的接口和函数集合。本文给出的PdbParser抽象了这些细节,提供了一个简单的面向任务的接口集合。在这个版本中,PdbPaser集中于模块的收集。PdbParser被组织成了一些列抽象层,打开一个PDB文件需要两步:

        使用IPdbParserFactory::Create()函数实例化 PdbParser

IPdbParser* pIPdbParser = IPdbParserFactory::Create();

        使用IPdbParser::Open() 函数打开一个指定的文件:

IPdbParser* pIPdbParser = IPdbParserFactory::Create(); IPdbFile* pIPdbfile = pIPdbParser->OpenFile(L"test.pdb");
        获取PDB对应的模块的细节信息,需要如下的三个步骤:

                调用IPdbFile::GetModules()函数获取对应的PE文件

                使用IPdbModule::GetModuleDetails() 方法获取指定模块的细节信息

                使用IPdbModuleDetails 接口的可用函数,获取相应的信息        

//Traverse the Modulesvector<ipdbmodule*> vModules = pIPdbfile->GetModules();vector<ipdbmodule*>::iterator it = vModules.begin();for( ;it!=vModules.end();it++){    IPdbModule* pIPdbModule = *it;    wprintf(L"%ws\n", pIPdbModule->GetName().c_str());}
        要获取指定模块的源文件信息,需要通过下三个步骤:

                调用IPdbFile::GetModules()函数获取对应的PE文件

                使用IPdbModule::GetSourceFiles()方法获取指定模块对应的源文件

                使用IPdbSourceFile::GetFileName()函数获取源码文件名称

//Traverse the Source file Names collection.std::vector<ipdbsourcefile*> vSources = pIPdbModule->GetSourceFiles();std::vector<ipdbsourcefile*>::iterator it = vSources.begin();for( ;it!=vSources.end(); it++){    IPdbSourceFile* pIPdbSourceFile = *it;    wprintf(L"%ws\n", pIPdbSourceFile->GetFileName().c_str());}
        在最后一步,需要将PdbParser分配的资源释放掉。

                使用 IPdbParserFactory::Destroy() 函数释放分配的资源

IPdbParserFactory::Destroy(); 

        下图给出了访问的结构:

        

历史记录

        略

许可

        本文,以及附件源码和文件是遵从CPOL授权许可。


        对应的源码工程:

                源码下载

By Andy @ 2015-10-08  午

0 0
原创粉丝点击