独立的调试符号文件
也许,我们还记得各大Linux发型版提供的debuginfo安装包,比如fedora:http://fedoraproject.org/wiki/Packaging:Debuginfo,这种将可执行程序与调试符号分离的方案好处多多。一方面,缩减了可执行程序的文件大小,在一定程度上提高了程序的执行性能,另一方面,对应的调试符号文件也方便了一些不时之需。本文就来看一下与此相关的两个问题。
一,如何给应用程序创建对应的调试符号文件?
这很简单,看个演示实例。有代码如下:
[root@lenky gdb]# cat t.c #include <stdio.h> int main(int argc, char *argv[]) { printf("Hello world!\n"); return 0; }
依次执行命令如下:
[root@lenky gdb]# ls -l total 4 -rw-r--r--. 1 root root 103 Mar 20 07:52 t.c [root@lenky gdb]# gcc -g t.c -o t [root@lenky gdb]# ls -l total 12 -rwxr-xr-x. 1 root root 7717 Mar 20 07:58 t -rw-r--r--. 1 root root 103 Mar 20 07:52 t.c [root@lenky gdb]# objcopy --only-keep-debug t t.debuginfo [root@lenky gdb]# objcopy --strip-debug t [root@lenky gdb]# objcopy --add-gnu-debuglink=t.debuginfo t [root@lenky gdb]# ls -l total 20 -rwxr-xr-x. 1 root root 6470 Mar 20 07:58 t -rw-r--r--. 1 root root 103 Mar 20 07:52 t.c -rwxr-xr-x. 1 root root 6109 Mar 20 07:58 t.debuginfo
OK,可执行程序t和对应的调试符号文件t.debuginfo就生成了。
几条命令,给以分别解释一下:
1,gcc -g t.c -o t
这个无需多说,值得注意的是,-g和-O2可以同时使用。
2,objcopy –only-keep-debug t t.debuginfo
将可执行程序文件t内的与调试相关的信息拷贝到文件t.debuginfo内。也可以这样:
cp t t.debuginfo strip --only-keep-debug t.debuginfo
3,objcopy –strip-debug t
删除可执行程序文件t内的调试相关信息。也可以直接使用strip命令,不过strip命令会把symtab也删除掉,导致在没有debuginfo文件的情况下,打印堆栈信息会受到影响,比如变得不那么清晰。
4,objcopy –add-gnu-debuglink=t.debuginfo t
在可执行程序文件t内添加一个名为.gnu_debuglink的section段,该段内包含有debuginfo文件的name名称和checksum校验和,以确保后续在进行实际调试时,可执行程序和对应的调试符号文件是一致的。
在参考1链接里,某牛给了一个shell脚本,那么整个过程可以直接这样:
[root@lenky gdb]# cat cdbi.sh #!/bin/bash scriptdir=`dirname ${0}` scriptdir=`(cd ${scriptdir}; pwd)` scriptname=`basename ${0}` set -e function errorexit() { errorcode=${1} shift echo $@ exit ${errorcode} } function usage() { echo "USAGE ${scriptname} <tostrip>" } tostripdir=`dirname "$1"` tostripfile=`basename "$1"` if [ -z ${tostripfile} ] ; then usage errorexit 0 "tostrip must be specified" fi cd "${tostripdir}" debugdir=.debug debugfile="${tostripfile}.debug" if [ ! -d "${debugdir}" ] ; then echo "creating dir ${tostripdir}/${debugdir}" mkdir -p "${debugdir}" fi echo "stripping ${tostripfile}, putting debug info into ${debugfile}" objcopy --only-keep-debug "${tostripfile}" "${debugdir}/${debugfile}" strip --strip-debug --strip-unneeded "${tostripfile}" objcopy --add-gnu-debuglink="${debugdir}/${debugfile}" "${tostripfile}" chmod -x "${debugdir}/${debugfile}" [root@lenky gdb]# !gcc gcc -g t.c -o t [root@lenky gdb]# ./cdbi.sh t stripping t, putting debug info into t.debug [root@lenky gdb]# ls -l .debug/ total 8 -rw-r--r--. 1 root root 6109 Mar 20 08:33 t.debug [root@lenky gdb]# ls -la total 28 drwxr-xr-x. 3 root root 4096 Mar 20 08:33 . drwxr-xr-x. 3 root root 4096 Mar 20 07:49 .. -rwxr-xr-x. 1 root root 874 Mar 20 08:31 cdbi.sh drwxr-xr-x. 2 root root 4096 Mar 20 08:33 .debug -rwxr-xr-x. 1 root root 4360 Mar 20 08:33 t -rw-r--r--. 1 root root 103 Mar 20 07:52 t.c
二,如何使用gdb调试带有调试符号文件的应用程序?
其实想想也知道,这只需解决一个问题,即如何把应用程序与调试符号文件关联起来。
gdb会按照一定的规则去搜索对应路径,找寻应用程序的调试符号文件,比如gdb会自动查找可执行程序所在目录下的.debug文件夹:
[root@lenky ~]# pwd /root [root@lenky ~]# gdb /home/work/gdb/t -q Reading symbols from /home/work/gdb/t...Reading symbols from /home/work/gdb/.debug/t.debug...done. done. (gdb)
拷贝到/tmp目录执行试试:
[root@lenky ~]# cp /home/work/gdb/t /tmp/ [root@lenky ~]# gdb /tmp/t -q Reading symbols from /tmp/t...Missing separate debuginfo for /tmp/t Try: yum --disablerepo='*' --enablerepo='*-debuginfo' install /usr/lib/debug/.build-id/01/f1df7f4971caacd934aca9523c4e4b5ae95332.debug (no debugging symbols found)...done. (gdb) q
提示找不到调试符号文件,把.debug文件夹也拷贝过去就OK了:
[root@lenky ~]# cp -r /home/work/gdb/.debug/ /tmp/ [root@lenky ~]# gdb /tmp/t -q Reading symbols from /tmp/t...Reading symbols from /tmp/.debug/t.debug...done. done. (gdb)
把调试符号文件放到同一个目录也可以:
[root@lenky ~]# rm -fr /tmp/.debug/ [root@lenky ~]# cp /home/work/gdb/.debug/t.debug /tmp/ [root@lenky ~]# gdb /tmp/t -q Reading symbols from /tmp/t...Reading symbols from /tmp/t.debug...done. done. (gdb)
下面再介绍另外几种主动设置方法:
1,通过gdb启动参数-s指定:
[root@lenky ~]# gdb -s /home/work/gdb/.debug/t.debug -e /tmp/t -q Reading symbols from /home/work/gdb/.debug/t.debug...done. (gdb)
注意:可执行程序必须通过-e指定,否则貌似gdb会拿它覆盖-s参数,比如如下:
[root@lenky ~]# gdb -s /home/work/gdb/.debug/t.debug /tmp/t -q Reading symbols from /tmp/t...Missing separate debuginfo for /tmp/t Try: yum --disablerepo='*' --enablerepo='*-debuginfo' install /usr/lib/debug/.build-id/01/f1df7f4971caacd934aca9523c4e4b5ae95332.debug (no debugging symbols found)...done. (gdb)
可以看到,gdb直接尝试从文件/tmp/t内读取符号了,而不是文件t.debug。
2,利用gdb的命令设置搜索路径:set debug-file-directory directories
这是gdb官方文档提到的,可以设置搜索路径的命令,但是貌似并没有起作用,或者是我漏掉了什么。具体不说了,请看参考5。
参考:
1,How to generate gcc debug symbol outside the build target?
http://stackoverflow.com/questions/866721/how-to-generate-gcc-debug-symbol-outside-the-build-target
2,Creating separate debug info
https://blogs.oracle.com/dbx/entry/creating_separate_debug_info
3,man objcopy
4,.gnu_debuglink or Debugging system libraries with source code
https://blogs.oracle.com/dbx/entry/gnu_debuglink_or_debugging_system
5,18.2 Debugging Information in Separate Files
http://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
6,http://www.technovelty.org/code/separate-debug-info.html
转载请保留地址:http://lenky.info/archives/2013/04/29/2261 或 http://lenky.info/?p=2261
备注:如无特殊说明,文章内容均出自Lenky个人的真实理解而并非存心妄自揣测来故意愚人耳目。由于个人水平有限,虽力求内容正确无误,但仍然难免出错,请勿见怪,如果可以则请留言告之,并欢迎来讨论。另外值得说明的是,Lenky的部分文章以及部分内容参考借鉴了网络上各位网友的热心分享,特别是一些带有完全参考的文章,其后附带的链接内容也许更直接、更丰富,而我只是做了一下归纳&转述,在此也一并表示感谢。关于本站的所有技术文章,欢迎转载,但请遵从CC创作共享协议,而一些私人性质较强的心情随笔,建议不要转载。
法律:根据最新颁布的《信息网络传播权保护条例》,如果您认为本文章的任何内容侵犯了您的权利,请以或书面等方式告知,本站将及时删除相关内容或链接。