diff --git a/elfutils-0.154-dwz.patch b/elfutils-0.154-dwz.patch new file mode 100644 index 0000000..c5c8635 --- /dev/null +++ b/elfutils-0.154-dwz.patch @@ -0,0 +1,474 @@ +https://lists.fedorahosted.org/pipermail/elfutils-devel/2012-July/002418.html + +From b1e42797293bcf34385d5cb0a18e8c773279241b Mon Sep 17 00:00:00 2001 +From: Mark Wielaard +Date: Fri, 22 Jun 2012 12:02:45 +0200 +Subject: [PATCH] libdw: Add support for DWZ multifile forms + DW_FORM_GNU_ref_alt/strp_alt. + +DWZ multifile forms http://www.dwarfstd.org/ShowIssue.php?issue=120604.1 +DW_FORM_GNU_ref_alt and DW_FORM_GNU_strp_alt reference an alternative +debuginfo file. dwarf_begin and dwarf_begin_elf will try to use this +automatically. There are no user visible changes to the libdw interface. + +dwarf_formref_die, dwarf_formstring and dwarf_formudata can now return +a Dwarf_Die which comes from a CU in the alternative Dwarf descriptor. + +__libdw_read_offset was adjusted to take an alternative Dwarf descriptor +into account. + +Signed-off-by: Mark Wielaard + +diff --git a/libdw/dwarf.h b/libdw/dwarf.h +index f41d296..81bc7fe 100644 +--- a/libdw/dwarf.h ++++ b/libdw/dwarf.h +@@ -299,7 +299,10 @@ enum + DW_FORM_sec_offset = 0x17, + DW_FORM_exprloc = 0x18, + DW_FORM_flag_present = 0x19, +- DW_FORM_ref_sig8 = 0x20 ++ DW_FORM_ref_sig8 = 0x20, ++ ++ DW_FORM_GNU_ref_alt = 0x1f20, /* offset in alternate .debuginfo. */ ++ DW_FORM_GNU_strp_alt = 0x1f21 /* offset in alternate .debug_str. */ + }; + + +diff --git a/libdw/dwarf_begin.c b/libdw/dwarf_begin.c +index 1f3fc3b..9f3050f 100644 +--- a/libdw/dwarf_begin.c ++++ b/libdw/dwarf_begin.c +@@ -98,3 +98,4 @@ dwarf_begin (fd, cmd) + + return result; + } ++INTDEF(dwarf_begin) +diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c +index 3e01800..fd95770 100644 +--- a/libdw/dwarf_begin_elf.c ++++ b/libdw/dwarf_begin_elf.c +@@ -31,12 +31,17 @@ + # include + #endif + ++#include ++#include + #include + #include + #include ++#include + #include + #include ++#include + #include ++#include + + #include "libdwP.h" + +@@ -66,6 +71,110 @@ static const char dwarf_scnnames[IDX_last][17] = + }; + #define ndwarf_scnnames (sizeof (dwarf_scnnames) / sizeof (dwarf_scnnames[0])) + ++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; ++} + + static Dwarf * + check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp) +@@ -110,6 +219,20 @@ check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp) + return NULL; + } + ++ /* For dwz multifile support, ignore if it looks wrong. */ ++ if (strcmp (scnname, ".gnu_debugaltlink") == 0) ++ { ++ Elf_Data *data = elf_getdata (scn, NULL); ++ 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); ++ } ++ } ++ + + /* Recognize the various sections. Most names start with .debug_. */ + size_t cnt; +diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c +index b77988f..e65314a 100644 +--- a/libdw/dwarf_end.c ++++ b/libdw/dwarf_end.c +@@ -111,6 +111,10 @@ dwarf_end (dwarf) + if (dwarf->free_elf) + elf_end (dwarf->elf); + ++ /* Free the alternative Dwarf descriptor if necessary. */ ++ if (dwarf->free_alt) ++ INTUSE (dwarf_end) (dwarf->alt_dwarf); ++ + /* Free the context descriptor. */ + free (dwarf); + } +diff --git a/libdw/dwarf_error.c b/libdw/dwarf_error.c +index 89047dc..2292914 100644 +--- a/libdw/dwarf_error.c ++++ b/libdw/dwarf_error.c +@@ -91,6 +91,7 @@ static const char *errmsgs[] = + [DWARF_E_INVALID_OFFSET] = N_("invalid offset"), + [DWARF_E_NO_DEBUG_RANGES] = N_(".debug_ranges section missing"), + [DWARF_E_INVALID_CFI] = N_("invalid CFI section"), ++ [DWARF_E_NO_ALT_DEBUGLINK] = N_("no alternative debug link found"), + }; + #define nerrmsgs (sizeof (errmsgs) / sizeof (errmsgs[0])) + +diff --git a/libdw/dwarf_formref.c b/libdw/dwarf_formref.c +index a2554e9..86da7ea 100644 +--- a/libdw/dwarf_formref.c ++++ b/libdw/dwarf_formref.c +@@ -72,6 +72,8 @@ __libdw_formref (attr, return_offset) + + case DW_FORM_ref_addr: + case DW_FORM_ref_sig8: ++ case DW_FORM_GNU_ref_alt: ++ /* These aren't handled by dwarf_formref, only by dwarf_formref_die. */ + __libdw_seterrno (DWARF_E_INVALID_REFERENCE); + return -1; + +diff --git a/libdw/dwarf_formref_die.c b/libdw/dwarf_formref_die.c +index 342f6b9..f070127 100644 +--- a/libdw/dwarf_formref_die.c ++++ b/libdw/dwarf_formref_die.c +@@ -46,7 +46,7 @@ dwarf_formref_die (attr, result) + struct Dwarf_CU *cu = attr->cu; + + Dwarf_Off offset; +- if (attr->form == DW_FORM_ref_addr) ++ if (attr->form == DW_FORM_ref_addr || attr->form == DW_FORM_GNU_ref_alt) + { + /* This has an absolute offset. */ + +@@ -54,11 +54,20 @@ dwarf_formref_die (attr, result) + ? cu->address_size + : cu->offset_size); + +- if (__libdw_read_offset (cu->dbg, IDX_debug_info, attr->valp, ++ Dwarf *dbg_ret = (attr->form == DW_FORM_GNU_ref_alt ++ ? cu->dbg->alt_dwarf : cu->dbg); ++ ++ if (dbg_ret == NULL) ++ { ++ __libdw_seterrno (DWARF_E_NO_ALT_DEBUGLINK); ++ return NULL; ++ } ++ ++ if (__libdw_read_offset (cu->dbg, dbg_ret, IDX_debug_info, attr->valp, + ref_size, &offset, IDX_debug_info, 0)) + return NULL; + +- return INTUSE(dwarf_offdie) (cu->dbg, offset, result); ++ return INTUSE(dwarf_offdie) (dbg_ret, offset, result); + } + + Elf_Data *data; +diff --git a/libdw/dwarf_formstring.c b/libdw/dwarf_formstring.c +index fe2183a..c66454e 100644 +--- a/libdw/dwarf_formstring.c ++++ b/libdw/dwarf_formstring.c +@@ -49,8 +49,17 @@ dwarf_formstring (attrp) + return (const char *) attrp->valp; + + Dwarf *dbg = attrp->cu->dbg; ++ Dwarf *dbg_ret = attrp->form == DW_FORM_GNU_strp_alt ? dbg->alt_dwarf : dbg; + +- if (unlikely (attrp->form != DW_FORM_strp) ++ if (unlikely (dbg_ret == NULL)) ++ { ++ __libdw_seterrno (DWARF_E_NO_ALT_DEBUGLINK); ++ return NULL; ++ } ++ ++ ++ if (unlikely (attrp->form != DW_FORM_strp ++ && attrp->form != DW_FORM_GNU_strp_alt) + || dbg->sectiondata[IDX_debug_str] == NULL) + { + __libdw_seterrno (DWARF_E_NO_STRING); +@@ -58,10 +67,10 @@ dwarf_formstring (attrp) + } + + uint64_t off; +- if (__libdw_read_offset (dbg, cu_sec_idx (attrp->cu), attrp->valp, ++ if (__libdw_read_offset (dbg, dbg_ret, cu_sec_idx (attrp->cu), attrp->valp, + attrp->cu->offset_size, &off, IDX_debug_str, 1)) + return NULL; + +- return (const char *) dbg->sectiondata[IDX_debug_str]->d_buf + off; ++ return (const char *) dbg_ret->sectiondata[IDX_debug_str]->d_buf + off; + } + INTDEF(dwarf_formstring) +diff --git a/libdw/dwarf_formudata.c b/libdw/dwarf_formudata.c +index f08e0d8..41b09e1 100644 +--- a/libdw/dwarf_formudata.c ++++ b/libdw/dwarf_formudata.c +@@ -52,7 +52,8 @@ __libdw_formptr (Dwarf_Attribute *attr, int sec_index, + Dwarf_Word offset; + if (attr->form == DW_FORM_sec_offset) + { +- if (__libdw_read_offset (attr->cu->dbg, cu_sec_idx (attr->cu), attr->valp, ++ if (__libdw_read_offset (attr->cu->dbg, attr->cu->dbg, ++ cu_sec_idx (attr->cu), attr->valp, + attr->cu->offset_size, &offset, sec_index, 0)) + return NULL; + } +@@ -63,7 +64,8 @@ __libdw_formptr (Dwarf_Attribute *attr, int sec_index, + { + case DW_FORM_data4: + case DW_FORM_data8: +- if (__libdw_read_offset (attr->cu->dbg, cu_sec_idx (attr->cu), ++ if (__libdw_read_offset (attr->cu->dbg, attr->cu->dbg, ++ cu_sec_idx (attr->cu), + attr->valp, + attr->form == DW_FORM_data4 ? 4 : 8, + &offset, sec_index, 0)) +diff --git a/libdw/dwarf_getpubnames.c b/libdw/dwarf_getpubnames.c +index 4ea3889..12728a3 100644 +--- a/libdw/dwarf_getpubnames.c ++++ b/libdw/dwarf_getpubnames.c +@@ -102,7 +102,8 @@ get_offsets (Dwarf *dbg) + } + + /* Get the CU offset. */ +- if (__libdw_read_offset (dbg, IDX_debug_pubnames, readp + 2, len_bytes, ++ if (__libdw_read_offset (dbg, dbg, IDX_debug_pubnames, ++ readp + 2, len_bytes, + &mem[cnt].cu_offset, IDX_debug_info, 3)) + /* Error has been already set in reader. */ + goto err_return; +diff --git a/libdw/libdwP.h b/libdw/libdwP.h +index 77e1b31..da82e5d 100644 +--- a/libdw/libdwP.h ++++ b/libdw/libdwP.h +@@ -116,6 +116,7 @@ enum + DWARF_E_INVALID_OFFSET, + DWARF_E_NO_DEBUG_RANGES, + DWARF_E_INVALID_CFI, ++ DWARF_E_NO_ALT_DEBUGLINK + }; + + +@@ -127,6 +128,9 @@ struct Dwarf + /* The underlying ELF file. */ + Elf *elf; + ++ /* dwz alternate DWARF file. */ ++ Dwarf *alt_dwarf; ++ + /* The section data. */ + Elf_Data *sectiondata[IDX_last]; + +@@ -141,6 +145,9 @@ struct Dwarf + /* If true, we allocated the ELF descriptor ourselves. */ + bool free_elf; + ++ /* If true, we allocated the Dwarf descriptor for alt_dwarf ourselves. */ ++ bool free_alt; ++ + /* Information for traversing the .debug_pubnames section. This is + an array and separately allocated with malloc. */ + struct pubnames_s +@@ -580,13 +587,13 @@ __libdw_read_offset_inc (Dwarf *dbg, + } + + static inline int +-__libdw_read_offset (Dwarf *dbg, ++__libdw_read_offset (Dwarf *dbg, Dwarf *dbg_ret, + int sec_index, const unsigned char *addr, + int width, Dwarf_Off *ret, int sec_ret, + size_t size) + { + READ_AND_RELOCATE (__libdw_relocate_offset, (*ret)); +- return __libdw_offset_in_section (dbg, sec_ret, *ret, size); ++ return __libdw_offset_in_section (dbg_ret, sec_ret, *ret, size); + } + + static inline size_t +@@ -617,12 +624,19 @@ unsigned char * __libdw_formptr (Dwarf_Attribute *attr, int sec_index, + Dwarf_Off *offsetp) + internal_function; + ++/* Checks that the build_id of the underlying Elf matches the expected. ++ Returns zero on match, -1 on error or no build_id found or 1 when ++ build_id doesn't match. */ ++int __check_build_id (Dwarf *dw, const uint8_t *build_id, const size_t id_len) ++ internal_function; ++ + + + /* Aliases to avoid PLTs. */ + INTDECL (dwarf_aggregate_size) + INTDECL (dwarf_attr) + INTDECL (dwarf_attr_integrate) ++INTDECL (dwarf_begin) + INTDECL (dwarf_begin_elf) + INTDECL (dwarf_child) + INTDECL (dwarf_dieoffset) +diff --git a/libdw/libdw_form.c b/libdw/libdw_form.c +index 2ff8868..c476a6e 100644 +--- a/libdw/libdw_form.c ++++ b/libdw/libdw_form.c +@@ -58,6 +58,8 @@ __libdw_form_val_len (Dwarf *dbg, struct Dwarf_CU *cu, unsigned int form, + + case DW_FORM_strp: + case DW_FORM_sec_offset: ++ case DW_FORM_GNU_ref_alt: ++ case DW_FORM_GNU_strp_alt: + result = cu->offset_size; + break; + +diff --git a/src/readelf.c b/src/readelf.c +index 3a27f8f..644e0f7 100644 +--- a/src/readelf.c ++++ b/src/readelf.c +@@ -3651,6 +3651,20 @@ dwarf_form_string (unsigned int form) + + if (likely (form < nknown_forms)) + result = known_forms[form]; ++ else ++ { ++ /* GNU extensions use vendor numbers. */ ++ switch (form) ++ { ++ case DW_FORM_GNU_ref_alt: ++ result = "GNU_ref_alt"; ++ break; ++ ++ case DW_FORM_GNU_strp_alt: ++ result = "GNU_strp_alt"; ++ break; ++ } ++ } + + if (unlikely (result == NULL)) + { +@@ -5593,6 +5607,7 @@ attr_callback (Dwarf_Attribute *attrp, void *arg) + case DW_FORM_indirect: + case DW_FORM_strp: + case DW_FORM_string: ++ case DW_FORM_GNU_strp_alt: + if (cbargs->silent) + break; + const char *str = dwarf_formstring (attrp); +@@ -5608,7 +5623,8 @@ attr_callback (Dwarf_Attribute *attrp, void *arg) + case DW_FORM_ref8: + case DW_FORM_ref4: + case DW_FORM_ref2: +- case DW_FORM_ref1:; ++ case DW_FORM_ref1: ++ case DW_FORM_GNU_ref_alt: + if (cbargs->silent) + break; + Dwarf_Die ref; diff --git a/elfutils.spec b/elfutils.spec index 2161c98..c0d249a 100644 --- a/elfutils.spec +++ b/elfutils.spec @@ -1,7 +1,7 @@ Name: elfutils Summary: A collection of utilities and DSOs to handle compiled objects Version: 0.154 -%global baserelease 2 +%global baserelease 3 URL: https://fedorahosted.org/elfutils/ %global source_url http://fedorahosted.org/releases/e/l/elfutils/%{version}/ License: GPLv3+ and (GPLv2+ or LGPLv3+) @@ -47,6 +47,7 @@ Patch1: %{?source_url}elfutils-robustify.patch Patch2: %{?source_url}elfutils-portability.patch Patch3: elfutils-0.154-binutils-pr-ld-13621.patch Patch4: elfutils-0.154-xlatetom-835877.patch +Patch5: elfutils-0.154-dwz.patch %if !%{compat} Release: %{baserelease}%{?dist} @@ -213,6 +214,7 @@ sed -i.scanf-m -e 's/%m/%a/g' src/addr2line.c tests/line2addr.c %patch3 -p1 -b .binutils-pr-ld-13621 %patch4 -p1 -b .xlatetom-835877 +%patch5 -p1 -b .dwz find . -name \*.sh ! -perm -0100 -print | xargs chmod +x @@ -329,6 +331,9 @@ rm -rf ${RPM_BUILD_ROOT} %{_libdir}/libelf.a %changelog +* Wed Aug 01 2012 Mark Wielaard 0.154-3 +- Add dwz support + * Mon Jul 18 2012 Mark Wielaard 0.154-2 - Add upstream xlatetom fix (#835877)