diff --git a/utils/capture-libs.c b/utils/capture-libs.c
index a4cb0e02b651f062d565ba7bfa74c9b637df3436..a22e2f5c3b3be73cb5372d0a74f94c4fdffb8470 100644
--- a/utils/capture-libs.c
+++ b/utils/capture-libs.c
@@ -111,24 +111,6 @@ enum
   OPTION_VERSION,
 };
 
-/*
- * string_set_diff_flags:
- * @STRING_SET_DIFF_ONLY_IN_FIRST: At least one element is in the first set but not the second
- * @STRING_SET_DIFF_ONLY_IN_SECOND: At least one element is in the second set but not the first
- * @STRING_SET_DIFF_NONE: All elements are equal
- *
- * The result of comparing two sets of strings. If each set
- * contains elements that the other does not, then
- * both @STRING_SET_DIFF_ONLY_IN_FIRST
- * and @STRING_SET_DIFF_ONLY_IN_SECOND will be set.
- */
-typedef enum
-{
-  STRING_SET_DIFF_ONLY_IN_FIRST = (1 << 0),
-  STRING_SET_DIFF_ONLY_IN_SECOND = (1 << 1),
-  STRING_SET_DIFF_NONE = 0
-} string_set_diff_flags;
-
 static const char * const *arg_patterns = NULL;
 static const char *option_container = "/";
 static const char *option_dest = ".";
@@ -347,558 +329,6 @@ static bool capture_patterns( const char * const *patterns,
                               capture_flags flags,
                               int *code, char **message );
 
