From a924c0eb95c787a36e5c5e9ad61f6fc8541882b8 Mon Sep 17 00:00:00 2001 From: Guillaume Girol Date: Thu, 29 May 2025 12:00:00 +0000 Subject: [PATCH 01/10] separateDebugInfo: add symlinks to executable and source for debuginfod support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A debuginfod support must be able to map a build-id to - debug symbols - the original elf file for which the debug symbols where separated - the corresponding source files Currently, hydra provides an index from build-id to the nar of the debug output containing the debug symbols. Add symlinks in these outputs so that we can recover the store path of the source and original elf file. We can then fetch them by the normal binary cache protocol. About source files: to minimize storage demands, in the ideal case, software would be built from the source store path $src and the debuginfod server would just have to serve source files from this store path. In practice, source files are sometimes patched as part of the build. This commit stores the modified files in the debug output is a so called source overlay so that the debuginfod serve can serve the patched content of the file. The checksum was chosen as follows (where big is 4GB of zeros): $ hyperfine -L s sysv,bsd,crc,sha1,sha224,sha256,sha384,sha512,blake2b,sm3 'cksum -a {s} big' Benchmark 1: cksum -a sysv big Time (mean ± σ): 854.5 ms ± 270.5 ms [User: 245.3 ms, System: 601.8 ms] Range (min … max): 760.5 ms … 1623.8 ms 10 runs Warning: The first benchmarking run for this command was significantly slower than the rest (1.624 s). This could be caused by (filesystem) caches that were not filled until after the first run. You should consider using the '--warmup' option to fill those caches before the actual benchmark. Alternatively, use the '--prepare' option to clear the caches before each timing run. Benchmark 2: cksum -a bsd big Time (mean ± σ): 5.838 s ± 0.045 s [User: 5.118 s, System: 0.693 s] Range (min … max): 5.767 s … 5.897 s 10 runs Benchmark 3: cksum -a crc big Time (mean ± σ): 829.9 ms ± 28.6 ms [User: 274.5 ms, System: 551.0 ms] Range (min … max): 803.2 ms … 904.8 ms 10 runs Benchmark 4: cksum -a sha1 big Time (mean ± σ): 2.553 s ± 0.010 s [User: 1.912 s, System: 0.631 s] Range (min … max): 2.543 s … 2.575 s 10 runs Benchmark 5: cksum -a sha224 big Time (mean ± σ): 2.716 s ± 0.018 s [User: 2.054 s, System: 0.645 s] Range (min … max): 2.695 s … 2.743 s 10 runs Benchmark 6: cksum -a sha256 big Time (mean ± σ): 2.751 s ± 0.029 s [User: 2.057 s, System: 0.674 s] Range (min … max): 2.712 s … 2.812 s 10 runs Benchmark 7: cksum -a sha384 big Time (mean ± σ): 5.600 s ± 0.049 s [User: 4.820 s, System: 0.753 s] Range (min … max): 5.515 s … 5.683 s 10 runs Benchmark 8: cksum -a sha512 big Time (mean ± σ): 5.543 s ± 0.021 s [User: 4.751 s, System: 0.768 s] Range (min … max): 5.523 s … 5.579 s 10 runs Benchmark 9: cksum -a blake2b big Time (mean ± σ): 5.091 s ± 0.025 s [User: 4.306 s, System: 0.764 s] Range (min … max): 5.048 s … 5.125 s 10 runs Benchmark 10: cksum -a sm3 big Time (mean ± σ): 14.220 s ± 0.120 s [User: 13.376 s, System: 0.783 s] Range (min … max): 14.077 s … 14.497 s 10 runs Summary cksum -a crc big ran 1.03 ± 0.33 times faster than cksum -a sysv big 3.08 ± 0.11 times faster than cksum -a sha1 big 3.27 ± 0.11 times faster than cksum -a sha224 big 3.31 ± 0.12 times faster than cksum -a sha256 big 6.13 ± 0.21 times faster than cksum -a blake2b big 6.68 ± 0.23 times faster than cksum -a sha512 big 6.75 ± 0.24 times faster than cksum -a sha384 big 7.03 ± 0.25 times faster than cksum -a bsd big 17.13 ± 0.61 times faster than cksum -a sm3 big unfortunately, crc (and sysv) are not supported by --check, so they are disqualified. sha1 sha224 and sha256 are sensibly as fast as one another, so let's use a non broken one, even though cryptographic qualities are not needed here. --- doc/release-notes/rl-2511.section.md | 8 ++ .../setup-hooks/separate-debug-info.sh | 85 ++++++++++++++++--- 2 files changed, 82 insertions(+), 11 deletions(-) diff --git a/doc/release-notes/rl-2511.section.md b/doc/release-notes/rl-2511.section.md index f859a5197a7d..506b0376402b 100644 --- a/doc/release-notes/rl-2511.section.md +++ b/doc/release-notes/rl-2511.section.md @@ -31,6 +31,14 @@ - `vmalert` now supports multiple instances with the option `services.vmalert.instances."".enable` +- The debug outputs produced by `separateDebugInfo = true;` now contain symlinks mapping build-ids to the original source and ELF file. + Specifically, if `$out/bin/ninja` has build-id `483bd7f7229bdb06462222e1e353e4f37e15c293`, then + * `$debug/lib/debug/.build-id/48/3bd7f7229bdb06462222e1e353e4f37e15c293.executable` is a symlink to `$out/bin/ninja` + * `$debug/lib/debug/.build-id/48/3bd7f7229bdb06462222e1e353e4f37e15c293.source` is a symlink to the value of `$src` during build + * `$debug/lib/debug/.build-id/48/3bd7f7229bdb06462222e1e353e4f37e15c293.sourceoverlay` is a symlink to a directory with the same structure as the expanded `$sourceRoot` but containing only a copy of files which were patched during the build + * `$debug/lib/debug/.build-id/48/3bd7f7229bdb06462222e1e353e4f37e15c293.debug` is the file containing debug symbols (like before). + + ## Nixpkgs Library {#sec-nixpkgs-release-25.11-lib} diff --git a/pkgs/build-support/setup-hooks/separate-debug-info.sh b/pkgs/build-support/setup-hooks/separate-debug-info.sh index 4208aa481d0d..32c9b1a2cba6 100644 --- a/pkgs/build-support/setup-hooks/separate-debug-info.sh +++ b/pkgs/build-support/setup-hooks/separate-debug-info.sh @@ -3,18 +3,47 @@ export NIX_LDFLAGS+=" --compress-debug-sections=zlib" export NIX_CFLAGS_COMPILE+=" -ggdb -Wa,--compress-debug-sections" export NIX_RUSTFLAGS+=" -g -C strip=none" +cksumAlgo=sha256 + fixupOutputHooks+=(_separateDebugInfo) +postUnpackHooks+=(_recordPristineSourceHashes) + +_recordPristineSourceHashes() { + # shellcheck disable=2154 + [ -e "$sourceRoot" ] || return 0 + + local checksumFileName=__nix_source_checksums + echo "separate-debug-info: recording checksum of source files for debug support..." + find "$sourceRoot" -type f -exec cksum -a "$cksumAlgo" '{}' \+ > "$checksumFileName" + recordedSourceChecksumsFileName="$(readlink -f "$checksumFileName")" +} _separateDebugInfo() { + # shellcheck disable=2154 [ -e "$prefix" ] || return 0 - local dst="${debug:-$out}" - if [ "$prefix" = "$dst" ]; then return 0; fi + local debugOutput="${debug:-$out}" + if [ "$prefix" = "$debugOutput" ]; then return 0; fi # in case there is nothing to strip, don't fail the build - mkdir -p "$dst" + mkdir -p "$debugOutput" - dst="$dst/lib/debug/.build-id" + local dst="$debugOutput/lib/debug/.build-id" + + local source + local sourceOverlay + # shellcheck disable=2154 + if [ -e "$src" ]; then + source="$src" + if [ -n "${recordedSourceChecksumsFileName:-}" ]; then + sourceOverlay="$debugOutput/src/overlay" + else + sourceOverlay="" + fi + else + source="" + sourceOverlay="" + fi # Find executables and dynamic libraries. local i @@ -25,30 +54,64 @@ _separateDebugInfo() { [ -z "${OBJCOPY:-}" ] && echo "_separateDebugInfo: '\$OBJCOPY' variable is empty, skipping." 1>&2 && break # 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')" + local id + 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. echo "separating debug info from $i (build ID $id)" - destDir=$dst/${id:0:2} - destFile=$dst/${id:0:2}/${id:2}.debug + local debuginfoDir="$dst/${id:0:2}" + local buildIdPrefix="$debuginfoDir/${id:2}" + local debuginfoFile="$buildIdPrefix.debug" + local executableSymlink="$buildIdPrefix.executable" + local sourceSymlink="$buildIdPrefix.source" + local sourceOverlaySymlink="$buildIdPrefix.sourceoverlay" - mkdir -p "$destDir" + mkdir -p "$debuginfoDir" - if [ -f "$destFile" ]; then + if [ -f "$debuginfoFile" ]; then echo "separate-debug-info: warning: multiple files with build id $id found, overwriting" fi # This may fail, e.g. if the binary is for a different # architecture than we're building for. (This happens with # firmware blobs in QEMU.) - if $OBJCOPY --only-keep-debug "$i" "$destFile"; then + if $OBJCOPY --only-keep-debug "$i" "$debuginfoFile"; then # If we succeeded, also a create a symlink .debug. - ln -sfn ".build-id/${id:0:2}/${id:2}.debug" "$dst/../$(basename "$i")" + ln -sfn "$debuginfoFile" "$dst/../$(basename "$i")" + # also create a symlink mapping the build-id to the original elf file and the source + # debuginfod protocol relies on it + ln -sfn "$i" "$executableSymlink" + if [ -n "$source" ]; then + ln -sfn "$source" "$sourceSymlink" + fi + if [ -n "$sourceOverlay" ]; then + # create it lazily + if [ ! -d "$sourceOverlay" ]; then + echo "separate-debug-info: copying patched source files to $sourceOverlay..." + mkdir -p "$sourceOverlay" + pushd "$(dirname "$recordedSourceChecksumsFileName")" || { echo "separate-debug-info: failed to cd parent directory of $recordedSourceChecksumsFileName"; return 1; } + while IFS= read -r -d $'\0' modifiedSourceFile; do + if [ -z "$modifiedSourceFile" ]; then + continue + fi + # this can happen with files with '\n' in their name + if [ ! -f "$modifiedSourceFile" ]; then + echo "separate-debug-info: cannot save modified source file $modifiedSourceFile: does not exist. ignoring" + continue + fi + mkdir -p "$sourceOverlay/$(dirname "$modifiedSourceFile")" + cp -v "$modifiedSourceFile" "$sourceOverlay/$modifiedSourceFile" + done < <(LANG=C cksum -a "$cksumAlgo" --check --ignore-missing --quiet "$recordedSourceChecksumsFileName" 2>&1 | sed -n -e 's/: FAILED$/\x00/p' | sed -z -e 's/^\n//') + popd || { echo "separate-debug-info: failed to popd" ; return 1; } + fi + ln -sfn "$sourceOverlay" "$sourceOverlaySymlink" + fi else # If we failed, try to clean up unnecessary directories rmdir -p "$dst/${id:0:2}" --ignore-fail-on-non-empty From 318b8c61bdacb3e5c190c5ab3a7acdfecf8cf8dc Mon Sep 17 00:00:00 2001 From: Guillaume Girol Date: Thu, 29 May 2025 12:00:00 +0000 Subject: [PATCH 02/10] git: __structuredAttrs = true needed for separateDebugInfo --- pkgs/applications/version-management/git/default.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkgs/applications/version-management/git/default.nix b/pkgs/applications/version-management/git/default.nix index 4064b1a29c8f..1d103f9ff165 100644 --- a/pkgs/applications/version-management/git/default.nix +++ b/pkgs/applications/version-management/git/default.nix @@ -94,6 +94,7 @@ stdenv.mkDerivation (finalAttrs: { outputs = [ "out" ] ++ lib.optional withManual "doc"; separateDebugInfo = true; + __structuredAttrs = true; hardeningDisable = [ "format" ]; @@ -165,7 +166,7 @@ stdenv.mkDerivation (finalAttrs: { ]; # required to support pthread_cancel() - NIX_LDFLAGS = + env.NIX_LDFLAGS = lib.optionalString (stdenv.cc.isGNU && stdenv.hostPlatform.libc == "glibc") "-lgcc_s" + lib.optionalString (stdenv.hostPlatform.isFreeBSD) "-lthr"; From 4f3fd5b70e2fb50670f11e1da9d6310dcaf3f667 Mon Sep 17 00:00:00 2001 From: Guillaume Girol Date: Thu, 29 May 2025 12:00:00 +0000 Subject: [PATCH 03/10] openjdk: __structuredAttrs = true needed for separateDebugInfo = true --- pkgs/development/compilers/openjdk/generic.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/pkgs/development/compilers/openjdk/generic.nix b/pkgs/development/compilers/openjdk/generic.nix index f397a7c2105b..a6913dc9bdc8 100644 --- a/pkgs/development/compilers/openjdk/generic.nix +++ b/pkgs/development/compilers/openjdk/generic.nix @@ -428,6 +428,7 @@ stdenv.mkDerivation (finalAttrs: { buildFlags = if atLeast17 then [ "images" ] else [ "all" ]; separateDebugInfo = true; + __structuredAttrs = true; # -j flag is explicitly rejected by the build system: # Error: 'make -jN' is not supported, use 'make JOBS=N' From 832e521ef9bd5e28934511b64ce6ab0da62d8996 Mon Sep 17 00:00:00 2001 From: Guillaume Girol Date: Thu, 29 May 2025 12:00:00 +0000 Subject: [PATCH 04/10] python: __structuredAttrs = true needed by separateDebugInfo = true --- pkgs/development/interpreters/python/cpython/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/pkgs/development/interpreters/python/cpython/default.nix b/pkgs/development/interpreters/python/cpython/default.nix index 4cf35d59ad74..ed8a105a4d6e 100644 --- a/pkgs/development/interpreters/python/cpython/default.nix +++ b/pkgs/development/interpreters/python/cpython/default.nix @@ -788,6 +788,7 @@ stdenv.mkDerivation (finalAttrs: { ]; separateDebugInfo = true; + __structuredAttrs = true; passthru = passthru // { doc = stdenv.mkDerivation { From abe472daf38b1cead85e77cca94b1b867fa26b00 Mon Sep 17 00:00:00 2001 From: Guillaume Girol Date: Thu, 29 May 2025 12:00:00 +0000 Subject: [PATCH 05/10] systemd: __structuredAttrs = true neeeded by separateDebugInfo = true --- pkgs/os-specific/linux/systemd/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/pkgs/os-specific/linux/systemd/default.nix b/pkgs/os-specific/linux/systemd/default.nix index 5d89887378e7..80a9ae1bb550 100644 --- a/pkgs/os-specific/linux/systemd/default.nix +++ b/pkgs/os-specific/linux/systemd/default.nix @@ -331,6 +331,7 @@ stdenv.mkDerivation (finalAttrs: { "dev" ] ++ (lib.optional (!buildLibsOnly) "man"); separateDebugInfo = true; + __structuredAttrs = true; hardeningDisable = [ From f37801034aed8b67c485444b49589f419901a264 Mon Sep 17 00:00:00 2001 From: Guillaume Girol Date: Thu, 29 May 2025 12:00:00 +0000 Subject: [PATCH 06/10] mesa: __structuredAttrs = true needed by separateDebugInfo = true --- pkgs/development/libraries/mesa/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/pkgs/development/libraries/mesa/default.nix b/pkgs/development/libraries/mesa/default.nix index b2145088cbf8..db9ec5273585 100644 --- a/pkgs/development/libraries/mesa/default.nix +++ b/pkgs/development/libraries/mesa/default.nix @@ -205,6 +205,7 @@ stdenv.mkDerivation { # Keep build-ids so drivers can use them for caching, etc. # Also some drivers segfault without this. separateDebugInfo = true; + __structuredAttrs = true; # Needed to discover llvm-config for cross preConfigure = '' From a4d355342976e9e9823fb94f133bc43ebec9da5b Mon Sep 17 00:00:00 2001 From: Guillaume Girol Date: Thu, 29 May 2025 12:00:00 +0000 Subject: [PATCH 07/10] mkDerivation: disable reference whitelisting in debug outputs created by separateDebugInfo this output contains unpredictable references by design. It would nearly always break allowedReferences et al. As it's not intended to enter a real closure, but to be fetched on demand by buildid, disable reference whitelisting instead, but only for this output. This requires __structuredAttrs. Only a dozen derivations are affected in the whole of nixpkgs. --- pkgs/stdenv/generic/make-derivation.nix | 40 +++++++++++++++++++++---- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/pkgs/stdenv/generic/make-derivation.nix b/pkgs/stdenv/generic/make-derivation.nix index bc58907fbe5b..526c1746138d 100644 --- a/pkgs/stdenv/generic/make-derivation.nix +++ b/pkgs/stdenv/generic/make-derivation.nix @@ -324,7 +324,21 @@ let doCheck' = doCheck && stdenv.buildPlatform.canExecute stdenv.hostPlatform; doInstallCheck' = doInstallCheck && stdenv.buildPlatform.canExecute stdenv.hostPlatform; - separateDebugInfo' = separateDebugInfo && stdenv.hostPlatform.isLinux; + separateDebugInfo' = + let + actualValue = separateDebugInfo && stdenv.hostPlatform.isLinux; + conflictingOption = + attrs ? "disallowedReferences" + || attrs ? "disallowedRequisites" + || attrs ? "allowedRequisites" + || attrs ? "allowedReferences"; + in + if actualValue && conflictingOption && !__structuredAttrs then + throw "separateDebugInfo = true in ${ + attrs.pname or "mkDerivation argument" + } requires __structuredAttrs if {dis,}allowedRequisites or {dis,}allowedReferences is set" + else + actualValue; outputs' = outputs ++ optional separateDebugInfo' "debug"; noNonNativeDeps = @@ -646,10 +660,26 @@ let outputChecks = builtins.listToAttrs ( map (name: { inherit name; - value = zipAttrsWith (_: builtins.concatLists) [ - (makeOutputChecks attrs) - (makeOutputChecks attrs.outputChecks.${name} or { }) - ]; + value = + let + raw = zipAttrsWith (_: builtins.concatLists) [ + (makeOutputChecks attrs) + (makeOutputChecks attrs.outputChecks.${name} or { }) + ]; + in + # separateDebugInfo = true will put all sorts of files in + # the debug output which could carry references, but + # that's "normal". Notably it symlinks to the source. + # So disable reference checking for the debug output + if separateDebugInfo' && name == "debug" then + removeAttrs raw [ + "allowedReferences" + "allowedRequisites" + "disallowedReferences" + "disallowedRequisites" + ] + else + raw; }) outputs ); } From 24cd08426a07616f036b270643b0538e44b37123 Mon Sep 17 00:00:00 2001 From: Guillaume Girol Date: Thu, 29 May 2025 12:00:00 +0000 Subject: [PATCH 08/10] lix: __structuredAttrs = true required for separateDebugInfo --- pkgs/tools/package-management/lix/common-lix.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/pkgs/tools/package-management/lix/common-lix.nix b/pkgs/tools/package-management/lix/common-lix.nix index df64103e8a45..0bf781c8c2e1 100644 --- a/pkgs/tools/package-management/lix/common-lix.nix +++ b/pkgs/tools/package-management/lix/common-lix.nix @@ -128,6 +128,7 @@ stdenv.mkDerivation (finalAttrs: { # We don't want the underlying GCC neither! stdenv.cc.cc.stdenv.cc.cc ]; + __structuredAttrs = true; # We only include CMake so that Meson can locate toml11, which only ships CMake dependency metadata. dontUseCmakeConfigure = true; From b0d26fa2cdd3c8a5d298f94e3e0d19218b85c0c7 Mon Sep 17 00:00:00 2001 From: Guillaume Girol Date: Thu, 29 May 2025 12:00:00 +0000 Subject: [PATCH 09/10] autoPatchelfHook: teach it to avoid objects created by separateDebugInfo otherwise systemd fails to build because autoPatchelfHook patches libs with debug objects and this creates circular dependencies from out to debug (of course, debug depends on out) example of faulty behavior: searching for dependencies of /nix/store/c8cd7b82py02f0rkags351nhg82wwjm6-systemd-minimal-257.5/bin/systemd-delta libsystemd-shared-257.so -> found: /nix/store/icpqrawjhsw4fbi4i2hp7cxvf3kbzq7m-systemd-minimal-257.5-debug/lib/debug libc.so.6 -> found: /nix/store/7lyblga0bzjk0sl93vp4aiwbvb57vp2x-glibc-2.40-66/lib --- pkgs/build-support/setup-hooks/auto-patchelf.sh | 1 + pkgs/by-name/au/auto-patchelf/source/auto-patchelf.py | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/pkgs/build-support/setup-hooks/auto-patchelf.sh b/pkgs/build-support/setup-hooks/auto-patchelf.sh index 541b7fc694d0..9f195ceead82 100644 --- a/pkgs/build-support/setup-hooks/auto-patchelf.sh +++ b/pkgs/build-support/setup-hooks/auto-patchelf.sh @@ -95,6 +95,7 @@ autoPatchelfPostFixup() { if [[ -z "${dontAutoPatchelf-}" ]]; then autoPatchelf -- $(for output in $(getAllOutputNames); do [ -e "${!output}" ] || continue + [ "${output}" = debug ] && continue echo "${!output}" done) fi diff --git a/pkgs/by-name/au/auto-patchelf/source/auto-patchelf.py b/pkgs/by-name/au/auto-patchelf/source/auto-patchelf.py index 3426752fa55a..bf8882818dd9 100644 --- a/pkgs/by-name/au/auto-patchelf/source/auto-patchelf.py +++ b/pkgs/by-name/au/auto-patchelf/source/auto-patchelf.py @@ -42,6 +42,13 @@ def is_dynamic_executable(elf: ELFFile) -> bool: # section but their ELF type is DYN. return bool(elf.get_section_by_name(".interp")) +def is_separate_debug_object(elf: ELFFile) -> bool: + # objects created by separateDebugInfo = true have all the section headers + # of the unstripped objects but those that normal `strip` would have kept + # are NOBITS + text_section = elf.get_section_by_name(".text") + return elf.has_dwarf_info() and bool(text_section) and text_section.header['sh_type'] == "SHT_NOBITS" + def get_dependencies(elf: ELFFile) -> list[list[Path]]: dependencies = [] @@ -174,6 +181,10 @@ def populate_cache(initial: list[Path], recursive: bool =False) -> None: try: with open_elf(path) as elf: + if is_separate_debug_object(elf): + print(f"skipping {path} because it looks like a separate debug object") + continue + osabi = get_osabi(elf) arch = get_arch(elf) rpath = [Path(p) for p in get_rpath(elf) From d641797bed1d6d705f62f8cecc768547c2569f8b Mon Sep 17 00:00:00 2001 From: Guillaume Girol Date: Sat, 31 May 2025 12:00:00 +0000 Subject: [PATCH 10/10] release notes: document interactions between separateDebugInfo and ref blacklisting --- doc/release-notes/rl-2511.section.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/release-notes/rl-2511.section.md b/doc/release-notes/rl-2511.section.md index 506b0376402b..58262d34214b 100644 --- a/doc/release-notes/rl-2511.section.md +++ b/doc/release-notes/rl-2511.section.md @@ -19,6 +19,8 @@ - `gentium` package now provides `Gentium-*.ttf` files, and not `GentiumPlus-*.ttf` files like before. The font identifiers `Gentium Plus*` are available in the `gentium-plus` package, and if you want to use the more recently updated package `gentium` [by sil](https://software.sil.org/gentium/), you should update your configuration files to use the `Gentium` font identifier. - `space-orbit` package has been removed due to lack of upstream maintenance. Debian upstream stopped tracking it in 2011. +- Derivations setting both `separateDebugInfo` and one of `allowedReferences`, `allowedRequistes`, `disallowedReferences` or `disallowedRequisites` must now set `__structuredAttrs` to `true`. The effect of reference whitelisting or blacklisting will be disabled on the `debug` output created by `separateDebugInfo`. + - `gnome-keyring` no longer ships with an SSH agent anymore because it has been deprecated upstream. You should use `gcr_4` instead, which provides the same features. More information on why this was done can be found on [the relevant GCR upstream PR](https://gitlab.gnome.org/GNOME/gcr/-/merge_requests/67). ## Other Notable Changes {#sec-nixpkgs-release-25.11-notable-changes}