设为首页 收藏本站
查看: 633|回复: 0

[经验分享] Windows程序调试系列: 使用VC++生成调试信息

[复制链接]

尚未签到

发表于 2016-5-21 12:10:14 | 显示全部楼层 |阅读模式
Windows程序调试系列: 使用VC++生成调试信息
ZhangTao,zhangtao.it@gmail.com, 译自 “Generating debug information with Visual C++”,Oleg Starodumov

出处: http://www.cnblogs.com/itrust/archive/2006/08/17/479603.aspx
引子
当我们使用调试器来调试程序时,我们希望能够单步调试到源代码中,在代码中设置断点,观察变量的值(包括用户自定义的复杂类型的值)。但是可执行文件只含有原始的字节数据——机器指令和操作系统执行程序时所使用的头信息和表信息。操作系统加载并运行可执行文件后,它根据不同的需求使用不同片段的内存(栈、堆)存放数据,其中的存放的依然是原始的字节数据。那么,调试器如何知道当前CPU指令对应哪一行代码?如何知道堆栈中的地址对应哪一个函数的局部变量?答案是“调试信息”,调试信息是高级编程语言和运行程序的原始字节数据之间的桥梁。
名词解释
   位置(location):在不同的情况有不同的含义。对于函数而言,是函数首字节的地址;对于全局和静态变量而言,是内存中变量的首字节;对局部变量和函数参数而言,通常是该变量的首字节相对于函数堆栈的预先定义的基址的偏移。另外,其他类型的位置也可能出现,如:寄存器、TLS slot(参见:http://www.blogcn.com/u2/38/94/silannyukun/blog/37069531.html)、元数据标记(metadata token, 参见http://naoku.net/blogs/framesniper/archive/2005/04/12/1910.aspx)。
FPO (frame pointer omission):帧指针省略,FPO用来链接CodeView或PDB符号。它在编译器没有用EBP寄存器生成标准堆栈桢(a standard stack frame) 的地方帮助调试器查找函数的参数和本地变量。
调试信息的类型
   我们只讨论在Intel X86平台上的现有的由微软提供的调试器。
  信息的类型
  描述
  公共函数和变量
  用于描述在多个的编译单元(源代码文件)中可见的函数和变量,调试信息保存每个函数和变量的位置(location)和名称。
  私有函数和变量
  用于描述除公共函数和变量以外的所有函数和变量,包括静态函数、静态和局部变量、函数参数),调试信息保存每个函数和变量的位置、大小和名称。
  源文件和代码行信息
  用于将每一行代码映射到可执行文件的某个位置上。当然,某些代码行不能做映射,如注释行,这样的代码行在调试信息中不做体现。
  类型信息
  用于存储每一个函数和变量的类型信息。对于变量或函数参数,类型信息能够告诉调试器它是整型还是字符串类型,或是用户自定义的类型。对于函数,类型信息记载了参数的个数、调用转换和返回值的类型。
  FPO信息
  对于做了FPO优化的函数,调试信息保存了一些数据来帮助调试器确定函数堆栈帧的大小,甚至在帧指针无效时也能工作。 如果没有FPO信息,调试器无法正确显示被优化的程序的调用堆栈。
  编辑和继续执行信息
  用于帮助Visual Studio IDE在调试时实现编辑和继续执行的功能

调试信息格式
   现在来探索调试信息是如何存储的。在过去的十年中,微软开发工具使用了几种不同的格式来包装调试信息。这里我们讨论COFF、CodeView和应用的最广泛的PDB(Program Database)格式。在讨论每种格式时,我们从下列几个特性着手:

  • 哪些类型的调试信息可以通过该格式保存?
  • 调试信息究竟保存在哪里(在可执行文件中,还是单独的一个文件)?
  • 该格式是否有文档说明?
COFF
   COFF是这里要涉及的所有格式中最古老的一种,它只能保存三种调试信息: 公共函数和变量,源文件和代码行信息,FPO信息。COFF总是保存在可执行文件中,不能够单独保存在其他文件中。该格式的文档说明参见:微软可移植可执行和通用对象文件格式规范.
CodeView
   CodeView是较COFF更新的而且更复杂的一种格式,它可以存储除编辑和继续执行信息外的所有类型的调试信息。CodeView通常保存在可执行文件中,它也可从可执行文件中导出到一个单独的文件(.DGB文件)。CodeView文档不全,其文档可以在MSDN中的VC++5.0符号调试信息规范(Symbolic Debug Information Specification)中找到。
