Linux平台下保留调试信息

40 views

在Linux平台下编程,构建动态库、可执行文件时,增加调试信息,可以在编译选项中增加-g
而去除动态库、可执行文件中保留的调试信息,可以使用strip命令,比如对于动态库,可以执行命令strip foo.so

现在问题来了。
对客户发布版本时,期望发布给客户的软件及压缩包尽量小,这样有如下好处:

  • 降低下载时文件传输的时间开销。
  • 降低解压文件时的时间开销。
  • 降低解压后文件占用硬盘的空间。

对于此类诉求,常规操作是:

  • 分析软件包的构成。
  • 罗列各类组成部分占用空间的大小。
  • 针对空间占用情况,倒排列表。
  • 对症下药,制订对口的优化策略。

针对软件包中的动态库和可执行文件,可行的对策有如下:

  • 裁剪不必要的构建目标。
  • 编译选项中增加空间优化选项,比如-Os
  • 编译选项中增加-ffunction-sections -fdata-sections,链接选项中增加-Wl,--gc-sections
  • 合并动态库、可执行文件,在链接选项中增加LTO相关的选项,比如-flto
  • 去除符号表,编译选项中去掉-g选项,或者使用strip命令。

去除符号表后,无疑会影响问题定位的效率,或者说增加定位问题时的成本。
假如在编译时去掉-g选项,获取到客户反馈的dump文件后,需要使用相同版本的源码、相同的编译执行机、相同的构建目录等条件下重新编译版本,才有可能在查看dump文件时,读取到正常的符号信息。
不过上述方法虽然美好,但存在一个潜在的问题,编译时增加-g和去除-g,生成的代码可能是有差异的,这样可能导致dump文件和重新构建得到可执行文件、动态库文件不匹配,进而导致解析dump文件失败。

所以,最好的办法是在构建时保留-g选项,构建完毕之后,得到带有调试符号的版本;然后使用命令strip对生成的动态库、可执行文件处理,进而在相同的版本基础上,得到不带调试符号的版本。

这样,客户收到的是不带调试信息的版本,软件包比较小;而项目组保留了带有调试信息的版本,遇到dump问题时,可以直接用于分析问题。
两不耽误,这样挺好。
缺点在于发布一个版本时,需要同时归档两个交付件,验证的工作量和版本服务器上的硬盘空间,都会double。

这里介绍另外一个方法,操作步骤很简单:

  • 使用-g选项构建版本。
  • 使用命名objcopy从动态库和可执行文件中提取调试信息。
  • 归档软件包和调试信息。

使用命令objcopy的操作序列如下:

objcopy --only-keep-debug foo foo.dbg
objcopy --strip-debug foo
objcopy --add-gnu-debuglink=foo.dbg foo

上述命令的作用,可以参见objcopy使用指导,这里摘抄如下:

Strip a file, removing contents of any sections that would not be stripped by –strip-debug and leaving the debugging sections intact. In ELF files, this preserves all note sections in the output.

Note – the section headers of the stripped sections are preserved, including their sizes, but the contents of the section are discarded. The section headers are preserved so that other tools can match up the debuginfo file with the real executable, even if that executable has been relocated to a different address space.

The intention is that this option will be used in conjunction with –add-gnu-debuglink to create a two part executable. One a stripped binary which will occupy less space in RAM and in a distribution and the second a debugging information file which is only needed if debugging abilities are required. The suggested procedure to create these files is as follows:

  1. Link the executable as normal. Assuming that it is called foo then…
  2. Run objcopy –only-keep-debug foo foo.dbg to create a file containing the debugging info.
  3. Run objcopy –strip-debug foo to create a stripped executable.
  4. Run objcopy –add-gnu-debuglink=foo.dbg foo to add a link to the debugging info into the stripped executable.

Note—the choice of .dbg as an extension for the debug info file is arbitrary. Also the –only-keep-debug step is optional. You could instead do this:

Link the executable as normal.

  1. Copy foo to foo.full
  2. Run objcopy –strip-debug foo
  3. Run objcopy –add-gnu-debuglink=foo.full foo

i.e., the file pointed to by the –add-gnu-debuglink can be the full executable. It does not have to be a file created by the –only-keep-debug switch.

Note—this switch is only intended for use on fully linked files. It does not make sense to use it on object files where the debugging information may be incomplete. Besides the gnu_debuglink feature currently only supports the presence of one filename containing debugging information, not multiple filenames on a one-per-object-file basis.

参考资料



若非注明,均为原创,欢迎转载,转载请注明来源:Linux平台下保留调试信息

关于 JackieAtHome

基层程序员,八年之后重新启航

此条目发表在 工作总结 分类目录,贴了 , 标签。将固定链接加入收藏夹。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

Protected with IP Blacklist CloudIP Blacklist Cloud