gnu ld/gdb:单独的调试文件。当需要链接的调试信息过多时如何生成调试文件?

Posted

技术标签:

【中文标题】gnu ld/gdb:单独的调试文件。当需要链接的调试信息过多时如何生成调试文件?【英文标题】:gnu ld/gdb: separate debug files. How to produce the debug file when there's too much debug info to link? 【发布时间】:2013-05-06 23:30:11 【问题描述】:

现在gdbbinutils 支持将调试信息与要调试的二进制文件分开。可以在以下位置找到描述此内容的文档:

gdb: separate debug files objcopy --add-gnu-debuglink, --only-keep-debug ld --build-id

经过一番试验,我可以使用 build-id 和 debug-link 方法获得 gdb (7.6) 来查找调试信息。下面是两个gdb 片段,显示调试器在非标准位置查找调试信息,分别使用 build-id 和 debug-link 方法:

(gdb)  set debug-file-directory .
(gdb) file uWithBuildId
Reading symbols from /home/peeterj/build-id/uWithBuildId...Reading symbols from /home/peeterj/build-id/.build-id/2d/41caac1bcbeb65255abc3f35624cf9ed37791a.debug...done.


Reading symbols from /home/peeterj/build-id/uWithDebugLink...Reading symbols from /home/peeterj/build-id/uWithDebugLink.debug...done.

为了创建调试信息文件,我使用了objcopystrip。我在下面包含了此类命令的详细信息以供参考。

但是,我查看这个的原因是希望能够使用-g 构建我们的产品代码的所有。目前,如果我们尝试,这会破坏调试器,因为我们的共享库太大,重定位被截断以适应以下消息:

/usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../lib64/crtn.o:(.debug_aranges+0x6):     relocation truncated to fit: R_X86_64_32 against `.debug_info'

(以及随后的链接失败)

有没有人知道以下方法之一:

    生成一个独立文件,其中包含来自对二进制文件有贡献的源中的所有调试信息(即在生成二进制文件的ld 命令中结束的所有 .o 和 .a)。 或者,指示ld 在二进制文件本身中不包含此调试信息的情况下进行链接,并生成一个独立的调试文件,该文件可以通过构建ID 或调试链接进行识别?我在文档中没有看到任何关于使用 ld 执行此操作的单通道方法,但 ld 文档很大,也许我错过了。 处理上述截断错误的某种方法(这种方法将允许 build-id 或 debug-link 方法工作)。

为可执行文件生成单独的调试文件的示例命令

以下是使用--build-id--add-gnu-debuglink 方法的示例命令行序列:

g++ -g   -c -o u.o u.cpp
g++ -o uWithBuildId -Wl,--build-id u.o
g++ -o uWithDebugLink u.o
copyDebugAndStrip uWithBuildId
objcopy --only-keep-debug uWithDebugLink uWithDebugLink.debug
objcopy --add-gnu-debuglink=uWithDebugLink.debug uWithDebugLink
strip -g uWithDebugLink

其中 copyDebugAndStrip 是以下 perl 代码:

#!/usr/bin/perl

my $binary = $ARGV[0] ;
my @p = `objdump --section .note.gnu.build-id -s $binary | tail -2` ;
foreach (@p)

   chomp ;
   s/^ *[\da-f]+ *// ;
   s/  .*// ;
   s/ //g ;


my $buildid = "$p[0]$p[1]" ;
$buildid =~ /^(..)(.*)/ ;

my ($d, $r) = ($1, $2) ;

print "build-id for '$binary': $buildid\n" ;

my $cmd =
"mkdir -p .build-id/$d
rm -f .build-id/$d/$r.debug
objcopy --only-keep-debug $binary .build-id/$d/$r.debug
strip -g $binary
" ;

print $cmd ;
system $cmd ;

【问题讨论】:

【参考方案1】:

最初,binutilsgold 链接器似乎能够构建大型 -g 共享库,为上述 (3) 提供解决方案,但事实证明这是因为缺乏错误检查。

另一方面,如果使用最前沿的工具链,看起来 (1) 和 (2) 的工作是可用的,这里描述的裂变 dwarf/binutils/gcc 工作的一部分:

http://gcc.gnu.org/ml/gcc/2011-10/msg00326.html http://gcc.gnu.org/wiki/DebugFission

在讨论有关此重定位截断错误的 bugzilla 报告时提到了此裂变工作:

http://sourceware.org/bugzilla/show_bug.cgi?id=15444

使用这种拆分调试文件的一个例子是:

g++ -gsplit-dwarf -gdwarf-4   -c -o main.o main.cpp
gcc -gsplit-dwarf -gdwarf-4   -c -o d1/t1.o d1/t1.c
g++ -gsplit-dwarf -gdwarf-4   -c -o d2/t2.o d2/t2.cpp
gcc -Wl,--index-gdb main.o d1/t1.o d2/t2.o   -o main

其中gcc/g++ 是 4.8 版本,binutils 主干 (cvs -z 9 -d :pserver:anoncvs@sourceware.org:/cvs/src co binutils) 已使用 --enable-gold=default 配置,最后使用 gdb 版本 7.6,可以读取拆分调试信息。

加入gcc党,intel(16版)编译器支持-gsplit-dwarf。需要 binutils-2.24+,gdb-7.6.1+ 的 intel 编译器文档。 clang 编译器代码库有一些 split dwarf 支持,但我不知道该支持处于什么状态。

【讨论】:

【参考方案2】:

在使用 g++ (v6.3.0) + gold linker (v2.27) + “-g” 参数编译时,我遇到了类似的链接器问题。

staticlib.a(sharedlib.o):(.debug_loc+0x1d38):重定位被截断以适应:R_X86_64_32 反对 `.debug_info' staticlib.a(sharedlib.o):(.debug_loc+0x6c8c):输出中省略了额外的重定位溢出 collect2:错误:ld 返回 1 个退出状态 gmake: *** [exec_file] 错误 1 287.760u 35.837s 7:30.37 71.8% 0+0k 17217048+14932696io 0pf+0w

添加参数“-fdebug-types-section”修复了这个问题。

更多详情请访问:https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html

【讨论】:

以上是关于gnu ld/gdb:单独的调试文件。当需要链接的调试信息过多时如何生成调试文件?的主要内容,如果未能解决你的问题,请参考以下文章

如何将内核调试信息构建为单独的文件?

使用 GNU 链接器的正确方法

调试 GNU make

[QNX Hypervisor 2.2用户手册]7.1 使用GNU调试器(GDB)

嵌入式软件中GCC编译,汇编,链接,调试的作用

非 GNU 链接器是不是有与 GNU 链接器“--just-symbols”选项等效的选项?