From ef44418895c5cc6d88955c158ee622a68c01842f Mon Sep 17 00:00:00 2001 From: pasta Date: Thu, 13 Nov 2025 12:58:05 -0600 Subject: [PATCH 1/6] guix: enable build-id on linux --- configure.ac | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/configure.ac b/configure.ac index f9138d39821e..6bae5a2b9efa 100644 --- a/configure.ac +++ b/configure.ac @@ -1128,6 +1128,11 @@ if test "$use_hardening" != "no"; then AX_CHECK_LINK_FLAG([-fPIE -pie], [PIE_FLAGS="-fPIE"; HARDENED_LDFLAGS="$HARDENED_LDFLAGS -pie"], [], [$CXXFLAG_WERROR]) fi +dnl Add build-id for perf and debug symbol matching (Linux only) +if test "$TARGET_OS" = "linux"; then + AX_CHECK_LINK_FLAG([-Wl,--build-id=sha1], [CORE_LDFLAGS="$CORE_LDFLAGS -Wl,--build-id=sha1"], [], [$LDFLAG_WERROR]) +fi + dnl These flags are specific to ld64, and may cause issues with other linkers. dnl For example: GNU ld will interpret -dead_strip as -de and then try and use dnl "ad_strip" as the symbol for the entry point. From 38934351e4d1c1eee1bba92f91bc3049225ed5b5 Mon Sep 17 00:00:00 2001 From: pasta Date: Thu, 13 Nov 2025 13:05:58 -0600 Subject: [PATCH 2/6] devtools: relax strip in split-debug.sh --- contrib/devtools/split-debug.sh.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/devtools/split-debug.sh.in b/contrib/devtools/split-debug.sh.in index 92b72b1446cf..7ad5f6ed5ad7 100644 --- a/contrib/devtools/split-debug.sh.in +++ b/contrib/devtools/split-debug.sh.in @@ -6,5 +6,5 @@ fi @OBJCOPY@ --enable-deterministic-archives -p --only-keep-debug $1 $3 @OBJCOPY@ --enable-deterministic-archives -p --strip-debug $1 $2 -@STRIP@ --enable-deterministic-archives -p -s $2 +@STRIP@ --enable-deterministic-archives -p --strip-debug --strip-unneeded $2 @OBJCOPY@ --enable-deterministic-archives -p --add-gnu-debuglink=$3 $2 From badabf970b624a1916f4ed41a21649a175fb04f8 Mon Sep 17 00:00:00 2001 From: pasta Date: Thu, 13 Nov 2025 13:06:53 -0600 Subject: [PATCH 3/6] build: enhance debug file handling on Linux - Added compression for DWARF sections in debug files. - Implemented creation of .build-id tree for automatic discovery by perf. - Added verification checks for build-ids and debug links in ELF files. --- contrib/guix/libexec/build.sh | 55 +++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh index 5f9b62e32cce..90a5238372fa 100755 --- a/contrib/guix/libexec/build.sh +++ b/contrib/guix/libexec/build.sh @@ -341,6 +341,61 @@ mkdir -p "$DISTSRC" find "${DISTNAME}/bin" -type f -executable -print0 find "${DISTNAME}/lib" -type f -print0 } | xargs -0 -P"$JOBS" -I{} "${DISTSRC}/contrib/devtools/split-debug.sh" {} {} {}.dbg + + case "$HOST" in + *linux*) + # Compress DWARF sections in debug files and set proper permissions + find "${DISTNAME}" -name "*.dbg" -type f -print0 | xargs -0 -P"$JOBS" -I{} sh -c ' + objcopy --compress-debug-sections=zlib "$1" "$1.tmp" && mv "$1.tmp" "$1" + chmod 644 "$1" + ' _ {} + + # Create .build-id tree for perf auto-discovery + mkdir -p "${DISTNAME}/usr/lib/debug/.build-id" + { + find "${DISTNAME}/bin" -type f -executable -print0 + find "${DISTNAME}/lib" -type f -print0 + } | while IFS= read -r -d '' elf; do + if file "$elf" | grep -q "ELF.*executable\|ELF.*shared object"; then + build_id=$(readelf -n "$elf" 2>/dev/null | awk '/Build ID/ {print $3; exit}') + if [ -n "$build_id" ] && [ -f "${elf}.dbg" ]; then + dir="${DISTNAME}/usr/lib/debug/.build-id/${build_id:0:2}" + mkdir -p "$dir" + cp "${elf}.dbg" "${dir}/${build_id:2}.debug" + chmod 644 "${dir}/${build_id:2}.debug" + fi + fi + done + + # Verify build-ids and debug links + { + find "${DISTNAME}/bin" -type f -executable -print0 + find "${DISTNAME}/lib" -type f -print0 + } | { + verification_failed=0 + while IFS= read -r -d '' elf; do + if file "$elf" | grep -q "ELF.*executable\|ELF.*shared object"; then + # Check for build-id + if ! readelf -n "$elf" 2>/dev/null | grep -q "Build ID"; then + echo "ERROR: No build-id found in $elf" >&2 + verification_failed=1 + fi + + # Check for .gnu_debuglink + if ! readelf --string-dump=.gnu_debuglink "$elf" >/dev/null 2>&1; then + echo "ERROR: No .gnu_debuglink found in $elf" >&2 + verification_failed=1 + fi + fi + done + + if [ "$verification_failed" -eq 1 ]; then + echo "ERROR: Verification failed - some ELF files are missing build-ids or debug links" >&2 + exit 1 + fi + } + ;; + esac ;; esac From 48446f9d71cc4dc5310203cdf325acd33eda97c7 Mon Sep 17 00:00:00 2001 From: pasta Date: Thu, 13 Nov 2025 19:14:35 -0600 Subject: [PATCH 4/6] fix: move the .debug files into the debug artifact --- contrib/guix/libexec/build.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh index 90a5238372fa..4438c3dc1246 100755 --- a/contrib/guix/libexec/build.sh +++ b/contrib/guix/libexec/build.sh @@ -432,12 +432,14 @@ mkdir -p "$DISTSRC" || ( rm -f "${OUTDIR}/${DISTNAME}-${HOST//x86_64-w64-mingw32/win64}-debug.zip" && exit 1 ) ;; *linux*) - find "${DISTNAME}" -not -name "*.dbg" -print0 \ + # Main (non-debug) tarball: exclude separate debug files and the build-id debug tree + find "${DISTNAME}" -not -name "*.dbg" -not -path "${DISTNAME}/usr/lib/debug/*" -print0 \ | sort --zero-terminated \ | tar --create --no-recursion --mode='u+rw,go+r-w,a+X' --null --files-from=- \ | gzip -9n > "${OUTDIR}/${DISTNAME}-${HOST}.tar.gz" \ || ( rm -f "${OUTDIR}/${DISTNAME}-${HOST}.tar.gz" && exit 1 ) - find "${DISTNAME}" -name "*.dbg" -print0 \ + # Debug tarball: include .dbg files and the build-id debug tree + find "${DISTNAME}" \( -name "*.dbg" -o -path "${DISTNAME}/usr/lib/debug/*" \) -print0 \ | sort --zero-terminated \ | tar --create --no-recursion --mode='u+rw,go+r-w,a+X' --null --files-from=- \ | gzip -9n > "${OUTDIR}/${DISTNAME}-${HOST}-debug.tar.gz" \ From 857f860a87aef646c7dd9ef6a32aecdd10b6194b Mon Sep 17 00:00:00 2001 From: pasta Date: Thu, 13 Nov 2025 21:32:37 -0600 Subject: [PATCH 5/6] fix: shellcheck linter --- contrib/guix/libexec/build.sh | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh index 4438c3dc1246..9ba96a33dc26 100755 --- a/contrib/guix/libexec/build.sh +++ b/contrib/guix/libexec/build.sh @@ -345,10 +345,7 @@ mkdir -p "$DISTSRC" case "$HOST" in *linux*) # Compress DWARF sections in debug files and set proper permissions - find "${DISTNAME}" -name "*.dbg" -type f -print0 | xargs -0 -P"$JOBS" -I{} sh -c ' - objcopy --compress-debug-sections=zlib "$1" "$1.tmp" && mv "$1.tmp" "$1" - chmod 644 "$1" - ' _ {} + find "${DISTNAME}" -name "*.dbg" -type f -print0 | xargs -0 -P"$JOBS" -I{} sh -c "objcopy --compress-debug-sections=zlib \"\$1\" \"\$1.tmp\" && mv \"\$1.tmp\" \"\$1\"; chmod 644 \"\$1\"" _ {} # Create .build-id tree for perf auto-discovery mkdir -p "${DISTNAME}/usr/lib/debug/.build-id" From 81cd24009bada4048b0fe44e617f6276dd555f7e Mon Sep 17 00:00:00 2001 From: pasta Date: Mon, 17 Nov 2025 11:28:01 -0600 Subject: [PATCH 6/6] fix: improve error handling in build script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix verification block to properly capture exit status and prevent build from continuing on failure. Change objcopy command to use && instead of semicolon to ensure chmod only runs if mv succeeds. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- contrib/guix/libexec/build.sh | 55 ++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh index 9ba96a33dc26..6408234d89f9 100755 --- a/contrib/guix/libexec/build.sh +++ b/contrib/guix/libexec/build.sh @@ -345,7 +345,7 @@ mkdir -p "$DISTSRC" case "$HOST" in *linux*) # Compress DWARF sections in debug files and set proper permissions - find "${DISTNAME}" -name "*.dbg" -type f -print0 | xargs -0 -P"$JOBS" -I{} sh -c "objcopy --compress-debug-sections=zlib \"\$1\" \"\$1.tmp\" && mv \"\$1.tmp\" \"\$1\"; chmod 644 \"\$1\"" _ {} + find "${DISTNAME}" -name "*.dbg" -type f -print0 | xargs -0 -P"$JOBS" -I{} sh -c "objcopy --compress-debug-sections=zlib \"\$1\" \"\$1.tmp\" && mv \"\$1.tmp\" \"\$1\" && chmod 644 \"\$1\"" _ {} # Create .build-id tree for perf auto-discovery mkdir -p "${DISTNAME}/usr/lib/debug/.build-id" @@ -365,32 +365,35 @@ mkdir -p "$DISTSRC" done # Verify build-ids and debug links - { - find "${DISTNAME}/bin" -type f -executable -print0 - find "${DISTNAME}/lib" -type f -print0 - } | { - verification_failed=0 - while IFS= read -r -d '' elf; do - if file "$elf" | grep -q "ELF.*executable\|ELF.*shared object"; then - # Check for build-id - if ! readelf -n "$elf" 2>/dev/null | grep -q "Build ID"; then - echo "ERROR: No build-id found in $elf" >&2 - verification_failed=1 - fi - - # Check for .gnu_debuglink - if ! readelf --string-dump=.gnu_debuglink "$elf" >/dev/null 2>&1; then - echo "ERROR: No .gnu_debuglink found in $elf" >&2 - verification_failed=1 + verification_output=$( + { + find "${DISTNAME}/bin" -type f -executable -print0 + find "${DISTNAME}/lib" -type f -print0 + } | { + verification_failed=0 + while IFS= read -r -d '' elf; do + if file "$elf" | grep -q "ELF.*executable\|ELF.*shared object"; then + # Check for build-id + if ! readelf -n "$elf" 2>/dev/null | grep -q "Build ID"; then + echo "ERROR: No build-id found in $elf" >&2 + verification_failed=1 + fi + + # Check for .gnu_debuglink + if ! readelf --string-dump=.gnu_debuglink "$elf" >/dev/null 2>&1; then + echo "ERROR: No .gnu_debuglink found in $elf" >&2 + verification_failed=1 + fi fi - fi - done - - if [ "$verification_failed" -eq 1 ]; then - echo "ERROR: Verification failed - some ELF files are missing build-ids or debug links" >&2 - exit 1 - fi - } + done + exit "$verification_failed" + } 2>&1 + ) + verification_status=$? + if [ "$verification_status" -ne 0 ]; then + echo "$verification_output" >&2 + exit 1 + fi ;; esac ;;