-/* Exclude empty symbols */
-static int
-symbol_excluded( const char *name )
-{
-    if( name == NULL ||
-        !strcmp(name, "") )
-        return 1;
-
-    return 0;
-}
-
-static int
-bsearch_strcmp_cb( const void *n, const void *ip )
-{
-    const char *needle = n;
-    const char * const *item_p = ip;
-    return strcmp( needle, *item_p );
-}
-
-static int
-qsort_strcmp_cb( const void* s1, const void* s2 )
-{
-    const char * const *a = (const char* const*) s1;
-    const char* const *b = (const char* const*) s2;
-    return strcmp( *a, *b );
-}
-
-/*
- * parse_map_symbols:
- * @base: (type filename): A `link_map` base address
- * @dyn: (type filename): The dynamic section of the shared object
- * @symbols_number: (out) (not optional): The number of symbols found
- * @code: (out) (optional): Used to return an error code on
- *  failure
- * @message: (out) (optional) (nullable): Used to return an error message
- *  on failure
- *
- * Returns: (transfer container): The list of symbols that the
- *  shared object has, on failure %NULL.
- */
-static const char **
-parse_map_symbols( ElfW(Addr) base,
-                   ElfW(Dyn) *dyn,
-                   size_t* symbols_number,
-                   int *code, char **message )
-{
-    size_t x = 0;
-    const char *strtab = NULL;
-    ElfW(Sym) *symtab = NULL;
-    const ElfW(Dyn) *entry = NULL;
-    const ElfW(Sym) *entry_sym = NULL;
-    /* The array is calloc'd, but the members point into the string table */
-    const char **symbols = NULL;
-
-    assert( symbols_number != NULL );
-
-    strtab = dynamic_section_find_strtab( dyn, (const void *) base, NULL );
-
-    if ( strtab == NULL )
-    {
-        _capsule_set_error( code, message, EINVAL,
-                            "String table is unexpectedly missing or inaccessible" );
-        return NULL;
-    }
-
-    for( entry = dyn; entry->d_tag != DT_NULL; entry++ )
-    {
-        switch( entry->d_tag )
-        {
-          case DT_SYMTAB:
-            symtab = (ElfW(Sym) *) entry->d_un.d_ptr;
-            break;
-
-          default:
-            break;
-        }
-    }
-
-    if ( symtab == NULL )
-    {
-        _capsule_set_error( code, message, EINVAL,
-                            "DT_SYMTAB is unexpectedly missing or inaccessible" );
-        return NULL;
-    }
-
-    x = 0;
-    /* We perform two times the for cycle in order to get the number of items.
-     * Skip all the excluded symbols. */
-    for( entry_sym = symtab;
-         ( (ELFW_ST_TYPE(entry_sym->st_info) < STT_NUM) &&
-           (ELFW_ST_BIND(entry_sym->st_info) < STB_NUM) );
-         entry_sym++ )
-    {
-        if ( !symbol_excluded( strtab + entry_sym->st_name ) )
-            x++;
-    }
-
-    *symbols_number = x;
-    symbols = calloc( *symbols_number + 1, sizeof(char *) );
-
-    x = 0;
-    for( entry_sym = symtab;
-         ( (ELFW_ST_TYPE(entry_sym->st_info) < STT_NUM) &&
-           (ELFW_ST_BIND(entry_sym->st_info) < STB_NUM) );
-         entry_sym++ )
-    {
-        if ( !symbol_excluded( strtab + entry_sym->st_name ) )
-        {
-            symbols[x] = strtab + entry_sym->st_name;
-            x++;
-        }
-    }
-
-    symbols[x] = NULL;
-    qsort( symbols, *symbols_number, sizeof(char *), qsort_strcmp_cb );
-    return symbols;
-}
-
-/*
- * parse_map_versions:
- * @base: (type filename): A `link_map` base address
- * @dyn: (type filename): The dynamic section of the shared object
- * @versions_number: (out) (optional): The number of versions found
- * @code: (out) (optional): Used to return an error code on
- *  failure
- * @message: (out) (optional) (nullable): Used to return an error message
- *  on failure
- *
- * Returns: (transfer container): The list of versions that the
- *  shared object has, on failure %NULL.
- */
-static const char **
-parse_map_versions( ElfW(Addr) base, ElfW(Dyn) *dyn,
-                    size_t* versions_number,
-                    int *code, char **message )
-{
-    size_t verdefnum = (size_t) -1;
-    void *start = NULL;
-    const ElfW(Verdef) *verdef = NULL;
-    const char *strtab = NULL;
-    const char *version = NULL;
-    ElfW(Verdaux) *aux = NULL;
-    const char *vd = NULL;
-    const char **versions = NULL;
-
-    start  = (void *) ((ElfW(Addr)) dyn - base );
-    strtab = dynamic_section_find_strtab( dyn, (const void *) base, NULL );
-    verdefnum = find_value( base, start, DT_VERDEFNUM );
-    verdef = (const ElfW(Verdef) *) find_ptr( base, start, DT_VERDEF );
-
-    /* The library doesn't have versions */
-    if( verdefnum == (size_t) -1 && verdef == NULL )
-    {
-        versions = malloc( sizeof(char *) );
-        versions[0] = NULL;
-        if( versions_number != NULL)
-            *versions_number = 0;
-
-        return versions;
-    }
-
-    if( verdefnum == (size_t) -1 || verdef == NULL )
-    {
-        _capsule_set_error( code, message, EINVAL,
-                            "Found one of DT_VERDEF or DT_VERDEFNUM, but not the other" );
-        return NULL;
-    }
-
-    vd = (const char *) verdef;
-
-    versions = calloc( verdefnum + 1, sizeof(char *) );
-
-    for( size_t x = 0; x < verdefnum; x++ )
-    {
-        ElfW(Verdef) *the_entry = (ElfW(Verdef) *) vd;
-        aux = (ElfW(Verdaux) *) ( vd + the_entry->vd_aux );
-        version = strtab + aux->vda_name;
-        versions[x] = version;
-        vd = vd + the_entry->vd_next;
-    }
-
-    versions[verdefnum] = NULL;
-    qsort( versions, verdefnum, sizeof(char *), qsort_strcmp_cb );
-    if( versions_number != NULL)
-        *versions_number = verdefnum;
-
-    return versions;
-}
-
-/*
- * get_link_map:
- * @soname: (type filename): The library name to load
- * @path: (type filename): If not %NULL, load libraries as though
- *  this base path was the root directory
- * @ns: (inout) (not optional): The namespace that will be used
- *  to search for @soname
- * @code: (out) (optional): Used to return an error code on
- *  failure
- * @message: (out) (optional) (nullable): Used to return an error message
- *  on failure
- *
- * Returns: A link_map of the loaded shared library @soname,
- *  on failure %NULL.
- */
-static struct link_map *
-get_link_map ( const char *soname, const char *path,
-               Lmid_t *ns, int *code, char **message )
-{
-    const char *libname;
-    ld_libs ldlibs = {};
-    void *handle;
-    int dlcode = 0;
-    struct link_map *map = NULL;
-
-    assert( ns != NULL );
-
-    if( !ld_libs_init( &ldlibs, NULL, path, 0, code, message ) )
-        return NULL;
-
-    if( !ld_libs_set_target( &ldlibs, soname, code, message ) )
-        return NULL;
-
-    if( ( handle = ld_libs_load( &ldlibs, ns, 0, code, message ) ) )
-    {
-        if( (libname = strrchr( soname, '/' ) ) )
-            libname = libname + 1;
-        else
-            libname = soname;
-
-        // dl_iterate_phdr won't work with private dlmopen namespaces:
-        if( ( dlcode = dlinfo( handle, RTLD_DI_LINKMAP, &map ) ) )
-        {
-            _capsule_set_error( code, message, EINVAL,
-                                "cannot access symbols for %s via handle %p [%d]: %s",
-                                libname, handle, dlcode, dlerror() );
-            return NULL;
-        }
-    }
-    else
-    {
-        return NULL;
-    }
-    return map;
-}
-
-/*
- * get_symbols:
- * @soname: (type filename): The library name to load
- * @path: (type filename): If not %NULL, load libraries as though
- *  this base path was the root directory
- * @symbols_number: (out) (not optional): The number of symbols found
- * @ns: (inout) (not optional): The namespace that will be used
- *  to search for @soname
- * @code: (out) (optional): Used to return an error code on
- *  failure
- * @message: (out) (optional) (nullable): Used to return an error message
- *  on failure
- *
- * Returns: (transfer container): The list of symbols that the
- *  shared object has, on failure %NULL.
- */
-static const char **
-get_symbols ( const char *soname, const char *path, size_t *symbols_number,
-              Lmid_t *ns, int *code, char **message )
-{
-    struct link_map *map;
-    const char **symbols = NULL;
-
-    map = get_link_map( soname, path, ns, code, message );
-
-    // We expect to have a pointer directly to the library we are interested in.
-    if( map != NULL )
-        symbols = parse_map_symbols( map->l_addr, map->l_ld, symbols_number,
-                                     code, message );
-
-    return symbols;
-}
-
-/*
- * get_versions:
- * @soname: (type filename): The library name to load
- * @path: (type filename): If not %NULL, load libraries as though
- *  this base path was the root directory
- * @versions_number: (out) (optional): The number of versions found
- * @ns: (inout) (not optional): The namespace that will be used
- *  to search for @soname
- * @code: (out) (optional): Used to return an error code on
- *  failure
- * @message: (out) (optional) (nullable): Used to return an error message
- *  on failure
- *
- * Returns: (transfer container): The list of versions that the
- *  shared object has, on failure %NULL.
- */
-static const char **
-get_versions ( const char *soname, const char *path, size_t* versions_number,
-               Lmid_t *ns, int *code, char **message )
-{
-    struct link_map *map;
-    const char **versions = NULL;
-
-    map = get_link_map( soname, path, ns, code, message );
-
-    // We expect to have a pointer directly to the library we are interested in.
-    if( map != NULL )
-        versions = parse_map_versions( map->l_addr, map->l_ld, versions_number,
-                                       code, message );
-
-    return versions;
-}
-
-/*
- * compare_string_sets:
- * @first: the first set to compare
- * @first_length: number of elements in the first set
- * @second: the second set to compare
- * @second_length: number of elements in the second set
- *
- * The two sets needs to be ordered because we will use a binary search to do
- * the comparison.
- */
-static string_set_diff_flags
-compare_string_sets ( const char **first, size_t first_length,
-                      const char **second, size_t second_length )
-{
-    string_set_diff_flags result = STRING_SET_DIFF_NONE;
-
-    assert( first != NULL );
-    assert( second != NULL );
-
-    if( first_length > second_length )
-    {
-        result |= STRING_SET_DIFF_ONLY_IN_FIRST;
-    }
-    else
-    {
-        for( size_t i = 0; i < first_length; i++ )
-        {
-            char *found = bsearch( first[i], second, second_length, sizeof(char *), bsearch_strcmp_cb );
-            if( found == NULL )
-            {
-                result |= STRING_SET_DIFF_ONLY_IN_FIRST;
-                break;
-            }
-        }
-    }
-
-    if( first_length < second_length )
-    {
-        result |= STRING_SET_DIFF_ONLY_IN_SECOND;
-    }
-    else
-    {
-        for( size_t i = 0; i < second_length; i++ )
-        {
-            char *found = bsearch( second[i], first, first_length, sizeof(char *), bsearch_strcmp_cb );
-            if( found == NULL )
-            {
-                result |= STRING_SET_DIFF_ONLY_IN_SECOND;
-                break;
-            }
-        }
-    }
-    return result;
-}
-
-/*
- * library_cmp_by_symbols:
- * @soname: The library we are interested in
- * @container_namespace: (inout): The namespace that will be used
- *  to search @soname in the container
- * @provider_namespace: (inout): The namespace that will be used
- *  to search @soname in the provider
- *
- * Attempt to determine whether @soname is older, newer or
- * the same in the container or the provider inspecting their
- * symbols.
- *
- * Return a strcmp-style result: negative if container < provider,
- * positive if container > provider, zero if container == provider
- * or if container and provider are non-comparable.
- */
-static int
-library_cmp_by_symbols( const char *soname, Lmid_t *container_namespace,
-                        Lmid_t *provider_namespace )
-{
-    const char **container_symbols = NULL;
-    const char **provider_symbols = NULL;
-    size_t container_symbols_number = 0;
-    size_t provider_symbols_number = 0;
-    string_set_diff_flags symbol_result = STRING_SET_DIFF_NONE;
-    int cmp_result = 0;
-    int code = 0;
-    char *message = NULL;
-
-    container_symbols = get_symbols( soname, option_container,
-                                     &container_symbols_number,
-                                     container_namespace, &code, &message );
-
-    if( container_symbols == NULL )
-    {
-        warnx( "failed to get container symbols for %s (%d): %s",
-               soname, code, message );
-        goto out;
-    }
-
-    provider_symbols = get_symbols( soname, option_provider,
-                                    &provider_symbols_number,
-                                    provider_namespace, &code, &message );
-
-    if( provider_symbols == NULL )
-    {
-        warnx( "failed to get provider symbols for %s (%d): %s",
-               soname, code, message );
-        goto out;
-    }
-
-    symbol_result = compare_string_sets( container_symbols, container_symbols_number,
-                                         provider_symbols, provider_symbols_number );
-
-    /* In container we have strictly more symbols: don't symlink the one
-     * from the provider */
-    if( symbol_result == STRING_SET_DIFF_ONLY_IN_FIRST )
-    {
-        DEBUG( DEBUG_TOOL,
-               "%s in the container is newer because its symbols are a strict superset",
-               soname );
-        cmp_result = 1;
-    }
-    /* In provider we have strictly more symbols: create the symlink */
-    else if( symbol_result == STRING_SET_DIFF_ONLY_IN_SECOND )
-    {
-        DEBUG( DEBUG_TOOL,
-               "%s in the provider is newer because its symbols are a strict superset",
-               soname );
-        cmp_result = -1;
-    }
-    /* With the following two cases we are still unsure which library is newer, so we
-     * will choose the provider */
-    else if( symbol_result == STRING_SET_DIFF_NONE )
-    {
-        DEBUG( DEBUG_TOOL,
-               "%s in the container and the provider have the same symbols",
-               soname );
-    }
-    else
-    {
-        DEBUG( DEBUG_TOOL,
-               "%s in the container and the provider have different symbols and neither is a superset of the other",
-               soname );
-    }
-
-    out:
-        _capsule_clear( &message );
-        free( container_symbols );
-        free( provider_symbols );
-        return cmp_result;
-}
-
-/*
- * library_cmp_by_versions:
- * @soname: The library we are interested in
- * @container_namespace: (inout): The namespace that will be used
- *  to search @soname in the container
- * @provider_namespace: (inout): The namespace that will be used
- *  to search @soname in the provider
- *
- * Attempt to determine whether @soname is older, newer or
- * the same in the container or the provider inspecting their
- * symbols versions.
- *
- * Return a strcmp-style result: negative if container < provider,
- * positive if container > provider, zero if container == provider
- * or if container and provider are non-comparable.
- */
-static int
-library_cmp_by_versions( const char *soname, Lmid_t *container_namespace,
-                         Lmid_t *provider_namespace )
-{
-    const char **container_versions = NULL;
-    const char **provider_versions = NULL;
-    size_t container_versions_number = 0;
-    size_t provider_versions_number = 0;
-    string_set_diff_flags version_result = STRING_SET_DIFF_NONE;
-    int cmp_result = 0;
-    int code = 0;
-    char *message = NULL;
-
-    container_versions = get_versions( soname, option_container,
-                                       &container_versions_number,
-                                       container_namespace, &code, &message );
-
-    if( container_versions == NULL )
-    {
-        warnx( "failed to get container versions for %s (%d): %s",
-               soname, code, message );
-        goto out;
-    }
-
-    provider_versions = get_versions( soname, option_provider,
-                                      &provider_versions_number,
-                                      provider_namespace, &code, &message );
-
-    if( provider_versions == NULL )
-    {
-        warnx( "failed to get provider versions for %s (%d): %s",
-               soname, code, message );
-        goto out;
-    }
-
-    version_result = compare_string_sets( container_versions, container_versions_number,
-                                          provider_versions, provider_versions_number );
-
-    /* Version in container is strictly newer: don't symlink the one
-     * from the provider */
-    if( version_result == STRING_SET_DIFF_ONLY_IN_FIRST )
-    {
-        DEBUG( DEBUG_TOOL,
-               "%s in the container is newer because its version definitions are a strict superset",
-               soname );
-        cmp_result = 1;
-    }
-    /* Version in the provider is strictly newer: create the symlink */
-    else if( version_result == STRING_SET_DIFF_ONLY_IN_SECOND )
-    {
-        DEBUG( DEBUG_TOOL,
-               "%s in the provider is newer because its version definitions are a strict superset",
-               soname );
-        cmp_result = -1;
-    }
-    /* With the following two cases we are still unsure which library is newer */
-    else if( version_result == STRING_SET_DIFF_NONE )
-    {
-        DEBUG( DEBUG_TOOL,
-               "%s in the container and the provider have the same symbol versions",
-               soname );
-    }
-    else
-    {
-        DEBUG( DEBUG_TOOL,
-               "%s in the container and the provider have different symbol versions and neither is a superset of the other",
-               soname );
-    }
-
-    out:
-        code = 0;
-        _capsule_clear( &message );
-        free( container_versions );
-        free( provider_versions );
-        return cmp_result;
-}
-
 /*
  * library_cmp_by_name:
  * @soname: The library we are interested in, used in debug logging
@@ -987,8 +417,6 @@ capture_one( const char *soname, capture_flags flags,
     _capsule_cleanup(ld_libs_finish) ld_libs provider = {};
     int local_code = 0;
     _capsule_autofree char *local_message = NULL;
-    Lmid_t container_namespace = LM_ID_NEWLM;
-    Lmid_t provider_namespace = LM_ID_NEWLM;
 
     if( !init_with_target( &provider, option_provider, soname,
                            &local_code, &local_message ) )
@@ -1047,29 +475,31 @@ capture_one( const char *soname, capture_flags flags,
 
         needed_basename = my_basename( needed_name );
 
-        size_t j;
-        bool libc_lib = false;
-        for( j = 0; j < N_ELEMENTS( libc_patterns ); j++ )
+        if( !option_glibc )
         {
-            if( libc_patterns[j] == NULL )
-                break;
-
-            assert( strstarts( libc_patterns[j], "soname:" ) );
+            unsigned int j;
+            bool capture = true;
 
-            if( strcmp( libc_patterns[j] + strlen( "soname:" ),
-                        needed_basename ) == 0 )
+            for( j = 0; j < N_ELEMENTS( libc_patterns ); j++ )
             {
-                libc_lib = true;
-                break;
+                if( libc_patterns[j] == NULL )
+                    break;
+
+                assert( strstarts( libc_patterns[j], "soname:" ) );
+
+                if( strcmp( libc_patterns[j] + strlen( "soname:" ),
+                            needed_basename ) == 0 )
+                {
+                    DEBUG( DEBUG_TOOL,
+                           "Not capturing \"%s\" because it is part of glibc",
+                           needed_name );
+                    capture = false;
+                    break;
+                }
             }
-        }
 
-        if( !option_glibc && libc_lib )
-        {
-            DEBUG( DEBUG_TOOL,
-                   "Not capturing \"%s\" because it is part of glibc",
-                   needed_name );
-            continue;
+            if( !capture )
+                continue;
         }
 
         if( fstatat( dest_fd, needed_basename, &statbuf,
@@ -1108,39 +538,33 @@ capture_one( const char *soname, capture_flags flags,
                                   &local_code, &local_message ) )
             {
                 const char *needed_path_in_container = container.needed[0].path;
-                int decision = 0;
 
-                /* Compare the version definitions.
-                 * We skip all libc related libraries to avoid problems with dlmopen() */
-                if( !libc_lib )
+                /* TODO: Ideally we would actually dlopen the libraries and
+                 * inspect their symbol tables, either in ambiguous cases
+                 * or always - but that's easier said than done, because
+                 * private symbols exist. For now we just use
+                 * library_cmp_by_name(). */
+
+                /* If equal, we prefer the provider over the container */
+                if( library_cmp_by_name( needed_name,
+                                         needed_path_in_container,
+                                         option_container,
+                                         needed_path_in_provider,
+                                         option_provider) > 0 )
                 {
-                    decision = library_cmp_by_versions( needed_name, &container_namespace,
-                                                        &provider_namespace);
-                }
-
-                /* Compare the numeric tail */
-                if( decision == 0 )
-                {
-                    decision = library_cmp_by_name( needed_name,
-                                                    needed_path_in_container,
-                                                    option_container,
-                                                    needed_path_in_provider,
-                                                    option_provider );
+                    /* Version in container is strictly newer: don't
+                     * symlink in the one from the provider */
+                    DEBUG( DEBUG_TOOL,
+                           "%s is strictly newer in the container",
+                           needed_name );
+                    continue;
                 }
-
-                /* Compare the symbols.
-                 * We skip all libc related libraries to avoid problems with dlmopen() */
-                if( decision == 0 && !libc_lib )
+                else
                 {
-                    decision = library_cmp_by_symbols( needed_name, &container_namespace,
-                                                       &provider_namespace);
+                    DEBUG( DEBUG_TOOL,
+                           "%s is newer or equal in the provider",
+                           needed_name );
                 }
-
-                /* If the container library is newer (decision > 0) we skip the link creation.
-                 * In all the other cases, even if we were unable to determine which library
-                 * was newer, we use the one from the provider. */
-                if ( decision > 0 )
-                    continue;
             }
             else if( local_code == ENOENT )
             {