gnu ld/gdb: separate debug files. How to produce the debug file when there's too much debug info to link?

Peeter Joot picture Peeter Joot · May 7, 2013 · Viewed 7k times · Source

There's now gdb and binutils support for separating debug info from the binaries to be debugged. Docs describing this can be found in:

After a bit of experimenting, I'm able to get gdb (7.6) to find the debug info using either the build-id and debug-link methods. Here's two gdb fragments that show the debugger finding the debug info in the non-standard locations, using the build-id and debug-link methods respectively:

(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.

To create the debug info files I've used objcopy and strip. I've included details of such commands below for reference.

However, the reason I'm looking at this at all is with the hope of being able to build all of our product code with -g. Currently this breaks the debugger if we try since our shared-lib is too big with relocation truncated to fit messages like:

/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'

(and subsequent link failure)

Does anybody know of a way to do one of:

  1. Generate a standalone file containing all the debug info from the sources that contribute to the binary (i.e all the .o's and .a's that end up in the ld command that generates the binary).
  2. Or, instruct ld to link without including this debug info in the binary itself, and generate a standalone debug file that can be identified with a build-id or debug-link? I don't see anything in the docs for a single pass method to do this with ld, but the ld docs are big and perhaps I missed it.
  3. Some way to deal with the truncation error above (such a method would allow either the build-id or debug-link methods to work).

sample commands to generate separate debug files for an executable

Here's a sample command line sequence using both the --build-id and --add-gnu-debuglink methods:

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

where copyDebugAndStrip is the following perl code:

#!/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 ;

Answer

Peeter Joot picture Peeter Joot · May 8, 2013

Initially it appeared that the binutils gold linker was capable of building large -g shared libs, providing a solution for (3) above, however, it turns out that is because of a lack of error checking.

On the other hand it looks like work on (1) and (2) is in available if a bleeding edge toolchain is used, part of the fission dwarf/binutils/gcc work described here:

This fission work was mentioned in discussion of a bugzilla report on this relocation truncation error:

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

An example of the use of this split debug files is:

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

where gcc/g++ are version 4.8, the binutils trunk (cvs -z 9 -d :pserver:[email protected]:/cvs/src co binutils) has been used configured with --enable-gold=default, and finally using gdb version 7.6 which can read the split debug info.

Joining gcc in the party, the intel (version 16) compiler supports -gsplit-dwarf. The intel compiler documents that binutils-2.24+,gdb-7.6.1+ are required. The clang compiler codebase has some split dwarf support, but I don't know what state that support is in.