From 31868844ed7cf83cf1b3bc44427fa9850d1173b1 Mon Sep 17 00:00:00 2001 From: Rong Bao Date: Thu, 23 Jul 2026 19:58:26 +0800 Subject: [PATCH] native/abnativeelf: make symbol stripping and debug info splitting orthogonal After this refactor, the semantics of ABSPLITDBG and ABSTRIP are: ABSPLITDBG: Split the debug information off the original ELF into an individual, new ELF object. The original ELF is also mutated in this case. This translates to "-d" of abelf_copy_dbg{,_parallel}. ABSTRIP: Strip off all symbols from the original ELF. This translates to "-s" of abelf_copy_dbg{,_parallel}. Any combinations of the two flags are now supported, thus making it possible to create ELFs with symbols retained and debug info separated. For Microsoft .{pdb,dbg} files, ABSPLITDBG move them into the desired directory, while ABSTRIP does nothing. --- filters/80-elf.sh | 13 ++-- filters/81-pdb.sh | 5 +- lib/default-defines.sh | 2 +- native/abnativeelf.cpp | 115 ++++++++++++++++++++++------------- native/abnativeelf.hpp | 10 +-- native/abnativefunctions.cpp | 30 +++++---- proc/01-core-defines.sh | 6 -- 7 files changed, 107 insertions(+), 74 deletions(-) diff --git a/filters/80-elf.sh b/filters/80-elf.sh index a0510ea..d0ffff9 100644 --- a/filters/80-elf.sh +++ b/filters/80-elf.sh @@ -17,12 +17,15 @@ BIN_DIRS=( filter_elf() { local _opts=() - if ! bool "$ABSTRIP"; then + if bool "$ABSTRIP"; then + _opts+=('-s') + else abinfo 'Not stripping ELF binaries as requested.' - _opts+=('-r') - elif ! bool "$ABSPLITDBG"; then - abinfo 'Not splitting ELF binaries as requested.' - _opts+=('-x') + fi + if bool "$ABSPLITDBG"; then + _opts+=('-d') + else + abinfo 'Not splitting ELF binaries as requested.' fi local _elf_path=() diff --git a/filters/81-pdb.sh b/filters/81-pdb.sh index 4eda6da..d1ff1c6 100644 --- a/filters/81-pdb.sh +++ b/filters/81-pdb.sh @@ -9,12 +9,9 @@ filter_pdb() { for f in "$i"/**/*.@(pdb|dbg); do if bool "$ABSPLITDBG"; then path="${f#"$PKGDIR"}" - abinfo "Saving Program Database file $f ..." + abinfo "Moving Program Database file $f ..." mkdir -p "$(dirname "$SYMDIR"/"$path")" mv "$f" "$SYMDIR"/"$path" - elif bool "$ABSTRIP"; then - abinfo "Dropping Program Database file $f ..." - rm "$f" fi done fi diff --git a/lib/default-defines.sh b/lib/default-defines.sh index 776e17f..8473ec8 100644 --- a/lib/default-defines.sh +++ b/lib/default-defines.sh @@ -15,7 +15,7 @@ ABCONFIGHACK=yes # Use config.{sub,guess} replacement for newer architectures? NOCARGOAUDIT=no # Audit Cargo (Rust) dependencies? NONPMAUDIT=no # Audit NPM dependencies? ABUSECMAKEBUILD=yes # Use cmake build for cmake* ABTYPEs? -ABSPLITDBG=yes # Automatically compile with -g and produce debug symbol package ($PKGNAME-dbg)? +ABSPLITDBG=yes # Automatically compile with -g and split out a debug symbol package ($PKGNAME-dbg)? ABBUILDDEPONLY=no # Avoid installing runtime dependencies when building? ABPATCHLAX=no # Disallow fuzzy patching ABSPIRAL=yes # Enable spiral provides generation diff --git a/native/abnativeelf.cpp b/native/abnativeelf.cpp index 50531dc..f0dca5a 100644 --- a/native/abnativeelf.cpp +++ b/native/abnativeelf.cpp @@ -686,12 +686,17 @@ int elf_copy_debug_symbols(const char *src_path, const char *dst_path, symbols.insert(result.needed_libs.begin(), result.needed_libs.end()); } - if (flags & AB_ELF_CHECK_ONLY) + bool split_debug = flags & AB_ELF_SPLIT_DEBUG; + bool strip_symbols = flags & AB_ELF_STRIP_SYMBOLS; + bool use_eu_strip = flags & AB_ELF_USE_EU_STRIP; + bool save_with_path = flags & AB_ELF_SAVE_WITH_PATH; + + if (!split_debug && !strip_symbols) return 0; if (!result.has_debug_info) { - // no debug info, strip only - flags |= AB_ELF_STRIP_ONLY; + // no debug info, don't split + split_debug = false; } switch (result.bin_type) { @@ -702,54 +707,63 @@ int elf_copy_debug_symbols(const char *src_path, const char *dst_path, // skip and also notify the caller return 1; case BinaryType::Static: - // skip static library - flags |= AB_ELF_STRIP_ONLY; + // Debug symbol splitting is unsupported for static libraries. + split_debug = false; // eu-strip can not handle static libraries - flags &= ~AB_ELF_USE_EU_STRIP; - args.emplace_back("-R"); - args.emplace_back(".gnu.lto*"); - args.emplace_back("--strip-debug"); - extra_args.emplace_back("--enable-deterministic-archives"); + use_eu_strip = false; + if (strip_symbols) { + args.emplace_back("-R"); + args.emplace_back(".gnu.lto*"); + args.emplace_back("--strip-debug"); + extra_args.emplace_back("--enable-deterministic-archives"); + } break; case BinaryType::Executable: - // strip all symbols - args.emplace_back("-s"); + if (strip_symbols) { + // strip all symbols + args.emplace_back("-s"); + } break; case BinaryType::Relocatable: // disable debug symbol saving for relocatables + split_debug = false; // also uses GNU binutils strip for compatibility - flags |= AB_ELF_STRIP_ONLY; - flags &= ~AB_ELF_USE_EU_STRIP; - args.emplace_back("--strip-debug"); - extra_args.emplace_back("--enable-deterministic-archives"); + use_eu_strip = false; + if (strip_symbols) { + args.emplace_back("--strip-debug"); + extra_args.emplace_back("--enable-deterministic-archives"); + } break; case BinaryType::Dynamic: case BinaryType::KernelObject: - extra_args.emplace_back("--strip-unneeded"); + if (strip_symbols) { + extra_args.emplace_back("--strip-unneeded"); + } break; } - fs::path final_path; - if (flags & AB_ELF_STRIP_ONLY) { + if (split_debug && strip_symbols) { + get_logger()->info(fmt::format( + "Splitting debug symbols and stripping symbols from {0}", src_path)); + } else if (split_debug) { get_logger()->info( - fmt::format("Stripping debug symbols from {0}", src_path)); + fmt::format("Splitting debug symbols from {0}", src_path)); + } else if (strip_symbols) { + get_logger()->info(fmt::format("Stripping symbols from {0}", src_path)); } else { - get_logger()->info( - fmt::format("Saving and stripping debug symbols from {0}", src_path)); - if (!result.has_debug_info) { - get_logger()->warning( - fmt::format("No debug symbols found in {0}", src_path)); - return -3; - } + return 0; + } - if (result.build_id.empty() && !(flags & AB_ELF_SAVE_WITH_PATH)) { + fs::path final_path; + if (split_debug) { + if (result.build_id.empty() && !save_with_path) { // For binaries without build-id, save with path - flags |= AB_ELF_SAVE_WITH_PATH; + save_with_path = true; get_logger()->warning(fmt::format( "No build id found in {0}. Saving with relative path", src_path)); } - if (flags & AB_ELF_SAVE_WITH_PATH) { + if (save_with_path) { final_path = fs::path{dst_path} / fs::path{src_path}.filename(); get_logger()->debug(fmt::format("Saving to {0}", final_path.string())); } else { @@ -760,9 +774,18 @@ int elf_copy_debug_symbols(const char *src_path, const char *dst_path, fs::create_directories(final_prefix); } - if (flags & AB_ELF_USE_EU_STRIP) { + if (use_eu_strip) { + if (!strip_symbols) { + const char *eu_strip_args[] = { + "eu-strip", "--strip-debug", "--reloc-debug-sections", + "-f", final_path.c_str(), src_path, + nullptr}; + return forked_execvp("eu-strip", + const_cast(eu_strip_args)); + } + args[0] = "eu-strip"; - if (!(flags & AB_ELF_STRIP_ONLY)) { + if (split_debug) { args.emplace_back("--reloc-debug-sections"); args.emplace_back("-f"); args.emplace_back(final_path.c_str()); @@ -771,21 +794,29 @@ int elf_copy_debug_symbols(const char *src_path, const char *dst_path, args.emplace_back(nullptr); return forked_execvp("eu-strip", const_cast(args.data())); } - if (!(flags & AB_ELF_STRIP_ONLY)) { - const auto path = final_path.string(); - const char *args[] = { + + if (split_debug) { + const char *objcopy_args[] = { "objcopy", "--only-keep-debug", "--compress-debug-sections=zstd", - src_path, path.c_str(), nullptr}; - int ret = forked_execvp("objcopy", const_cast(args)); + src_path, final_path.c_str(), nullptr}; + const int ret = + forked_execvp("objcopy", const_cast(objcopy_args)); if (ret != 0) { return ret; } } - args[0] = "strip"; - std::copy(extra_args.begin(), extra_args.end(), std::back_inserter(args)); - args.emplace_back(src_path); - args.emplace_back(nullptr); - return forked_execvp("strip", const_cast(args.data())); + + if (strip_symbols) { + args[0] = "strip"; + std::copy(extra_args.begin(), extra_args.end(), std::back_inserter(args)); + args.emplace_back(src_path); + args.emplace_back(nullptr); + return forked_execvp("strip", const_cast(args.data())); + } + + const char *strip_debug_args[] = {"strip", "--strip-debug", src_path, + nullptr}; + return forked_execvp("strip", const_cast(strip_debug_args)); } int elf_copy_to_symdir(const char *src_path, const char *dst_path, diff --git a/native/abnativeelf.hpp b/native/abnativeelf.hpp index 68aee4d..86fedc3 100644 --- a/native/abnativeelf.hpp +++ b/native/abnativeelf.hpp @@ -65,10 +65,10 @@ template class GuardedSet { std::unordered_set m_set; }; -constexpr int AB_ELF_STRIP_ONLY = 1 << 0; -constexpr int AB_ELF_USE_EU_STRIP = 1 << 1; -constexpr int AB_ELF_FIND_SO_DEPS = 1 << 2; -constexpr int AB_ELF_CHECK_ONLY = 1 << 3; +constexpr int AB_ELF_SPLIT_DEBUG = 1 << 0; +constexpr int AB_ELF_STRIP_SYMBOLS = 1 << 1; +constexpr int AB_ELF_USE_EU_STRIP = 1 << 2; +constexpr int AB_ELF_FIND_SO_DEPS = 1 << 3; constexpr int AB_ELF_SAVE_WITH_PATH = 1 << 4; constexpr int AB_ELF_FIND_SONAMES = 1 << 5; @@ -81,6 +81,6 @@ int elf_copy_debug_symbols_parallel(const std::vector &directories, const char *dst_path, std::unordered_set &so_deps, std::unordered_set &sonames, - int flags = AB_ELF_USE_EU_STRIP); + int flags); const std::unordered_set aosc_arch_to_debian_arch_suffix(const char *arch_name); diff --git a/native/abnativefunctions.cpp b/native/abnativefunctions.cpp index e827a24..b628acf 100644 --- a/native/abnativefunctions.cpp +++ b/native/abnativefunctions.cpp @@ -787,7 +787,11 @@ static int abelf_elf_copy_to_symdir(WORD_LIST *list) { /** * Copy debug symbols for one specific file specified: * @param list arguments of the following form: - * <-flags> + * <-flags> + * -d: split debug symbols + * -s: strip symbols + * -e: use eu-strip + * -p: save debug symbols by filename instead of build ID * @return command status code: * 0 - success * 1 - invalid flags @@ -798,13 +802,13 @@ static int abelf_copy_dbg(WORD_LIST *list) { int flags = AB_ELF_FIND_SO_DEPS; reset_internal_getopt(); int opt = 0; - while ((opt = internal_getopt(list, const_cast("exrp"))) != -1) { + while ((opt = internal_getopt(list, const_cast("desp"))) != -1) { switch (opt) { - case 'x': - flags |= AB_ELF_STRIP_ONLY; + case 'd': + flags |= AB_ELF_SPLIT_DEBUG; break; - case 'r': - flags |= AB_ELF_CHECK_ONLY; + case 's': + flags |= AB_ELF_STRIP_SYMBOLS; break; case 'e': flags |= AB_ELF_USE_EU_STRIP; @@ -847,6 +851,10 @@ static void ab_set_to_bash_array(const char *varname, * Copy debug symbols for all files specified: * @param list arguments of the following form: * <-flags> + * -d: split debug symbols + * -s: strip symbols + * -e: use eu-strip + * -p: save debug symbols by filename instead of build ID * @return command status code: * 0 - success * 1 - invalid flags @@ -860,13 +868,13 @@ static int abelf_copy_dbg_parallel(WORD_LIST *list) { reset_internal_getopt(); int opt = 0; - while ((opt = internal_getopt(list, const_cast("exrp"))) != -1) { + while ((opt = internal_getopt(list, const_cast("desp"))) != -1) { switch (opt) { - case 'x': - flags |= AB_ELF_STRIP_ONLY; + case 'd': + flags |= AB_ELF_SPLIT_DEBUG; break; - case 'r': - flags |= AB_ELF_CHECK_ONLY; + case 's': + flags |= AB_ELF_STRIP_SYMBOLS; break; case 'e': flags |= AB_ELF_USE_EU_STRIP; diff --git a/proc/01-core-defines.sh b/proc/01-core-defines.sh index fffd756..9bd88e9 100644 --- a/proc/01-core-defines.sh +++ b/proc/01-core-defines.sh @@ -126,12 +126,6 @@ if [ "$ABHOST" != "noarch" ] ; then unset last_status chk_op fi -if ! bool "$ABSTRIP" && bool "$ABSPLITDBG"; then - abwarn "QA: ELF stripping is turned OFF." - abwarn " Won't package debug symbols as they are shipped in ELF themselves." - ABSPLITDBG=0 -fi - if [[ $ABHOST == noarch ]]; then abinfo "Architecture-agnostic (noarch) package detected, disabling -dbg package split ..." ABSPLITDBG=0