Skip to content

Commit

Permalink
Enhance requires with version information from the build root.
Browse files Browse the repository at this point in the history
The --libtool-version-fallback option will cause elfdeps to
try to use the version information in the shared object's filename
for shared objects that don't provide versioned symbols. This
additional information allows rpm to track minor-version
dependencies.
  • Loading branch information
gordonmessmer committed Feb 1, 2023
1 parent a9ac172 commit a01b715
Showing 1 changed file with 81 additions and 10 deletions.
91 changes: 81 additions & 10 deletions tools/elfdeps.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@
#include <popt.h>
#include <gelf.h>

#include <link.h>
#include <dlfcn.h>

#include <rpm/rpmstring.h>
#include <rpm/argv.h>

int libtool_version_fallback = 0;
int soname_only = 0;
int fake_soname = 1;
int filter_soname = 1;
Expand All @@ -33,6 +37,53 @@ typedef struct elfInfo_s {
ARGV_t provides;
} elfInfo;

/*
* If filename contains ".so" followed by a version number, return
* a copy of the version number.
*/
static char *getLibtoolVer(const char *filename)
{
const char *so;
int found_digit, found_dot = 0;
// Start from the end of the string. Verify that it ends with
// numbers and dots, preceded by ".so.".
so = filename + strlen(filename);
while (so > filename+2) {
if (*so == '.') {
found_dot++;
so--;
continue;
} else if (strchr("0123456789", *so)) {
found_digit++;
so--;
continue;
} else if (strncmp(so-2, ".so.", 4) == 0) {
so+=2;
if (found_digit && found_dot > 1) {
return strdup(so);
}
break;
} else {
return NULL;
}
}
return NULL;
}

static char *getLibtoolVerFromShLink(const char *filename)
{
void *dl_handle;
struct link_map *linkmap;
char *version = NULL;
dl_handle = dlmopen(LM_ID_NEWLM, filename, RTLD_LAZY);
if (dl_handle == NULL) return NULL;
if (dlinfo(dl_handle, RTLD_DI_LINKMAP, &linkmap) != -1) {
version = getLibtoolVer(linkmap->l_name);
}
dlclose(dl_handle);
return version;
}

/*
* Rough soname sanity filtering: all sane soname's dependencies need to
* contain ".so", and normal linkable libraries start with "lib",
Expand Down Expand Up @@ -96,14 +147,21 @@ static const char *mkmarker(GElf_Ehdr *ehdr)
}

static void addDep(ARGV_t *deps,
const char *soname, const char *ver, const char *marker)
const char *soname, const char *ver, const char *marker,
const char *compare_op, const char *fallback_ver)
{
char *dep = NULL;

if (skipSoname(soname))
return;

if (ver || marker) {
if (compare_op && fallback_ver) {
// when versioned symbols aren't available, the libtool version
// might be used to generate a minimum dependency version.
rasprintf(&dep,
"%s()%s %s %s", soname, marker ? marker : "",
compare_op, fallback_ver);
} else if (ver || marker) {
rasprintf(&dep,
"%s(%s)%s", soname, ver ? ver : "", marker ? marker : "");
}
Expand Down Expand Up @@ -143,10 +201,10 @@ static void processVerDef(Elf_Scn *scn, GElf_Shdr *shdr, elfInfo *ei)
auxoffset += aux->vda_next;
continue;
} else if (soname && !soname_only) {
addDep(&ei->provides, soname, s, ei->marker);
addDep(&ei->provides, soname, s, ei->marker, NULL, NULL);
}
}

}
}
rfree(soname);
Expand Down Expand Up @@ -182,7 +240,7 @@ static void processVerNeed(Elf_Scn *scn, GElf_Shdr *shdr, elfInfo *ei)
break;

if (genRequires(ei) && soname && !soname_only) {
addDep(&ei->requires, soname, s, ei->marker);
addDep(&ei->requires, soname, s, ei->marker, NULL, NULL);
}
auxoffset += aux->vna_next;
}
Expand Down Expand Up @@ -222,8 +280,14 @@ static void processDynamic(Elf_Scn *scn, GElf_Shdr *shdr, elfInfo *ei)
case DT_NEEDED:
if (genRequires(ei)) {
s = elf_strptr(ei->elf, shdr->sh_link, dyn->d_un.d_val);
if (s)
addDep(&ei->requires, s, NULL, ei->marker);
if (s) {
char *libtool_ver = NULL;
if (libtool_version_fallback) {
libtool_ver = getLibtoolVerFromShLink(s);
}
addDep(&ei->requires, s, NULL, ei->marker, ">=", libtool_ver);
free(libtool_ver);
}
}
break;
}
Expand Down Expand Up @@ -322,8 +386,14 @@ static int processFile(const char *fn, int dtype)
const char *bn = strrchr(fn, '/');
ei->soname = rstrdup(bn ? bn + 1 : fn);
}
if (ei->soname)
addDep(&ei->provides, ei->soname, NULL, ei->marker);
if (ei->soname) {
char *libtool_ver = NULL;
if (libtool_version_fallback) {
libtool_ver = getLibtoolVer(fn);
}
addDep(&ei->provides, ei->soname, NULL, ei->marker, "=", libtool_ver);
free(libtool_ver);
}
}

/* If requested and present, add dep for interpreter (ie dynamic linker) */
Expand Down Expand Up @@ -359,11 +429,12 @@ int main(int argc, char *argv[])
struct poptOption opts[] = {
{ "provides", 'P', POPT_ARG_VAL, &provides, -1, NULL, NULL },
{ "requires", 'R', POPT_ARG_VAL, &requires, -1, NULL, NULL },
{ "libtool-version-fallback", 0, POPT_ARG_VAL, &libtool_version_fallback, -1, NULL, NULL },
{ "soname-only", 0, POPT_ARG_VAL, &soname_only, -1, NULL, NULL },
{ "no-fake-soname", 0, POPT_ARG_VAL, &fake_soname, 0, NULL, NULL },
{ "no-filter-soname", 0, POPT_ARG_VAL, &filter_soname, 0, NULL, NULL },
{ "require-interp", 0, POPT_ARG_VAL, &require_interp, -1, NULL, NULL },
POPT_AUTOHELP
POPT_AUTOHELP
POPT_TABLEEND
};

Expand Down

0 comments on commit a01b715

Please sign in to comment.