From: Michael Tremer Date: Fri, 3 Jan 2025 17:27:05 +0000 (+0000) Subject: ELF: Fetch provided dependencies X-Git-Tag: 0.9.30~557 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=85d21134fc78053377f3da8f77b392309bd8f52a;p=pakfire.git ELF: Fetch provided dependencies Signed-off-by: Michael Tremer --- diff --git a/src/pakfire/build.c b/src/pakfire/build.c index d07c5e9df..c7bfa22ef 100644 --- a/src/pakfire/build.c +++ b/src/pakfire/build.c @@ -584,6 +584,57 @@ ERROR: return r; } +static int pakfire_build_find_elf_provides( + struct pakfire_ctx* ctx, struct pakfire_file* file, struct pakfire_find_deps_ctx* deps) { + struct pakfire_elf* elf = NULL; + char** provides = NULL; + int r; + + // Skip files that are not executable + if (!pakfire_file_is_executable(file)) + return 0; + + // Only handle .so files + if (!pakfire_file_matches(file, "**.so") && !pakfire_file_matches(file, "**.so.*")) + return 0; + + // Try to open the ELF file + r = pakfire_elf_open_file(&elf, ctx, file); + if (r < 0) { + switch (-r) { + // This does not seem to be an ELF file + case ENOTSUP: + return 0; + + // Raise any other errors + default: + goto ERROR; + } + } + + // Fetch all provides + r = pakfire_elf_provides(elf, &provides); + if (r < 0) + goto ERROR; + + // Add them all to the package + if (provides) { + for (char** p = provides; *p; p++) { + r = pakfire_package_add_dep(deps->pkg, PAKFIRE_PKG_PROVIDES, "%s", *p); + if (r < 0) + goto ERROR; + } + } + +ERROR: + if (provides) + pakfire_strings_free(provides); + if (elf) + pakfire_elf_unref(elf); + + return r; +} + static int pakfire_build_find_elf_requires( struct pakfire_ctx* ctx, struct pakfire_file* file, struct pakfire_find_deps_ctx* deps) { struct pakfire_elf* elf = NULL; @@ -682,7 +733,6 @@ static int pakfire_build_find_provides( else if (pakfire_path_match("**.pc", path)) return pakfire_build_find_pkgconfig_provides(ctx, file, deps); -#if 0 // Split certain file types differently switch (pakfire_file_get_type(file)) { // Regular files @@ -693,7 +743,6 @@ static int pakfire_build_find_provides( return r; break; } -#endif return 0; } diff --git a/src/pakfire/elf.c b/src/pakfire/elf.c index 8f4670815..101b1e3f0 100644 --- a/src/pakfire/elf.c +++ b/src/pakfire/elf.c @@ -945,10 +945,83 @@ int pakfire_elf_is_stripped(struct pakfire_elf* self) { return 1; } +static int pakfire_elf_find_provides(struct pakfire_elf* self, + Elf_Scn* section, const GElf_Shdr* shdr, void* data) { + GElf_Verdaux verdaux = {}; + GElf_Verdef verdef = {}; + const char* version = NULL; + const char* base = NULL; + char*** provides = data; + int r; + + // Fetch the section data + Elf_Data* d = elf_getdata(section, NULL); + + size_t offset = 0; + + while (offset < shdr->sh_size) { + if (!gelf_getverdef(d, offset, &verdef)) + break; + + size_t aux_offset = offset + verdef.vd_aux; + + for (int i = 0; i < verdef.vd_cnt; i++) { + if (!gelf_getverdaux(d, aux_offset, &verdaux)) + break; + + // Fetch the version string + version = elf_strptr(self->elf, shdr->sh_link, verdaux.vda_name); + + // Skip empty versions + if (!version || !*version) + continue; + + // Is this the base? + if (verdef.vd_flags & VER_FLG_BASE) { + base = version; + break; + } + + // Add it to the list + r = pakfire_strings_appendf(provides, "%s(%s)%s", + base, version, pakfire_elf_is_elf64(self) ? "(64bit)" : ""); + if (r < 0) + return r; + + if (!verdaux.vda_next) + break; + + aux_offset += verdaux.vda_next; + } + + if (!verdef.vd_next) + break; + + offset += verdef.vd_next; + } + + return 0; +} + +int pakfire_elf_provides(struct pakfire_elf* self, char*** provides) { + int r; + + // Fetch the soname + const char* soname = pakfire_elf_soname(self); + if (soname) { + r = pakfire_strings_appendf(provides, + "%s()%s", soname, pakfire_elf_is_elf64(self) ? "(64bit)" : ""); + if (r < 0) + return r; + } + + return pakfire_elf_foreach_section(self, SHT_GNU_verdef, pakfire_elf_find_provides, provides); +} + static int pakfire_elf_find_requires(struct pakfire_elf* self, Elf_Scn* section, const GElf_Shdr* shdr, void* data) { - GElf_Verneed verneed = {}; GElf_Vernaux vernaux = {}; + GElf_Verneed verneed = {}; const char* version = NULL; const char* name = NULL; char*** requires = data; diff --git a/src/pakfire/elf.h b/src/pakfire/elf.h index d6f3ef99e..170698f59 100644 --- a/src/pakfire/elf.h +++ b/src/pakfire/elf.h @@ -65,6 +65,7 @@ enum { }; // Dependencies +int pakfire_elf_provides(struct pakfire_elf* self, char*** provides); int pakfire_elf_requires(struct pakfire_elf* self, char*** requires); // Source Files