Program Database 程序数据库
   这是三种中最新的一种调试信息格式,可以存储所有类型的调试信息(包括编辑和继续执行信息),也支持增量编译(其余两种格式不支持)。程序数据库信息保存在一个单独的.PDB文件中。遗憾的是,微软没有提供程序数据库格式的文档,只提供特殊的编程接口DbgHelp 和DIA来访问它。目前,程序数据库格式有两个版本,第一版(PDB2.0)为VC6.0所用,第二版(PDB 7.0)被Visual Studio.NET采用。PDB 7.0不能向上兼容,也就是说:VC6.0不能读取PDB 7.0格式。
  三种格式对比如下:
  格式
  是否有文档
  存储
  公共函数和变量
  私有函数和变量
  源文件和代码行信息
  类型信息
  FPO 信息
  编辑和继续执行信息
  COFF
  
  可执行文件中
  +
  -
  +
  -
  +
  -
  CodeView
  部分
  可执行文件中
  或.DBG文件中
  +
  +
  +
  +
  +
  -
  Program Database
  
  .PDB文件中
  +
  +
  +
  +
  +
  +

生成调试信息
构造(build)过程
   一个典型的可执行文件的构造过程包含两步:编译和链接。首先,编译器分析源文件,生成机器指令(保存在.obj对象文件中);然后链接器将所有可用的对象文件合并到最终的可执行文件。在对象文件之外,链接器也会用到库文件(库文件也是其他一些对象文件的汇集)。整个构造过程如下图:
   DSC0000.gif
   如果我们想要为可执行文件生成调试信息,也得经历两步:首先,编译器为每一个源文件创建调试信息;然后,链接器合并由编译器创建得调试信息,如下图:
   DSC0001.gif
   缺省状态下,编译器和链接器不会产生调试信息。因此我们必须通过编译和链接选项来要求编译器和链接器生成调试信息,我们也可以指定生成哪些类型得调试信息,使用什么调试信息格式,将调试信息保存在什么地方。
   接下来,我讨论具体得编译器和链接器选项。
Visual C++ 6.0
编译器 Compiler
  有下列选项:
/Zd 生成COFF格式的调试信息,保存在对象文件中
/Z7 生成CodeView格式的调试信息,保存在对象文件中
/Zi 生成程序数据库格式的调试信息,保存在.PDB文件中
/ZI 与 /Zi 基本一致, 唯一不同的是调试信息中包含编辑和继续执行信息
缺省时,/Zi 和 /ZI 选项生成的PDB文件名为VC60.PDB,也可以使用/Fd指定文件名。
  选项
  格式
  存储文件
  内容
  /Zd
  COFF
  .OBJ


  • 公共函数和变量
  • 源文件和代码行信息
  • FPO信息
  /Z7
  CodeView
  .OBJ


  • 公共函数和变量
  • 私有函数和变量
  • 源文件和代码行信息
  • 类型信息
  • FPO信息
  /Zi
  Program Database
  .PDB


  • 公共函数和变量
  • 私有函数和变量
  • 源文件和代码行信息
  • 类型信息
  • FPO信息
  /ZI
  Program Database
  .PDB


  • 公共函数和变量
  • 私有函数和变量
  • 源文件和代码行信息
  • 类型信息
  • FPO信息
  • 编辑和继续执行信息

链接器Linker
  下列选项可用:
  /debug 告诉链接器生成调试信息,如果该选项不使用,则其他所有选项都无效
  /debugtype 指定调试信息格式,可能的用法包括:
   /debugtype:coff COFF格式。注意:该选项下,调试信息中不包含源文件和代码行信息
   /debugtype:cv CodeView或程序数据库格式。究竟是哪一种格式,由/pdb决定
   /debugtype:both 同时使用COFF格式和CodeView/程序数据库格式
  /pdb 决定是CodeView还是程序数据库格式。/pdb:none 表示CodeView格式,/pdb:filename(如/pdb:myexe.pdb)表示使用程序数据库格式,文件名为myexe.pdb。在/debugtype:coff 选项下,/pdb 选项无效。
  /pdbtype 该选项只在一个或多个对象文件或库文件的调试信息也保存在一个单独的PDB文件中。/pdbtype:sept 选项可以使得调试信息各自保存在各自的PDB文件中,这样可以加快链接速度,不利的是调试信息分散,调试时需要多个PDB文件。相对的,/pdbtype:con 选项使得所有调试信息都保存在与可执行文件对应的最终的PDB文件中。
  为便于理解各个选项的配对使用,请见下表:
  /debugtype
  /pdb
  格式
  存储
  coff
  /pdb:none (无效)
  COFF
  在可执行文件中
  coff
  /pdb:filename (无效)
  COFF
  在可执行文件中
  cv
  /pdb:none
  CodeView
  在可执行文件中
  cv
  /pdb:filename
  Program Database
  .PDB 文件
  both
  /pdb:none
  COFF and CodeView
  在可执行文件中
  both
  /pdb:filename
  COFF and Program Database
  COFF 信息在可执行文件中, 程序数据库信息在 .PDB 文件中

Visual C++.NET (2002 and 2003)
编译器 Compiler
  下列选项可用:
  /Z7 生成CodeView格式的调试信息,保存在对象文件中
