From dbf05458e3bd8c46f5e49918593557293a29d41a Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Mon, 6 Dec 2021 10:37:49 -0500 Subject: [PATCH] libdwarf: Support consumption of compressed ELF sections Automatically decompress zlib-compressed debug sections when loading them. This lets ctfcovert work on userland code after commit c910570e7573 ("Use compressed debug in standalone userland debug files by default"). Reported by: avg Reviewed by: avg, emaste MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D33139 --- contrib/elftoolchain/libdwarf/_libdwarf.h | 5 +- contrib/elftoolchain/libdwarf/libdwarf.h | 1 + .../elftoolchain/libdwarf/libdwarf_elf_init.c | 87 ++++++++++++++++--- lib/libdwarf/Makefile | 2 +- share/mk/src.libnames.mk | 2 +- 5 files changed, 80 insertions(+), 17 deletions(-) diff --git a/contrib/elftoolchain/libdwarf/_libdwarf.h b/contrib/elftoolchain/libdwarf/_libdwarf.h index 6658d2d2f6f4..68a4c61522fa 100644 --- a/contrib/elftoolchain/libdwarf/_libdwarf.h +++ b/contrib/elftoolchain/libdwarf/_libdwarf.h @@ -379,8 +379,9 @@ typedef struct _Dwarf_Rel_Section { } *Dwarf_Rel_Section; typedef struct { - Elf_Data *ed_data; - void *ed_alloc; + Elf_Data *ed_data; + void *ed_alloc; + size_t ed_size; /* Uncompressed size. */ } Dwarf_Elf_Data; typedef struct { diff --git a/contrib/elftoolchain/libdwarf/libdwarf.h b/contrib/elftoolchain/libdwarf/libdwarf.h index 6ec8f99c56a1..b1f9e0c8abc7 100644 --- a/contrib/elftoolchain/libdwarf/libdwarf.h +++ b/contrib/elftoolchain/libdwarf/libdwarf.h @@ -335,6 +335,7 @@ enum { DW_DLE_ARANGE_OFFSET_BAD, /* Invalid arange offset. */ DW_DLE_DEBUG_MACRO_INCONSISTENT,/* Invalid macinfo data. */ DW_DLE_ELF_SECT_ERR, /* Application callback failed. */ + DW_DLE_COMPRESSION, /* Section decompression error. */ DW_DLE_NUM /* Max error number. */ }; diff --git a/contrib/elftoolchain/libdwarf/libdwarf_elf_init.c b/contrib/elftoolchain/libdwarf/libdwarf_elf_init.c index e304ef164157..c9b6ae601e0e 100644 --- a/contrib/elftoolchain/libdwarf/libdwarf_elf_init.c +++ b/contrib/elftoolchain/libdwarf/libdwarf_elf_init.c @@ -25,6 +25,7 @@ */ #include "_libdwarf.h" +#include ELFTC_VCSID("$Id: libdwarf_elf_init.c 3475 2016-05-18 18:11:26Z emaste $"); @@ -168,21 +169,28 @@ _dwarf_elf_relocate(Dwarf_Debug dbg, Elf *elf, Dwarf_Elf_Data *ed, size_t shndx, return (DW_DLE_NONE); } - ed->ed_alloc = malloc(ed->ed_data->d_size); + /* + * A copy may already have been created if the section + * is compressed. + */ if (ed->ed_alloc == NULL) { - DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); - return (DW_DLE_MEMORY); + ed->ed_alloc = malloc(ed->ed_size); + if (ed->ed_alloc == NULL) { + DWARF_SET_ERROR(dbg, error, + DW_DLE_MEMORY); + return (DW_DLE_MEMORY); + } + memcpy(ed->ed_alloc, ed->ed_data->d_buf, + ed->ed_size); } - memcpy(ed->ed_alloc, ed->ed_data->d_buf, - ed->ed_data->d_size); if (sh.sh_type == SHT_REL) _dwarf_elf_apply_rel_reloc(dbg, - ed->ed_alloc, ed->ed_data->d_size, + ed->ed_alloc, ed->ed_size, rel, symtab_data, eh.e_ident[EI_DATA]); else _dwarf_elf_apply_rela_reloc(dbg, - ed->ed_alloc, ed->ed_data->d_size, - rel, symtab_data, eh.e_ident[EI_DATA]); + ed->ed_alloc, ed->ed_size, rel, symtab_data, + eh.e_ident[EI_DATA]); return (DW_DLE_NONE); } @@ -196,13 +204,58 @@ _dwarf_elf_relocate(Dwarf_Debug dbg, Elf *elf, Dwarf_Elf_Data *ed, size_t shndx, return (DW_DLE_NONE); } +static int +_dwarf_elf_decompress(Dwarf_Debug dbg, Dwarf_Elf_Object *e, Elf_Scn *scn, + Dwarf_Elf_Data *ed, GElf_Shdr *shdr, Dwarf_Error *error) +{ + GElf_Chdr chdr; + size_t hsize; + unsigned long csize; + + if (gelf_getchdr(scn, &chdr) == NULL) { + DWARF_SET_ELF_ERROR(dbg, error); + return (DW_DLE_ELF); + } + + if (chdr.ch_type != ELFCOMPRESS_ZLIB) { + DWARF_SET_ERROR(dbg, error, DW_DLE_COMPRESSION); + return (DW_DLE_COMPRESSION); + } + + if ((ed->ed_alloc = malloc(chdr.ch_size)) == NULL) { + DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); + return (DW_DLE_MEMORY); + } + + csize = chdr.ch_size; + hsize = e->eo_ehdr.e_ident[EI_CLASS] == ELFCLASS64 ? + sizeof(Elf64_Chdr) : sizeof(Elf32_Chdr); + if (uncompress(ed->ed_alloc, &csize, (char *)ed->ed_data->d_buf + hsize, + ed->ed_data->d_size - hsize) != Z_OK) { + DWARF_SET_ERROR(dbg, error, DW_DLE_COMPRESSION); + return (DW_DLE_COMPRESSION); + } + /* Sanity check. */ + if (csize != chdr.ch_size) { + DWARF_SET_ERROR(dbg, error, DW_DLE_COMPRESSION); + return (DW_DLE_COMPRESSION); + } + + ed->ed_size = chdr.ch_size; + shdr->sh_size = chdr.ch_size; + shdr->sh_addralign = chdr.ch_addralign; + + return (DW_DLE_NONE); +} + int _dwarf_elf_init(Dwarf_Debug dbg, Elf *elf, Dwarf_Error *error) { Dwarf_Obj_Access_Interface *iface; + Dwarf_Elf_Data *ed; Dwarf_Elf_Object *e; const char *name; - GElf_Shdr sh; + GElf_Shdr *es, sh; Elf_Scn *scn; Elf_Data *symtab_data; size_t symtab_ndx; @@ -319,8 +372,6 @@ _dwarf_elf_init(Dwarf_Debug dbg, Elf *elf, Dwarf_Error *error) if (sh.sh_type == SHT_NOBITS) continue; - memcpy(&e->eo_shdr[j], &sh, sizeof(sh)); - if ((name = elf_strptr(elf, e->eo_strndx, sh.sh_name)) == NULL) { DWARF_SET_ELF_ERROR(dbg, error); @@ -328,13 +379,15 @@ _dwarf_elf_init(Dwarf_Debug dbg, Elf *elf, Dwarf_Error *error) goto fail_cleanup; } + ed = &e->eo_data[j]; + es = &e->eo_shdr[j]; + memcpy(es, &sh, sizeof(sh)); for (i = 0; debug_name[i] != NULL; i++) { if (strcmp(name, debug_name[i])) continue; (void) elf_errno(); - if ((e->eo_data[j].ed_data = elf_getdata(scn, NULL)) == - NULL) { + if ((ed->ed_data = elf_getdata(scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) { _DWARF_SET_ERROR(dbg, error, @@ -344,6 +397,14 @@ _dwarf_elf_init(Dwarf_Debug dbg, Elf *elf, Dwarf_Error *error) } } + if ((sh.sh_flags & SHF_COMPRESSED) != 0) { + if (_dwarf_elf_decompress(dbg, e, scn, ed, + es, error) != DW_DLE_NONE) + goto fail_cleanup; + } else { + ed->ed_size = ed->ed_data->d_size; + } + if (_libdwarf.applyreloc) { if (_dwarf_elf_relocate(dbg, elf, &e->eo_data[j], elf_ndxscn(scn), symtab_ndx, diff --git a/lib/libdwarf/Makefile b/lib/libdwarf/Makefile index 03f40cdd85ee..a3ef95b2572a 100644 --- a/lib/libdwarf/Makefile +++ b/lib/libdwarf/Makefile @@ -98,7 +98,7 @@ sys/elf32.h sys/elf64.h sys/elf_common.h: ${SRCTOP}/sys/${.TARGET} .NOMETA mkdir -p ${.OBJDIR}/sys ln -sf ${.ALLSRC} ${.TARGET} -LIBADD+= elf +LIBADD+= elf z SHLIB_MAJOR= 4 diff --git a/share/mk/src.libnames.mk b/share/mk/src.libnames.mk index bc3ad9c4bf40..23d09a434466 100644 --- a/share/mk/src.libnames.mk +++ b/share/mk/src.libnames.mk @@ -329,7 +329,7 @@ _DP_fetch= ssl crypto _DP_fetch= md .endif _DP_execinfo= elf -_DP_dwarf= elf +_DP_dwarf= elf z _DP_dpv= dialog figpar util tinfow ncursesw _DP_dialog= tinfow ncursesw m _DP_cuse= pthread