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;
+ char** requires = NULL;
int r;
// Try to open the ELF file
goto ERROR;
}
+ // Fetch all requires
+ r = pakfire_elf_requires(elf, &requires);
+ if (r < 0)
+ goto ERROR;
+
+ // Add them all to the package
+ if (requires) {
+ for (char** s = requires; *s; s++) {
+ r = pakfire_package_add_dep(deps->pkg, PAKFIRE_PKG_REQUIRES, "%s", *s);
+ if (r < 0)
+ goto ERROR;
+ }
+ }
+
ERROR:
+ if (requires)
+ pakfire_strings_free(requires);
if (elf)
pakfire_elf_unref(elf);
return self->ehdr.e_machine;
}
+int pakfire_elf_is_elf64(struct pakfire_elf* self) {
+ return self->ehdr.e_ident[EI_CLASS] = ELFCLASS64;
+}
+
int pakfire_elf_endianess(struct pakfire_elf* self) {
return self->ehdr.e_ident[EI_DATA];
}
return 1;
}
+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 = {};
+ const char* version = NULL;
+ const char* name = NULL;
+ char*** requires = data;
+ GElf_Dyn dyn = {};
+ int r;
+
+ // Fetch the section data
+ Elf_Data* d = elf_getdata(section, NULL);
+
+ switch (shdr->sh_type) {
+ case SHT_DYNAMIC:
+ for (size_t i = 0; i < shdr->sh_size / shdr->sh_entsize; i++) {
+ // Fetch the symbol
+ if (!gelf_getdyn(d, i, &dyn))
+ continue;
+
+ switch (dyn.d_tag) {
+ case DT_NEEDED:
+ name = elf_strptr(self->elf, shdr->sh_link, dyn.d_un.d_val);
+
+ // Skip empty names (this should not happen)
+ if (!name || !*name)
+ continue;
+
+ DEBUG(self->ctx, "%s depends on %s\n", self->path, name);
+
+ // Add it to the list
+ r = pakfire_strings_appendf(requires, "%s()%s",
+ name, pakfire_elf_is_elf64(self) ? "(64bit)" : "");
+ if (r < 0)
+ return r;
+ break;
+ }
+ }
+ break;
+
+ case SHT_GNU_verneed:
+ size_t offset = 0;
+
+ while (offset < shdr->sh_size) {
+ if (!gelf_getverneed(d, offset, &verneed))
+ break;
+
+ // Fetch the library name
+ name = elf_strptr(self->elf, shdr->sh_link, verneed.vn_file);
+ if (!name || !*name)
+ continue;
+
+ size_t aux_offset = verneed.vn_aux;
+
+ for (int i = 0; i < verneed.vn_cnt; i++) {
+ if (!gelf_getvernaux(d, aux_offset, &vernaux))
+ break;
+
+ // Fetch the version string
+ version = elf_strptr(self->elf, shdr->sh_link, vernaux.vna_name);
+
+ // Skip empty versions
+ if (!version || !*version)
+ continue;
+
+ // Add it to the list
+ r = pakfire_strings_appendf(requires, "%s(%s)%s",
+ name, version, pakfire_elf_is_elf64(self) ? "(64bit)" : "");
+ if (r < 0)
+ return r;
+
+ if (!vernaux.vna_next)
+ break;
+
+ aux_offset += vernaux.vna_next;
+ }
+
+ if (!verneed.vn_next)
+ break;
+
+ offset += verneed.vn_next;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int pakfire_elf_requires(struct pakfire_elf* self, char*** requires) {
+ return pakfire_elf_foreach_section(self, SHT_NULL, pakfire_elf_find_requires, requires);
+}
+
/*
libdw does not seem to export the error codes in their header files,
although there is a function to retrieve them...
const char* pakfire_elf_path(struct pakfire_elf* self);
int pakfire_elf_type(struct pakfire_elf* self);
int pakfire_elf_machine(struct pakfire_elf* self);
+int pakfire_elf_is_elf64(struct pakfire_elf* self);
int pakfire_elf_endianess(struct pakfire_elf* self);
const char* pakfire_elf_build_id(struct pakfire_elf* self);
const char* pakfire_elf_debuglink(struct pakfire_elf* self);
PAKFIRE_ELF_MISSING_SHSTK = (1 << 3),
};
+// Dependencies
+int pakfire_elf_requires(struct pakfire_elf* self, char*** requires);
+
// Source Files
typedef int (*pakfire_elf_foreach_source_file_callback)
(struct pakfire_ctx* ctx, struct pakfire_elf* elf, const char* filename, void* data);
return 0
}
-find_weak_symbols() {
- local file="${1}"
-
- local suffix
-
- # Is this a 64 bit file?
- if file -L "${file}" 2>/dev/null | grep -q "ELF 64-bit"; then
- suffix="(64bit)"
- fi
-
- # List all weak symbol versions
- objdump -p "${file}" 2>/dev/null | \
- awk \
- 'BEGIN { START=0; LIBNAME=""; }
- /^$/ { START=0; }
- /^Dynamic Section:$/ { START=1; }
- (START==1) && /NEEDED/ {
- if ("'${suffix}'" != "") {
- sub(/$/, "()'${suffix}'", $2);
- }
- print $2;
- }
- (START==2) && /^[A-Za-z]/ { START=3; }
- /^Version References:$/ { START=2; }
- (START==2) && /required from/ {
- sub(/:/, "", $3);
- LIBNAME=$3;
- }
- (START==2) && (LIBNAME!="") && ($4!="") {
- print LIBNAME "(" $4 ")'${suffix}'";
- }'
-
- return 0
-}
-
find_script_interpreter() {
local file="${1}"
continue
fi
- # Is this an ELF file?
- if file -L "${path}" 2>/dev/null | grep -q "ELF"; then
- # Find weak symbols
- if ! find_weak_symbols "${path}"; then
- return 1
- fi
-
- continue
- fi
-
# Add script interpreters
if ! find_script_interpreter "${path}"; then
return 1