生成可调试的Release版本二进制文件--调试符号信息提取和附加调试链接section

本文讲的是不编译完全release的可执行文件,而是使用cmakeRelWithDebugInfo(附加调试信息的编译,它的效果下面会说明)或者Debug编译也可以生成release版本的可执行文件进行调试.

详细的 cmake 使用会在下一篇文章里讲.

这里先记下Debug, Release 和 RelWithDebugInfo的区别(对比我手上的gcc 4.8.2编译出的不同版本得出的结论)

  • Debug 等同于 -O0 -g 编译选项, 不优化代码, 附加调试信息
  • Release 等同于 -O3 编译选项, 最大化优化代码, 但不包含调试信息
  • RelWithDebugInfo 等同于 -O2 -g 编译选项, 中等程度优化代码, 并且包含调试信息.

可以自定义使用-O3 -g 的编译选项,来生成最接近Release的代码(至于-ggdb的选项,加了以后二进制只大了8个字节,目测无所谓)

下面的方法只对-g编译有效,方法有两种.

  1. man手册里推荐的方法

    • objcopy –only-keep-debug foo foo.dbg 把调试信息(即debug section)dump到单独的文件里.
    • objcopy –strip-debug foo 这里只剔除调试信息,符号信息仍保留(用户依然可以用nm查看到各种函数符号,我推荐用–strip-all,连同符号信息一起删除,生成的可执行文件更小,不影响调试)
    • objcopy –add-gnu-debuglink=foo.dbg foo 为foo添加.gnu-debuglink section, 这个会让二进制增加近100字节的样子.
      这样分离了Debug Section后,就可以单独分发release版本的foo,调试时只需讲foo.dbg放在和foo同一目录下即可直接gdb foo进行调试.
  2. 如果不希望Release的最终二进制文件包含.gnu-debuglink段,那么可以直接省略第三步,且当成另一种方法,方便叙述.

    • 同一
    • strip foo 这个效果等同于objcopy –strip-all foo,剔除所有符号和调试信息, 即为release版本.

方法二所不同的调试方法是需先加载dbg文件, gdb foo.dbg, 然后attach(或者exec)到foo进程,这样不要求.dbg和执行程序在同一个目录下,并且适合调试已经启动的进程,例如服务器.