Enable separate debug info

You can now pass

  separateDebugInfo = true;

to mkDerivation. This causes debug info to be separated from ELF
binaries and stored in the "debug" output. The advantage is that it
enables installing lean binaries, while still having the ability to
make sense of core dumps, etc.
This commit is contained in:
Eelco Dolstra 2015-09-17 15:24:32 +02:00
parent edee7f1720
commit ec5b66eb4a
6 changed files with 93 additions and 16 deletions

View File

@ -899,6 +899,34 @@ following:
phase.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>separateDebugInfo</varname></term>
<listitem><para>If set to <literal>true</literal>, the standard
environment will enable debug information in C/C++ builds. After
installation, the debug information will be separated from the
executables and stored in the output named
<literal>debug</literal>. (This output is enabled automatically;
you dont need to set the <varname>outputs</varname> attribute
explicitly.) To be precise, the debug information is stored in
<filename><replaceable>debug</replaceable>/lib/debug/.build-id/<replaceable>XX</replaceable>/<replaceable>YYYY…</replaceable></filename>,
where <replaceable>XXYYYY…</replaceable> is the <replaceable>build
ID</replaceable> of the binary — a SHA-1 hash of the contents of
the binary. Debuggers like GDB use the build ID to look up the
separated debug information.</para>
<para>For example, with GDB, you can add
<programlisting>
set debug-file-directory ~/.nix-profile/lib/debug
</programlisting>
to <filename>~/.gdbinit</filename>. GDB will then be able to find
debug information installed via <literal>nix-env
-i</literal>.</para>
</listitem>
</varlistentry>
</variablelist>
</section>

View File

@ -8,7 +8,9 @@ stdenv.mkDerivation rec {
sha256 = "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i";
};
doCheck = true;
doCheck = false;
separateDebugInfo = true;
meta = {
description = "A program that produces a familiar, friendly greeting";

View File

@ -0,0 +1,37 @@
export NIX_LDFLAGS+=" --build-id"
export NIX_CFLAGS_COMPILE+=" -ggdb"
dontStrip=1
fixupOutputHooks+=(_separateDebugInfo)
_separateDebugInfo() {
local dst="${debug:-$out}"
if [ "$prefix" = "$dst" ]; then return; fi
dst="$dst/lib/debug/.build-id"
# Find executables and dynamic libraries.
local -a files=($(find "$prefix" -type f -a \( -perm /0100 -o -name "*.so" -o -name "*.so.*" \)))
local i magic
for i in "${files[@]}"; do
# Skip non-ELF files.
exec 10< "$i"
read -n 4 -u 10 magic
if [[ "$magic" =~ ELF ]]; then echo FOO; fi
exec 10<&-
# Extract the Build ID. FIXME: there's probably a cleaner way.
local id="$(readelf -n "$i" | sed 's/.*Build ID: \([0-9a-f]*\).*/\1/; t; d')"
if [ "${#id}" != 40 ]; then
echo "could not find build ID of $i, skipping" >&2
continue
fi
# Extract the debug info.
header "separating debug info from $i (build ID $id)"
mkdir -p "$dst/${id:0:2}"
objcopy --only-keep-debug "$i" "$dst/${id:0:2}/${id:2}.debug"
strip --strip-debug "$i"
done
}

View File

@ -96,6 +96,10 @@ let
, meta ? {}
, passthru ? {}
, pos ? null # position used in error messages and for meta.position
, separateDebugInfo ? false
, outputs ? [ "out" ]
, __impureHostDeps ? []
, __propagatedImpureHostDeps ? []
, ... } @ attrs:
let
pos' =
@ -132,6 +136,13 @@ let
throwEvalHelp "Broken" "is not supported on ${result.system}"
else true;
outputs' =
outputs ++
(if separateDebugInfo then [ "debug" ] else []);
buildInputs' = buildInputs ++
(if separateDebugInfo then [ ../../build-support/setup-hooks/separate-debug-info.sh ] else []);
in
assert licenseAllowed attrs;
@ -140,18 +151,11 @@ let
["meta" "passthru" "crossAttrs" "pos"
"__impureHostDeps" "__propagatedImpureHostDeps"])
// (let
buildInputs = attrs.buildInputs or [];
nativeBuildInputs = attrs.nativeBuildInputs or [];
propagatedBuildInputs = attrs.propagatedBuildInputs or [];
propagatedNativeBuildInputs = attrs.propagatedNativeBuildInputs or [];
crossConfig = attrs.crossConfig or null;
__impureHostDeps = attrs.__impureHostDeps or [];
__propagatedImpureHostDeps = attrs.__propagatedImpureHostDeps or [];
# TODO: remove lib.unique once nix has a list canonicalization primitive
computedImpureHostDeps = lib.unique (lib.concatMap (input: input.__propagatedImpureHostDeps or []) (extraBuildInputs ++ buildInputs ++ nativeBuildInputs));
computedPropagatedImpureHostDeps = lib.unique (lib.concatMap (input: input.__propagatedImpureHostDeps or []) (propagatedBuildInputs ++ propagatedNativeBuildInputs));
computedImpureHostDeps =
lib.unique (lib.concatMap (input: input.__propagatedImpureHostDeps or []) (extraBuildInputs ++ buildInputs ++ nativeBuildInputs));
computedPropagatedImpureHostDeps =
lib.unique (lib.concatMap (input: input.__propagatedImpureHostDeps or []) (propagatedBuildInputs ++ propagatedNativeBuildInputs));
in
{
builder = attrs.realBuilder or shell;
@ -162,10 +166,10 @@ let
__ignoreNulls = true;
# Inputs built by the cross compiler.
buildInputs = if crossConfig != null then buildInputs else [];
buildInputs = if crossConfig != null then buildInputs' else [];
propagatedBuildInputs = if crossConfig != null then propagatedBuildInputs else [];
# Inputs built by the usual native compiler.
nativeBuildInputs = nativeBuildInputs ++ (if crossConfig == null then buildInputs else []);
nativeBuildInputs = nativeBuildInputs ++ (if crossConfig == null then buildInputs' else []);
propagatedNativeBuildInputs = propagatedNativeBuildInputs ++
(if crossConfig == null then propagatedBuildInputs else []);
} // ifDarwin {
@ -176,7 +180,9 @@ let
"/bin/sh"
];
__propagatedImpureHostDeps = computedPropagatedImpureHostDeps ++ __propagatedImpureHostDeps;
}))) (
} // (if outputs' != [ "out" ] then {
outputs = outputs';
} else { })))) (
{
# The meta attribute is passed in the resulting attribute set,
# but it's not part of the actual derivation, i.e., it's not

View File

@ -41,7 +41,9 @@ let
installFlags = "sysconfdir=$(out)/etc";
doInstallCheck = true;
doInstallCheck = false;
separateDebugInfo = true;
crossAttrs = {
postUnpack =

View File

@ -477,6 +477,8 @@ let
deps = [ makeWrapper ];
} ../build-support/setup-hooks/wrap-gapps-hook.sh;
separateDebugInfo = makeSetupHook { } ../build-support/setup-hooks/separate-debug-info.sh;
### TOOLS