剥离调试信息
程序发布时,总是会把调试信息从程序中移除,另存到一个文件中,一则是减少发布程序的大小,二则是保护信息。
一般的步骤如下(demo就是程序名):
objcopy --only-keep-debug demo demo.debuginfo
,读取demo中的调试信息保存到demo.debuginfo文件中。objcopy --strip-debug demo
,从demo中移除一下调试信息。使用readelf -S
查看前后的section,可以发现缺少了以下section(PS:这些section只有在编译时加了-g
参数时才会有)。
> [27] .debug_aranges PROGBITS 0000000000000000 00001061
> 0000000000000030 0000000000000000 0 0 1
> [28] .debug_info PROGBITS 0000000000000000 00001091
> 00000000000000bb 0000000000000000 0 0 1
> [29] .debug_abbrev PROGBITS 0000000000000000 0000114c
> 0000000000000069 0000000000000000 0 0 1
> [30] .debug_line PROGBITS 0000000000000000 000011b5
> 0000000000000042 0000000000000000 0 0 1
> [31] .debug_str PROGBITS 0000000000000000 000011f7
-
objcopy --add-gnu-debuglink demo.debuginfo demo
,在demo中增加一个叫做.gnu_debuglink
的section,其中保存了保存调试信息文件的名字和CRC校验值。
剥离符号信息
为了更彻底地减小程序大小和保护信息,可以使用objcopy --strip-all demo
,不止删除调试信息还删除符号表,此时用nm
命令是无法获取符号信息的,对比objcopy --strip-debug demo
后的程序,主要是多删了程序中的以下section。
> [28] .symtab SYMTAB 0000000000000000 00001170
> 00000000000005d0 0000000000000018 29 41 8
> [29] .strtab STRTAB 0000000000000000 00001740
> 0000000000000228 0000000000000000 0 0 1
gdb调试
说一下gdb是如何根据.gnu_debuglink
查找调试信息文件的
For the “debug link” method, GDB looks up the named file in the directory of the executable file, then in a subdirectory of that directory named .debug, and finally under each one of the global debug directories, in a subdirectory whose name is identical to the leading directories of the executable’s absolute file name.
通过strace gdb a.out
的输出得到以下信息验证了一下
open("/root/gdb/a.out.debug", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/root/gdb/.debug/a.out.debug", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/debug//root/gdb/a.out.debug", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/debug/root/gdb/a.out.debug", O_RDONLY) = -1 ENOENT (No such file or directory)
- 程序所在目录(尝试过从在其他目录下启动gdb,仍然是在程序所在目录)
- 程序所在目录的
.debug
目录 /usr/lib/debug/程序绝对路径
- 不知道和上一种有什么区别
不论是只剥离了调试信息还是将调试信息和符号都剥离了,只要有调试信息文件,并将其放在上述任一目录下,就可以用gdb调试。
demo.debuginfo是一个ELF文件
[root@localhost ~]# file demo.debuginfo
demo.debuginfo: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=3c390d31af9856f59d1817b5eeefce937dc0ef78, not stripped
通过readelf -S demo.debuginfo
,可看到其包含了以下section
[28] .debug_aranges PROGBITS 0000000000000000 000002c5
0000000000000030 0000000000000000 0 0 1
[29] .debug_info PROGBITS 0000000000000000 000002f5
0000000000000091 0000000000000000 0 0 1
[30] .debug_abbrev PROGBITS 0000000000000000 00000386
0000000000000042 0000000000000000 0 0 1
[31] .debug_line PROGBITS 0000000000000000 000003c8
000000000000003a 0000000000000000 0 0 1
[32] .debug_str PROGBITS 0000000000000000 00000402
00000000000000aa 0000000000000001 MS 0 0 1
[33] .symtab SYMTAB 0000000000000000 000004b0
0000000000000678 0000000000000018 34 52 8
[34] .strtab STRTAB 0000000000000000 00000b28
00000000000001c8 0000000000000000 0 0 1
[35] .shstrtab STRTAB 0000000000000000 00000cf0
000000000000014c 0000000000000000 0 0 1
这些sesion说明通过objcopy --only-keep-debug
命令生成的文件不止包含了调试信息,还包含了符号信息。