When gdb uses debuginfod to fetch missing sharedlibraries from a given debuginfod server it fails for most libraries that don't have a soname due to an inconsistency in how the buildids are registered and how they are queried. In corelow.c in the build_file_mappings we can see how the build ids are registered: /* If this is a bfd of a shared library, record its soname and build id. */ if (build_id != nullptr) { gdb::unique_xmalloc_ptr<char> soname = gdb_bfd_read_elf_soname (bfd->filename); if (soname != nullptr) set_cbfd_soname_build_id (current_program_space->cbfd, soname.get (), build_id); } }); Here, if a library was downloaded by a debuginfod server bfd->filename it's the file that is in the debuginfod cache, (for example /home/pablogsal/.cache/debuginfod_client/4a834042b43eec1f2556ef4979828ea3b0813adc/executable). Notice that here there are two problems: 1) Libraries that do not have soname will never be registered in the map by set_cbfd_soname_build_id. This is very unfortunate because most shared libraries for dynamic languages such as Python do not have sonames set. 2) The registering into the map from library to buildid in set_cbfd_soname_build_id it's made by SONAME (from the dynamic table). But later, in solib.c in the get_cbfd_soname_build_id() function we can see the following: soname_build_id_map *mapptr = cbfd_soname_build_id_data_key.get (abfd.get ()); if (mapptr == nullptr) return {}; auto it = mapptr->find (lbasename (soname)); if (it == mapptr->end ()) return {}; Here the query is made by the basename of the *soname* argument (lbasename (soname)) but this function is NOT called with the soname but rather the full path. Indeed, in solib_map_sections() we can observe: gdb::unique_xmalloc_ptr<char> build_id_hexstr = get_cbfd_soname_build_id (current_program_space->cbfd, so.so_name.c_str ()); but so.so_name.c_str() is a full path from the linker map. Notice the following: 1) This full path may be different from the one in the previous section because one comes from the core and the other comes from the linker map. One it's an absolute path and the other can be a symlink. 2) The query is made by full path but the map it's populate from DT_SONAME, which is inconsistent. All of this together means that gdb will never properly load executables that are downloaded from the server for shared libraries that do not have sonames set. This is very unfortunate because many extension modules for dynamic languages such as Python don't have sonames and will never work for debuginfod: $ python Python 3.11.7 (main, Dec 24 2023, 14:12:08) [GCC 13.2.1 20230801] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import _ssl >>> _ssl <module '_ssl' from '/home/pablogsal/.pyenv/versions/3.11.7/lib/python3.11/lib- $ readelf -d /home/pablogsal/.pyenv/versions/3.11.7/lib/python3.11/lib-dynload/_ssl.cpython-311-x86_64-linux-gnu.so Dynamic section at offset 0x2ad28 contains 27 entries: Tag Type Name/Value 0x0000000000000001 (NEEDED) Shared library: [libssl.so.3] 0x0000000000000001 (NEEDED) Shared library: [libcrypto.so.3] 0x0000000000000001 (NEEDED) Shared library: [libc.so.6] 0x000000000000001d (RUNPATH) Library runpath: [/home/pablogsal/.pyenv/versions/3.11.7/lib] 0x000000000000000c (INIT) 0x12000 0x000000000000000d (FINI) 0x1c23c 0x0000000000000019 (INIT_ARRAY) 0x2bc10 0x000000000000001b (INIT_ARRAYSZ) 8 (bytes) 0x000000000000001a (FINI_ARRAY) 0x2bc18 0x000000000000001c (FINI_ARRAYSZ) 8 (bytes) 0x000000006ffffef5 (GNU_HASH) 0x300 0x0000000000000005 (STRTAB) 0x22c0 0x0000000000000006 (SYMTAB) 0x328 0x000000000000000a (STRSZ) 6467 (bytes) 0x000000000000000b (SYMENT) 24 (bytes) 0x0000000000000003 (PLTGOT) 0x2bfe8 0x0000000000000002 (PLTRELSZ) 7488 (bytes) 0x0000000000000014 (PLTREL) RELA 0x0000000000000017 (JMPREL) 0xffd8 0x0000000000000007 (RELA) 0x3f18 0x0000000000000008 (RELASZ) 49344 (bytes) 0x0000000000000009 (RELAENT) 24 (bytes) 0x000000006ffffffe (VERNEED) 0x3ea8 0x000000006fffffff (VERNEEDNUM) 3 0x000000006ffffff0 (VERSYM) 0x3c04 0x000000006ffffff9 (RELACOUNT) 2033 0x0000000000000000 (NULL) 0x0
Also related: https://sourceware.org/bugzilla/show_bug.cgi?id=31634
(In reply to Pablo Galindo Salgado from comment #0) > 1) Libraries that do not have soname will never be registered in the map by > set_cbfd_soname_build_id. This is very unfortunate because most shared > libraries for dynamic languages such as Python do not have sonames set. > 2) The registering into the map from library to buildid in > set_cbfd_soname_build_id it's made by SONAME (from the dynamic table). One challenge for getting debuginfod to work with corefiles is figuring out which library buildid in the corefile corresponds to a particular library that gdb is unable to open in solib_map_sections. Sonames are used because we can create a soname to buildid mapping from the corefile and then use this mapping to get the right buildid for the debuginfod query when a shared library can't otherwise be found by gdb in solib_map_sections. > [...] > Here the query is made by the basename of the *soname* argument (lbasename > (soname)) but this function is NOT called with the soname but rather the > full path. Indeed, in solib_map_sections() we can observe: > > gdb::unique_xmalloc_ptr<char> build_id_hexstr > = get_cbfd_soname_build_id (current_program_space->cbfd, > so.so_name.c_str ()); > > but so.so_name.c_str() is a full path from the linker map. Notice the > following: > > 1) This full path may be different from the one in the previous section > because one comes from the core and the other comes from the linker map. One > it's an absolute path and the other can be a symlink. > 2) The query is made by full path but the map it's populate from DT_SONAME, > which is inconsistent. AFAIK when the library has a soname, the basename in get_cbfd_soname_build_id should generally match a soname in the map. If this wasn't the case then gdb would fail to query debuginfod for libraries associated with corefiles much more often. I'll look into what paths gdb uses in solib_map_sections for libraries with no soname. Maybe it's possible to create a path-to-buildid map from the corefile that we could use instead of the the soname-to-buildid map when a soname isn't available.