加载了对应的调试符号文件也看不了函数名?也许是 fastlink 搞的鬼

缘起

在上一次折腾的过程中遇到了一个小问题 —— 在使用 IDA 查看反汇编的时候,居然搜索不到相关的函数,在 windbg 中使用 x 命令也搜不到,即使加载了符号文件也搜不到。最后发现是 /debug:fastlink 选项导致的。

初遇问题

使用 IDA 打开 vs2017 编译出来的程序,查看反汇编代码,但是没有看到相关函数。

no-symbol-found-in-ida

最开始以为是 IDA 加载符号文件的问题,就想着在 windbg 中使用 x 命令看一下,没想到也查看不了。

no-symbol-found-with-x-command-in-windbg

感觉有些离谱,之前一直好好的,而且这个示例程序非常简单。于是,使用 vs2013 编译同样的代码,然后在 IDA 中查看反汇编的函数,一切正常。又试了试 vs2019,也一切正常。下图是使用 IDA 查看 vs2019 生成的程序的情况。

meaningful-symbol-in-ida

根据多年的经验,应该是 pdb 出问题了。难道是 vs2017 在生成 pdb 的过程中有 bug?不管是不是 bug,先看看 pdb 的内容,看看到底在哪里失败了。

查看 PDB 内容

github 上搜索 pdb,发现了几个有用的仓库。我列在这里,感兴趣的小伙伴儿可以点进去查看。

  • microsoft-pdb 微软官方介绍 pdb 文件格式的仓库。
  • PDBRipper 查看 pdb 程序
  • raw_pdb 查看 pdbc++ 库,可以基于此开发自己的工具。
  • formatPE 可以查看 PE 文件或者 PDB 文件格式的库。

因为 PDBRipper 不用编译即可使用,所以我决定先使用它查看 vs2017 生成的 pdb 文件。发现什么都没有。这是什么情况?赶紧试试 vs2013vs2019 生成的 pdb 文件,发现可以正确的列出很多符号。

view-pdb-vs2017-vs2019

至此,我更加怀疑是 vs2017 的问题。具体是什么问题呢?到底问题出在哪里呢?还是要跟踪一下解析过程才能知道。

既然有现成的工具和代码,就不用自己研究 pdb 文件格式,再根据格式写解析程序了。我没有跟踪 PDBRipper,而是直接调试的 raw_pdb

发现关键线索

使用 vs2019 打开 raw_pdb\build\RawPDB.sln,编译。编译成功后,修改解决方案启动工程并设置好调试参数,加载有问题的 pdb 文件进行调试。简单跟踪几步后,发现在下图中的位置报错返回了。

debug-raw_pdb-return-error

从提示看,不能正确解析 PDB 是因为生成 PDB 的时候使用了名为 /DEBUG:FASTLINK 的选项。

至此得到了一个非常重要的线索 —— /DEBUG:FASTLINK。赶紧 google 一下。

搜索

很快就搜到了以下两个非常有用的网址:

http://www.windbg.xyz/windbg/article/204-MSVC-Linker-Option---Generate-Debug-Info

https://devblogs.microsoft.com/cppblog/faster-c-build-cycle-in-vs-15-with-debugfastlink/

https://lists.llvm.org/pipermail/llvm-dev/2017-June/113903.html

根据以上文章,可以得到如下结论:

  • 为了提高链接速度,从 vs2015 开始引入了 /DEBUG:fastlink 选项。

  • 使用 /DEBUG:fastlink 编译选项生成的 PDBpartitial pdb,这种 pdb 缺少私有符号信息,但是可以提高链接速度。

  • Visual Studio 15 (也就是 vs2017)开始,/Debug:fastlink 将成为默认选项。/DEBUG 选项等同于 /DEBUG:fastlink

  • 可以通过 Linker -> Debugging -> Generate Debug Info 来设置使用 /DEBUG:fastlink 或者 /DEBUG:FULL

  • 可以通过 vs 安装目录下的 VC\bin 子目录下的 mspdbcmf.exe 工具从 partitial pdb 获得 full pdb

友情提示: 如果有小伙伴儿不清楚 vs 各个版本名称与版本号的对应关系,可以参考下图。vs-history

看完以上几篇文章基本明白了原因。

赶紧在 vs2017 中修改对应的设置为 /DEBUG:FULL,然后在 windbg 中使用 x 命令查看,果然出现了期待已久的函数。

view-symbol-in-windbg

当然,肯定也得用 mspdbcmf.exe 转换成 full pdb 试试,结果也是很 ok 的。

mspdbcmf-convert-partitial-pdb-to-full-pdb

说明

经过验证,使用 vs2019 新建工程后,Generate Debug Info 的默认选项是 /DEBUG。但是使用默认选项生成的程序在调试的时候,并不存在不能查看符号的问题。看来,vs2019 又把 /DEBUG 选项处理成 /DEBUG:FULL 了。

其它资源

在调查这个问题的时候还搜到一些相关的网址,感兴趣的小伙伴儿可以看一下。

下面这篇文章是译文,讲的是 /DEBUG:fastlink 在缩短链接时间上的好处。

https://www.topomel.com/archives/3221.html

下面这篇是国外网友遇到的不能使用 DIA SDK 读取使用 /DEBUG:fastlink 选项编译生成的 Partitial PDB 的问题。

https://developercommunity.visualstudio.com/t/dia-sdk-still-doesnt-support-debugfastlink/4631

下面这篇是国外网友遇到的,在使用 vtune 分析使用 /DEBUG:fastlink 选项编译的程序,加载符号文件导致的卡死问题。

https://community.intel.com/t5/Analyzers/Unable-to-load-pdb-files-after-profiling-using-VS2019/m-p/1165445

总结

  • 可以使用很多工具查看 pdb 的内容,比如 PDBRipper

  • 使用 /DEBUG:fastlink 可以降低链接所需要的时间。

  • 使用 /DEBUG:fastlink 生成的是 partitial pdb,这种 pdb 中并不包含缺少私有符号,调试的时候会有不能查看符号的问题。

  • 可以使用 mspdbcmf.exepartitial pdb 转换成 full pdb

BianChengNan wechat
扫描左侧二维码关注公众号,扫描右侧二维码加我个人微信:)
0%