diff options
-rw-r--r-- | libdw/ChangeLog | 6 | ||||
-rw-r--r-- | libdw/dwarf_begin_elf.c | 120 | ||||
-rw-r--r-- | libdwfl/ChangeLog | 8 | ||||
-rw-r--r-- | libdwfl/dwfl_module_getdwarf.c | 121 |
4 files changed, 135 insertions, 120 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 49004325..3152239f 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,9 @@ +2014-04-15 Florian Weimer <fweimer@redhat.com> + + * dwarf_begin_elf.c (__check_build_id, try_debugaltlink) + (open_debugaltlink): Move to libdwfl. + (check_section): Do not locate alternate debuginfo. + 2014-04-24 Florian Weimer <fweimer@redhat.com> * libdw.map (ELFUTILS_0.159): Export dwelf_dwarf_gnu_debugaltlink. diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c index 5f69c61c..4c6346ae 100644 --- a/libdw/dwarf_begin_elf.c +++ b/libdw/dwarf_begin_elf.c @@ -32,7 +32,6 @@ #endif #include <assert.h> -#include <inttypes.h> #include <stdbool.h> #include <stddef.h> #include <stdlib.h> @@ -72,113 +71,6 @@ static const char dwarf_scnnames[IDX_last][18] = }; #define ndwarf_scnnames (sizeof (dwarf_scnnames) / sizeof (dwarf_scnnames[0])) -#ifdef ENABLE_DWZ -internal_function int -__check_build_id (Dwarf *dw, const uint8_t *build_id, const size_t id_len) -{ - if (dw == NULL) - return -1; - - Elf *elf = dw->elf; - Elf_Scn *scn = elf_nextscn (elf, NULL); - if (scn == NULL) - return -1; - - do - { - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - if (likely (shdr != NULL) && shdr->sh_type == SHT_NOTE) - { - size_t pos = 0; - GElf_Nhdr nhdr; - size_t name_pos; - size_t desc_pos; - Elf_Data *data = elf_getdata (scn, NULL); - while ((pos = gelf_getnote (data, pos, &nhdr, &name_pos, - &desc_pos)) > 0) - if (nhdr.n_type == NT_GNU_BUILD_ID - && nhdr.n_namesz == sizeof "GNU" - && ! memcmp (data->d_buf + name_pos, "GNU", sizeof "GNU")) - return (nhdr.n_descsz == id_len - && ! memcmp (data->d_buf + desc_pos, - build_id, id_len)) ? 0 : 1; - } - } - while ((scn = elf_nextscn (elf, scn)) != NULL); - - return -1; -} - -/* Try to open an debug alt link by name, checking build_id. - Marks free_alt on success, return NULL on failure. */ -static Dwarf * -try_debugaltlink (Dwarf *result, const char *try_name, - const uint8_t *build_id, const size_t id_len) -{ - int fd = open (try_name, O_RDONLY); - if (fd > 0) - { - result->alt_dwarf = INTUSE (dwarf_begin) (fd, DWARF_C_READ); - if (result->alt_dwarf != NULL) - { - Elf *elf = result->alt_dwarf->elf; - if (__check_build_id (result->alt_dwarf, build_id, id_len) == 0 - && elf_cntl (elf, ELF_C_FDREAD) == 0) - { - close (fd); - result->free_alt = 1; - return result; - } - INTUSE (dwarf_end) (result->alt_dwarf); - } - close (fd); - } - return NULL; -} - -/* For dwz multifile support, ignore if it looks wrong. */ -static Dwarf * -open_debugaltlink (Dwarf *result, const char *alt_name, - const uint8_t *build_id, const size_t id_len) -{ - /* First try the name itself, it is either an absolute path or - a relative one. Sadly we don't know relative from where at - this point. */ - if (try_debugaltlink (result, alt_name, build_id, id_len) != NULL) - return result; - - /* Lets try based on the build-id. This is somewhat distro specific, - we are following the Fedora implementation described at - https://fedoraproject.org/wiki/Releases/FeatureBuildId#Find_files_by_build_ID - */ -#define DEBUG_PREFIX "/usr/lib/debug/.build-id/" -#define PREFIX_LEN sizeof (DEBUG_PREFIX) - char id_name[PREFIX_LEN + 1 + id_len * 2 + sizeof ".debug" - 1]; - strcpy (id_name, DEBUG_PREFIX); - int n = snprintf (&id_name[PREFIX_LEN - 1], - 4, "%02" PRIx8 "/", (uint8_t) build_id[0]); - assert (n == 3); - for (size_t i = 1; i < id_len; ++i) - { - n = snprintf (&id_name[PREFIX_LEN - 1 + 3 + (i - 1) * 2], - 3, "%02" PRIx8, (uint8_t) build_id[i]); - assert (n == 2); - } - strcpy (&id_name[PREFIX_LEN - 1 + 3 + (id_len - 1) * 2], - ".debug"); - - if (try_debugaltlink (result, id_name, build_id, id_len)) - return result; - - /* Everything failed, mark this Dwarf as not having an alternate, - but don't fail the load. The user may want to set it by hand - before usage. */ - result->alt_dwarf = NULL; - return result; -} -#endif /* ENABLE_DWZ */ - static Dwarf * check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp) { @@ -319,18 +211,6 @@ check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp) } #endif -#ifdef ENABLE_DWZ - Elf_Data *data = result->sectiondata[IDX_gnu_debugaltlink]; - if (data != NULL && data->d_size != 0) - { - const char *alt_name = data->d_buf; - const void *build_id = memchr (data->d_buf, '\0', data->d_size); - const int id_len = data->d_size - (build_id - data->d_buf + 1); - if (alt_name && build_id && id_len > 0) - return open_debugaltlink (result, alt_name, build_id + 1, id_len); - } -#endif /* ENABLE_DWZ */ - return result; } diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog index 5c1ab809..62ea412c 100644 --- a/libdwfl/ChangeLog +++ b/libdwfl/ChangeLog @@ -1,3 +1,11 @@ +2014-04-15 Florian Weimer <fweimer@redhat.com> + + * dwfl_module_getdwarf.c (__check_build_id): Moved from libdw. + (try_debugaltlink): Likewise. + (open_debugaltlink): Likewise. + (load_dw): Locate alternate debug information using + dwelf_dwarf_gnu_debugaltlink and call open_debugaltlink. + 2014-04-11 Mark Wielaard <mjw@redhat.com> * Makefile.am (AM_CPPFLAGS): Add libdwelf. diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c index f8a7816a..6163ddbe 100644 --- a/libdwfl/dwfl_module_getdwarf.c +++ b/libdwfl/dwfl_module_getdwarf.c @@ -27,12 +27,120 @@ not, see <http://www.gnu.org/licenses/>. */ #include "libdwflP.h" +#include <inttypes.h> #include <fcntl.h> #include <string.h> #include <unistd.h> #include "../libdw/libdwP.h" /* DWARF_E_* values are here. */ #include "../libelf/libelfP.h" +#ifdef ENABLE_DWZ +internal_function int +__check_build_id (Dwarf *dw, const uint8_t *build_id, const size_t id_len) +{ + if (dw == NULL) + return -1; + + Elf *elf = dw->elf; + Elf_Scn *scn = elf_nextscn (elf, NULL); + if (scn == NULL) + return -1; + + do + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + if (likely (shdr != NULL) && shdr->sh_type == SHT_NOTE) + { + size_t pos = 0; + GElf_Nhdr nhdr; + size_t name_pos; + size_t desc_pos; + Elf_Data *data = elf_getdata (scn, NULL); + while ((pos = gelf_getnote (data, pos, &nhdr, &name_pos, + &desc_pos)) > 0) + if (nhdr.n_type == NT_GNU_BUILD_ID + && nhdr.n_namesz == sizeof "GNU" + && ! memcmp (data->d_buf + name_pos, "GNU", sizeof "GNU")) + return (nhdr.n_descsz == id_len + && ! memcmp (data->d_buf + desc_pos, + build_id, id_len)) ? 0 : 1; + } + } + while ((scn = elf_nextscn (elf, scn)) != NULL); + + return -1; +} + +/* Try to open an debug alt link by name, checking build_id. + Marks free_alt on success, return NULL on failure. */ +static Dwarf * +try_debugaltlink (Dwarf *result, const char *try_name, + const uint8_t *build_id, const size_t id_len) +{ + int fd = open (try_name, O_RDONLY); + if (fd > 0) + { + Dwarf *alt_dwarf = INTUSE (dwarf_begin) (fd, DWARF_C_READ); + if (alt_dwarf != NULL) + { + Elf *elf = alt_dwarf->elf; + if (__check_build_id (alt_dwarf, build_id, id_len) == 0 + && elf_cntl (elf, ELF_C_FDREAD) == 0) + { + close (fd); + INTUSE (dwarf_setalt) (result, alt_dwarf); + result->free_alt = true; + return result; + } + INTUSE (dwarf_end) (result->alt_dwarf); + } + close (fd); + } + return NULL; +} + +/* For dwz multifile support, ignore if it looks wrong. */ +static Dwarf * +open_debugaltlink (Dwarf *result, const char *alt_name, + const uint8_t *build_id, const size_t id_len) +{ + /* First try the name itself, it is either an absolute path or + a relative one. Sadly we don't know relative from where at + this point. */ + if (try_debugaltlink (result, alt_name, build_id, id_len) != NULL) + return result; + + /* Lets try based on the build-id. This is somewhat distro specific, + we are following the Fedora implementation described at + https://fedoraproject.org/wiki/Releases/FeatureBuildId#Find_files_by_build_ID + */ +#define DEBUG_PREFIX "/usr/lib/debug/.build-id/" +#define PREFIX_LEN sizeof (DEBUG_PREFIX) + char id_name[PREFIX_LEN + 1 + id_len * 2 + sizeof ".debug" - 1]; + strcpy (id_name, DEBUG_PREFIX); + int n = snprintf (&id_name[PREFIX_LEN - 1], + 4, "%02" PRIx8 "/", (uint8_t) build_id[0]); + assert (n == 3); + for (size_t i = 1; i < id_len; ++i) + { + n = snprintf (&id_name[PREFIX_LEN - 1 + 3 + (i - 1) * 2], + 3, "%02" PRIx8, (uint8_t) build_id[i]); + assert (n == 2); + } + strcpy (&id_name[PREFIX_LEN - 1 + 3 + (id_len - 1) * 2], + ".debug"); + + if (try_debugaltlink (result, id_name, build_id, id_len)) + return result; + + /* Everything failed, mark this Dwarf as not having an alternate, + but don't fail the load. The user may want to set it by hand + before usage. */ + result->alt_dwarf = NULL; + return result; +} +#endif /* ENABLE_DWZ */ /* Open libelf FILE->fd and compute the load base of ELF as loaded in MOD. When we return success, FILE->elf and FILE->vaddr are set up. */ @@ -1122,6 +1230,19 @@ load_dw (Dwfl_Module *mod, struct dwfl_file *debugfile) return err == DWARF_E_NO_DWARF ? DWFL_E_NO_DWARF : DWFL_E (LIBDW, err); } +#ifdef ENABLE_DWZ + /* For dwz multifile support, ignore if it looks wrong. */ + { + const void *build_id; + const char *alt_name; + size_t id_len = INTUSE (dwelf_dwarf_gnu_debugaltlink) (mod->dw, + &alt_name, + &build_id); + if (id_len > 0) + open_debugaltlink (mod->dw, alt_name, build_id, id_len); + } +#endif /* ENABLE_DWZ */ + /* Until we have iterated through all CU's, we might do lazy lookups. */ mod->lazycu = 1; |