From 12d6c8bd03fa64f36a0c0d180e0eb6d493e75060 Mon Sep 17 00:00:00 2001 From: Jiangjin Wang <kaymw@aosc.io> Date: Tue, 13 Feb 2024 19:11:39 -0800 Subject: [PATCH] feat(abnativeelf): generate spiral pkgnames while scanning ELF files --- native/abnativeelf.cpp | 96 ++++++++++++++++++++++++++++++++++-- native/abnativeelf.hpp | 5 +- native/abnativefunctions.cpp | 28 +++++++---- 3 files changed, 115 insertions(+), 14 deletions(-) diff --git a/native/abnativeelf.cpp b/native/abnativeelf.cpp index a0c8aa0..e8f5e64 100644 --- a/native/abnativeelf.cpp +++ b/native/abnativeelf.cpp @@ -11,6 +11,7 @@ #include <sys/mman.h> #include <sys/stat.h> #include <thread> +#include <algorithm> #include <elf.h> #include <sys/wait.h> @@ -491,8 +492,75 @@ static inline int forked_execvp(const char *path, char *const argv[]) { return status; } +std::vector<std::string> +to_spiral_provides(const std::string &soname) { + std::vector<std::string> ret; + + if (soname.empty()) return ret; + + // Rule out strings without the ".so" extension name + const size_t libname_pos = soname.find(".so"); + if (libname_pos == std::string::npos) return ret; + + // Extract libname + auto libname = soname.substr(0, libname_pos); + for (auto &c : libname) { + // - is not allowed + if (c == '_') { + c = '-'; + continue; + } + // Only [a-z0-9.-+] allowed + if ((c >= '0') && (c <= '9')) continue; + if ((c == '-') || (c == '+') || (c == '.')) continue; + c = tolower(c); + + // Contains invalid character + if ((c < 'a') || (c > 'z')) { + return ret; + } + } + + // Remove all occurrences of '-' + libname.erase(std::remove(libname.begin(), libname.end(), '-'), libname.end()); + + auto dev_name = fmt::format("{}-dev", libname); + + // Extract the major part of sover, +3 for ".so" + const size_t sover_start = libname_pos + 3; + // If there's no sover + if (sover_start == soname.size()) { + ret.emplace_back(libname); + ret.emplace_back(fmt::format("{}-dev", libname)); + return ret; + } + // Make sure there's the dot + if (soname[sover_start] != '.') return ret; + size_t sover_major = 0; + for (const auto &c : soname.substr(sover_start + 1, soname.size())) { + if (c == '.') break; + if ((c < '0') || c > '9') return ret; + sover_major *= 10; + sover_major += c - '0'; + } + + // Add a '-' in between libname and sover if libname ends with a digit + char libname_last = libname[libname.size() - 1]; + if ((libname_last >= '0') && (libname_last <= '9')) { + ret.emplace_back(fmt::format("{}-{}", libname, sover_major)); + } else { + ret.emplace_back(fmt::format("{}{}", libname, sover_major)); + } + + // Add -dev package name + ret.emplace_back(fmt::format("{}-dev", libname)); + + return ret; +} + int elf_copy_debug_symbols(const char *src_path, const char *dst_path, - int flags, GuardedSet<std::string> &symbols) { + int flags, GuardedSet<std::string> &symbols, + GuardedSet<std::string> &spiral_provides) { int fd = open(src_path, O_RDONLY, 0); if (fd < 0) { perror("open"); @@ -513,6 +581,17 @@ int elf_copy_debug_symbols(const char *src_path, const char *dst_path, const char *data = static_cast<const char *>(file.addr()); const ELFParseResult result = identify_binary_data(data, size); + if (flags & AB_ELF_GENERATE_SPIRAL_PROVIDES) { + const std::string filename(basename(src_path)); + const auto spiral_filename = to_spiral_provides(filename); + spiral_provides.insert(spiral_filename.begin(), spiral_filename.end()); + + if (! result.soname.empty()) { + const auto spiral_soname = to_spiral_provides(result.soname); + spiral_provides.insert(spiral_soname.begin(), spiral_soname.end()); + } + } + if (flags & AB_ELF_FIND_SO_DEPS) { symbols.insert(result.needed_libs.begin(), result.needed_libs.end()); } @@ -629,22 +708,28 @@ public: ELFWorkerPool(std::string symdir, int flags) : ThreadPool<std::string, int>([&, flags](const std::string& src_path) { return elf_copy_debug_symbols(src_path.c_str(), m_symdir.c_str(), - flags, m_sodeps); + flags, m_sodeps, m_spiral_provides); }), - m_symdir(std::move(symdir)), m_sodeps() {} + m_symdir(std::move(symdir)), m_sodeps(), m_spiral_provides() {} const std::unordered_set<std::string> get_sodeps() const { return m_sodeps.get_set(); } + const std::unordered_set<std::string> get_spiral_provides() const { + return m_spiral_provides.get_set(); + } + private: const std::string m_symdir; GuardedSet<std::string> m_sodeps; + GuardedSet<std::string> m_spiral_provides; }; int elf_copy_debug_symbols_parallel(const std::vector<std::string> &directories, const char *dst_path, std::unordered_set<std::string> &so_deps, + std::unordered_set<std::string> &spiral_provides, int flags) { ELFWorkerPool pool{dst_path, flags}; for (const auto &directory : directories) { @@ -666,5 +751,10 @@ int elf_copy_debug_symbols_parallel(const std::vector<std::string> &directories, so_deps.insert(pool_results.begin(), pool_results.end()); } + if (flags & AB_ELF_GENERATE_SPIRAL_PROVIDES) { + const auto spiral_results = pool.get_spiral_provides(); + spiral_provides.insert(spiral_results.begin(), spiral_results.end()); + } + return 0; } diff --git a/native/abnativeelf.hpp b/native/abnativeelf.hpp index e14d331..399f3be 100644 --- a/native/abnativeelf.hpp +++ b/native/abnativeelf.hpp @@ -44,12 +44,15 @@ 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_SAVE_WITH_PATH = 1 << 4; +constexpr int AB_ELF_GENERATE_SPIRAL_PROVIDES = 1 << 5; int elf_copy_to_symdir(const char *src_path, const char *dst_path, const char *build_id); int elf_copy_debug_symbols(const char *src_path, const char *dst_path, - int flags, GuardedSet<std::string> &symbols); + int flags, GuardedSet<std::string> &symbols, + GuardedSet<std::string> &spiral_provides); int elf_copy_debug_symbols_parallel(const std::vector<std::string> &directories, const char *dst_path, std::unordered_set<std::string> &so_deps, + std::unordered_set<std::string> &spiral_provides, int flags = AB_ELF_USE_EU_STRIP); diff --git a/native/abnativefunctions.cpp b/native/abnativefunctions.cpp index 9ca075e..6784cc5 100644 --- a/native/abnativefunctions.cpp +++ b/native/abnativefunctions.cpp @@ -807,13 +807,23 @@ static int abelf_copy_dbg(WORD_LIST *list) { if (!dst) return EX_BADUSAGE; GuardedSet<std::string> symbols{}; + GuardedSet<std::string> spiral_provides; const int ret = - elf_copy_debug_symbols(src, dst, flags, symbols); + elf_copy_debug_symbols(src, dst, flags, symbols, spiral_provides); if (ret < 0) return 10; return 0; } +static void ab_set_to_bash_array(const char *varname, const std::unordered_set<std::string> &set) { + auto *var = make_new_array_variable(const_cast<char *>(varname)); + var->attributes |= att_readonly; + auto *var_a = array_cell(var); + for (const auto &elem : set) { + array_push(var_a, const_cast<char *>(elem.c_str())); + } +} + /** * Copy debug symbols for all files specified: * @param list arguments of the following form: @@ -825,8 +835,9 @@ static int abelf_copy_dbg(WORD_LIST *list) { * 10 - error occurred during processing */ static int abelf_copy_dbg_parallel(WORD_LIST *list) { - constexpr const char *varname = "__AB_SO_DEPS"; - int flags = AB_ELF_FIND_SO_DEPS; + constexpr const char *varname_so_deps = "__AB_SO_DEPS"; + constexpr const char *varname_spiral = "__AB_SPIRAL_PROVIDES"; + int flags = AB_ELF_FIND_SO_DEPS | AB_ELF_GENERATE_SPIRAL_PROVIDES; reset_internal_getopt(); int opt = 0; @@ -855,17 +866,14 @@ static int abelf_copy_dbg_parallel(WORD_LIST *list) { const auto dst = std::string{args.back()}; args.pop_back(); std::unordered_set<std::string> so_deps{}; + std::unordered_set<std::string> spiral_provides; const int ret = - elf_copy_debug_symbols_parallel(args, dst.c_str(), so_deps, flags); + elf_copy_debug_symbols_parallel(args, dst.c_str(), so_deps, spiral_provides, flags); if (ret < 0) return 10; // copy the data to the bash variable - auto *var = make_new_array_variable(const_cast<char *>(varname)); - var->attributes |= att_readonly; - auto *var_a = array_cell(var); - for (const auto &so_dep : so_deps) { - array_push(var_a, const_cast<char *>(so_dep.c_str())); - } + ab_set_to_bash_array(varname_so_deps, so_deps); + ab_set_to_bash_array(varname_spiral, spiral_provides); return 0; } -- GitLab