/Zd, /Zi 和 /ZI都表示生成程序数据库格式的调试信息,保存在.PDB文件中. 不同之处是调试信息的内容(见下表)。
缺省时,/Zd,/Zi 和 /ZI 选项生成的PDB文件名为VC70.PDB或VC71.PDB,也可以使用/Fd指定文件名。
注意: VC++.NET 编译器不支COFF。
  选项
  格式
  存储
  内容
  /Z7
  CodeView
  .OBJ


  • 公共函数和变量
  • 私有函数和变量
  • 源文件和代码行信息
  • 类型信息
  • FPO信息
  /Zd
  Program Database
  .PDB


  • 公共函数和变量
  • 源文件和代码行信息
  • FPO信息
  /Zi
  Program Database
  .PDB


  • 公共函数和变量
  • 私有函数和变量
  • 源文件和代码行信息
  • 类型信息
  • FPO信息
  /ZI
  Program Database
  .PDB


  • 公共函数和变量
  • 私有函数和变量
  • 源文件和代码行信息
  • 类型信息
  • FPO信息
  • 编辑和继续执行信息

链接器Linker
  下列选项可用:
  /debug告诉链接器生成调试信息,如果该选项不使用,则其他所有选项都无效。调试信息的格式总是程序数据库格式,保存在PDB文件中。缺省的,链接器使用可执行文件名生成PDB文件名。PDB文件名可包含所有调试信息的变量内容。
  /pdb 指定PDB文件名.
  /pdbstripped 允许链接器生成附加的PDB文件,该文件的内容限定于:

  • 公共函数和变量
  • FPO信息
  注意: COFF 和 CodeView 格式不被 VC++.NET链接器支持。
静态库的调试信息
   由于没有连接过程,静态库的调试信息的生成比可执行文件要简单的多。不考虑编译器版本(VC6 或 VS.NET),我们可以使用(/Zd, /Z7, /Zi, /ZI)中一个选项通知编译器为静态库生成调试信息。
   关键问题是将调试信息保存在什么地方。当使用/Z7或/Zd选项时,调试信息保存在.LIB文件中;当使用/Zi或/ZI选项时,调试信息保存在.PDB文件中(当然可以使用/Fd指定文件名)。
调试信息对可执行文件的大小的影响
   调试信息对可执行文件的大小的影响,决定于存储调试信息的地方,也间接的决定于所使用的格式。
   COFF和CodeView格式下,调试信息保存在可执行文件中,因此可执行文件的大小将显著增长(通常要增长一倍以上,甚至更大)。
   程序数据库格式下,调试信息单独保存,对可执行文件的大小几乎没有影响。在这种情况下,可执行文件需要保存一个头信息方便调试器对调试信息进行定位,因此需要增长大约几百个字节。
   要避免可执行文件的膨胀,我们需要在使用/debug 同时,将/opt:ref 选项改为opt:noref。这样做,有一个另外的结果就是关闭了链接器的大小优化。如果要恢复大小优化,需要改回/opt:ref。
.DBG 文件
   使用一个小工具——Rebase——可以将CodeView格式的内容从可执行文件中导出,存入到DBG文件中。Rebase包含在Visual Studio中。除了用于导出DBG文件外,它还有其他的一些用途。如果用于导出DBG文件,其命令行格式为:
  rebase –b BaseAddr –x SymbolDir [-p] ExeName
  选项
  描述
<nobr><p><span>-b BaseAddr</span></p></nobr>  指定可执行文件的基地址,如果你不想更改基地址,就指定当前可执行文件所使用的地址
<nobr><p><span>-x SymbolDir</span></p></nobr>  制定存放.DBG文件的目录, 使用“.”表示当前目录
  -p
  如果该选项被使用,DBG文件只包含公共函数和变量和FPO信息

   例如:下面的命令行从DLL中导出调试信息到当前目录下的DBG文件中: rebase –b 0x60000000 –x . MyDll.dll
调试器和调试信息的格式
   通用的调试器支持的格式如下:
  调试器
  COFF
  CodeView
  Program Database (2.0)
  Program Database (7.0)
  Visual Studio.NET
  -
  +
  +
  +
  Visual C++ 6.0
  +
  +
  +
  -
  WinDbg 6.3
  +
  部分支持
  +
  +

   WinDbg 6.3 部分支持CodeView格式,它只能读取下列信息:

  • 公共函数和变量
  • FPO信息
  • 源文件和代码行信息
   它可以单步进入源代码,看到调用堆栈,但无法观察变量的值(因此类型信息不被支持).
操作系统符号文件(symbols)
   Windows操作系统所公开的调试系统格式如下:
  操作系统
  格式
<nobr><p><span>Windows NT 4.0</span></p></nobr>  CodeView (.DBG files)
<nobr><p><span>Windows 2000</span></p></nobr>  CodeView (.DBG files) and Program Database (2.0)
<nobr><p><span>Windows XP</span></p></nobr>(including SP1 and SP1a)  Program Database (2.0)
<nobr><p><span>Windows XP SP2</span></p></nobr>  Program Database (7.0)
<nobr><p><span>Windows 2003 Server</span></p></nobr>  Program Database (2.0)

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-219926-1-1.html 上篇帖子: Windows Mobile BLOG 问题集锦 2006-9-25 下篇帖子: 用C语言编写Windows服务程序的五个步骤
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表