Archive for the ‘Continous integration’ Category

Debug symbols in separate files on Linux via boost bjam

July 12, 2015

Surprisingly many developers I have met do not realize the significance of debug symbols and how they should  be handled. This is especially true when it comes to release builds.

Those who do realize the need of resymbolication of customer crash dumps have a problem of how to generate them to separate files. They need to be in separate files because you don’t want to ship debug symbols with your software (because they are big and for other reasons).

Boost bjam does not support this out of the box. Weather the symbols will be stripped (or generated in the first place) in bjam depends on <debug-symbols> feature value. This feature is off for release builds by default but can be enabled explicitly.

Assuming that debug symbols are kept in shared object file or executable we can separate debug symbols, strip and add pointer to the binary so that debugger finds them later. This can be done by leveraging objcopy and is described here.

To get this working in bjam we need to modify gcc.jam file.

First we need to register .so.debug and .debug types:

# Should be called PDB on Windows. Also prefixes should not be set on windows or cygwin
type.register SO_DEBUG : so.debug ;
type.set-generated-target-prefix SO_DEBUG : gcc : lib ;
type.register DEBUG : debug ;

Then we need to modify generator so that it produces two files: .debug and executable and so.debug and shared library:


generators.register
[ new gcc-linking-generator gcc.link
: LIB OBJ
: DEBUG EXE
: gcc ] ;
generators.register
[ new gcc-linking-generator gcc.link.dll
: LIB OBJ
: SO_DEBUG SHARED_LIB
: gcc ] ;

Now, we modify the actions to add additional steps to save debug information to .debug file before stripping. We also add gnu link so that debuggers can find external debug information bits:

actions link bind LIBRARIES
{
"$(CONFIG_COMMAND)" -L"$(LINKPATH)" -Wl,$(RPATH_OPTION:E=-R)$(SPACE)-Wl,$(RPATH) -Wl,-rpath-link$(SPACE)-Wl,"$(RPATH_LINK)" -o "$(<[-1])" $(START-GROUP) "$(>)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) -l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) $(OPTIONS) $(USER_OPTIONS)
objcopy --only-keep-debug "$(<[-1])" "$(<[-1]).debug"
strip --strip-debug --strip-unneeded "$(<[-1])"
objcopy --add-gnu-debuglink="$(<[-1]).debug" "$(<[-1])"
}

And the same for shared library:


# Differs from 'link' above only by -shared.
actions link.dll bind LIBRARIES
{
"$(CONFIG_COMMAND)" -L"$(LINKPATH)" -Wl,$(RPATH_OPTION:E=-R)$(SPACE)-Wl,$(RPATH) "$(.IMPLIB-COMMAND)$(<[1])" -o "$(<[-1])" $(HAVE_SONAME)-Wl,$(SONAME_OPTION)$(SPACE)-Wl,$(<[-1]:D=) -shared $(START-GROUP) "$(>)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) -l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) $(OPTIONS) $(USER_OPTIONS)
objcopy --only-keep-debug "$(<[-1])" "$(<[-1]).debug"
strip --strip-debug --strip-unneeded "$(<[-1])"
objcopy --add-gnu-debuglink="$(<[-1]).debug" "$(<[-1])"
}

Here is the link to differences in github.

Problems with the above solution: 

Note that above changes will cause linking with rpath to misbehave. If you know how to fix it, please let me know. I tried reversing EXE and DEBUG (and changing -1 to -2) but this caused problems with relink rule of exe. Not sure how to fix this one other than setting <install-type>EXE to narrow down targets. Also relinking will cause .debug files to be created next to executable anyway so this hack really needs some honing.

Advertisements