Index: contrib/elftoolchain/libelf/_libelf.h =================================================================== --- contrib/elftoolchain/libelf/_libelf.h +++ contrib/elftoolchain/libelf/_libelf.h @@ -220,6 +220,7 @@ size_t count); _libelf_translator_function *_libelf_get_translator(Elf_Type _t, int _direction, int _elfclass, int _elfmachine); +void *_libelf_getchdr(Elf_Scn *_e, int _elfclass); void *_libelf_getphdr(Elf *_e, int _elfclass); void *_libelf_getshdr(Elf_Scn *_scn, int _elfclass); void _libelf_init_elf(Elf *_e, Elf_Kind _kind); Index: contrib/elftoolchain/libelf/gelf.h =================================================================== --- contrib/elftoolchain/libelf/gelf.h +++ contrib/elftoolchain/libelf/gelf.h @@ -39,6 +39,7 @@ typedef Elf64_Word GElf_Word; /* Unsigned words (32 bit) */ typedef Elf64_Xword GElf_Xword; /* Unsigned long words (64 bit) */ +typedef Elf64_Chdr GElf_Chdr; /* Compressed section header */ typedef Elf64_Dyn GElf_Dyn; /* ".dynamic" section entries */ typedef Elf64_Ehdr GElf_Ehdr; /* ELF header */ typedef Elf64_Phdr GElf_Phdr; /* Program header */ @@ -73,6 +74,7 @@ long gelf_checksum(Elf *_elf); size_t gelf_fsize(Elf *_elf, Elf_Type _type, size_t _count, unsigned int _version); +GElf_Chdr *gelf_getchdr(Elf_Scn *_scn, GElf_Chdr *_dst); int gelf_getclass(Elf *_elf); GElf_Dyn *gelf_getdyn(Elf_Data *_data, int _index, GElf_Dyn *_dst); GElf_Ehdr *gelf_getehdr(Elf *_elf, GElf_Ehdr *_dst); Index: contrib/elftoolchain/libelf/gelf_chdr.c =================================================================== --- /dev/null +++ contrib/elftoolchain/libelf/gelf_chdr.c @@ -0,0 +1,83 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2018 The FreeBSD Foundation + * + * This software was developed by Tiger Gao under sponsorship from + * the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include "_libelf.h" + + +Elf32_Chdr * +elf32_getchdr(Elf_Scn *s) +{ + return (_libelf_getchdr(s, ELFCLASS32)); +} + +Elf64_Chdr * +elf64_getchdr(Elf_Scn *s) +{ + return (_libelf_getchdr(s, ELFCLASS64)); +} + +GElf_Chdr * +gelf_getchdr(Elf_Scn *s, GElf_Chdr *d) +{ + int ec; + void *ch; + Elf32_Chdr *ch32; + Elf64_Chdr *ch64; + + if (d == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + if ((ch = _libelf_getchdr(s, ELFCLASSNONE)) == NULL) + return (NULL); + + ec = s->s_elf->e_class; + assert(ec == ELFCLASS32 || ec == ELFCLASS64); + + if (ec == ELFCLASS32) { + ch32 = (Elf32_Chdr *) ch; + + d->ch_type = (Elf64_Word) ch32->ch_type; + d->ch_size = (Elf64_Xword) ch32->ch_size; + d->ch_addralign = (Elf64_Xword) ch32->ch_addralign; + } else { + ch64 = (Elf64_Chdr *) ch; + *d = *ch64; + } + + return (d); +} Index: contrib/elftoolchain/libelf/libelf.h =================================================================== --- contrib/elftoolchain/libelf/libelf.h +++ contrib/elftoolchain/libelf/libelf.h @@ -153,9 +153,12 @@ ELF_E_CLASS, /* Mismatched ELF class */ ELF_E_DATA, /* Invalid data descriptor */ ELF_E_HEADER, /* Missing or malformed ELF header */ + ELF_E_INVALID_SECTION_FLAGS, /* Invalid ELF section header flags */ + ELF_E_INVALID_SECTION_TYPE, /* Invalid ELF section header type */ ELF_E_IO, /* I/O error */ ELF_E_LAYOUT, /* Layout constraint violation */ ELF_E_MODE, /* Wrong mode for ELF descriptor */ + ELF_E_NOT_COMPRESSED, /* Section is not compressed */ ELF_E_RANGE, /* Value out of range */ ELF_E_RESOURCE, /* Resource exhaustion */ ELF_E_SECTION, /* Invalid section descriptor */ @@ -227,6 +230,7 @@ long elf32_checksum(Elf *_elf); size_t elf32_fsize(Elf_Type _type, size_t _count, unsigned int _version); +Elf32_Chdr *elf32_getchdr(Elf_Scn *_scn); Elf32_Ehdr *elf32_getehdr(Elf *_elf); Elf32_Phdr *elf32_getphdr(Elf *_elf); Elf32_Shdr *elf32_getshdr(Elf_Scn *_scn); @@ -240,6 +244,7 @@ long elf64_checksum(Elf *_elf); size_t elf64_fsize(Elf_Type _type, size_t _count, unsigned int _version); +Elf64_Chdr *elf64_getchdr(Elf_Scn *_scn); Elf64_Ehdr *elf64_getehdr(Elf *_elf); Elf64_Phdr *elf64_getphdr(Elf *_elf); Elf64_Shdr *elf64_getshdr(Elf_Scn *_scn); Index: contrib/elftoolchain/libelf/libelf_chdr.c =================================================================== --- /dev/null +++ contrib/elftoolchain/libelf/libelf_chdr.c @@ -0,0 +1,105 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2018 The FreeBSD Foundation + * + * This software was developed by Tiger Gao under sponsorship from + * the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include "_libelf.h" + + +void * +_libelf_getchdr(Elf_Scn *s, int ec) +{ + Elf *e; + void *sh; + Elf32_Shdr *sh32; + Elf64_Shdr *sh64; + + sh32 = NULL; + sh64 = NULL; + + if (s == NULL || (e = s->s_elf) == NULL || + e->e_kind != ELF_K_ELF) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + if (ec == ELFCLASSNONE) + ec = e->e_class; + + if (ec != e->e_class) { + LIBELF_SET_ERROR(CLASS, 0); + return (NULL); + } + + if ((sh = _libelf_getshdr(s, ec)) == NULL) + return (NULL); + + if (ec == ELFCLASS32) { + sh32 = (Elf32_Shdr *) sh; + if ((sh32->sh_flags & SHF_ALLOC) != 0) { + LIBELF_SET_ERROR(INVALID_SECTION_FLAGS, 0); + return (NULL); + } + + if (sh32->sh_type == SHT_NULL || sh32->sh_type == SHT_NOBITS) { + LIBELF_SET_ERROR(INVALID_SECTION_TYPE, 0); + return (NULL); + } + + if ((sh32->sh_flags & SHF_COMPRESSED) == 0) { + LIBELF_SET_ERROR(NOT_COMPRESSED, 0); + return (NULL); + } + } else { + sh64 = (Elf64_Shdr *) sh; + if ((sh64->sh_flags & SHF_ALLOC) != 0) { + LIBELF_SET_ERROR(INVALID_SECTION_FLAGS, 0); + return (NULL); + } + + if (sh64->sh_type == SHT_NULL || sh64->sh_type == SHT_NOBITS) { + LIBELF_SET_ERROR(INVALID_SECTION_TYPE, 0); + return (NULL); + } + + if ((sh64->sh_flags & SHF_COMPRESSED) == 0) { + LIBELF_SET_ERROR(NOT_COMPRESSED, 0); + return (NULL); + } + } + + Elf_Data *d = elf_getdata(s, NULL); + + if (!d) + return (NULL); + + return ((void *) d->d_buf); +} Index: contrib/elftoolchain/readelf/readelf.c =================================================================== --- contrib/elftoolchain/readelf/readelf.c +++ contrib/elftoolchain/readelf/readelf.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -87,6 +88,7 @@ #define RE_WW 0x00040000 #define RE_W 0x00080000 #define RE_X 0x00100000 +#define RE_Z 0x00200000 /* * dwarf dump options. @@ -212,6 +214,7 @@ {"version-info", no_argument, 0, 'V'}, {"version", no_argument, 0, 'v'}, {"wide", no_argument, 0, 'W'}, + {"decompress", no_argument, 0, 'z'}, {NULL, 0, NULL, 0} }; @@ -6833,6 +6836,84 @@ return (sym.st_value); } +/* + * Decompress a data section if needed (using ZLIB). + */ +static int +decompress_section(struct section *s, unsigned char **buffer, uint64_t *sz) { + GElf_Shdr sh; + + if (gelf_getshdr(s->scn, &sh) == NULL) + errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", + elf_errmsg(-1)); + + if (sh.sh_flags & SHF_COMPRESSED) { + int ret; + GElf_Chdr chdr; + Elf64_Xword compressed_size; + unsigned char *compressed_data_buffer = NULL; + Elf64_Xword inflated_size; + unsigned char *uncompressed_data_buffer = NULL; + Elf64_Xword uncompressed_size; + z_stream strm; + + if (gelf_getchdr(s->scn, &chdr) == NULL) + errx(EXIT_FAILURE, "gelf_getchdr() failed: %s", + elf_errmsg(-1)); + if (chdr.ch_type != ELFCOMPRESS_ZLIB) + goto fail; + + compressed_data_buffer = *buffer; + compressed_size = *sz; + inflated_size = 0; + uncompressed_size = chdr.ch_size; + uncompressed_data_buffer = malloc(uncompressed_size); + compressed_data_buffer += sizeof(chdr); + compressed_size -= sizeof(chdr); + + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = compressed_size; + strm.avail_out = uncompressed_size; + ret = inflateInit(&strm); + + if (ret != Z_OK) + goto fail; + /* + * The section can contain several compressed buffers, + * so decompress in a loop until all data is inflated. + */ + while (inflated_size < compressed_size) { + strm.next_in = compressed_data_buffer + inflated_size; + strm.next_out = uncompressed_data_buffer + inflated_size; + ret = inflate(&strm, Z_FINISH); + if (ret != Z_STREAM_END) { + goto fail; + } + inflated_size = uncompressed_size - strm.avail_out; + ret = inflateReset(&strm); + if (ret != Z_OK) + goto fail; + } + if (strm.avail_out != 0) { + goto fail; + } + ret = inflateEnd(&strm); + if (ret != Z_OK) + goto fail; + free(*buffer); + *buffer = uncompressed_data_buffer; + *sz = uncompressed_size; + return (1); + fail: + free(uncompressed_data_buffer); + warnx("decompress_section failed: %s", elf_errmsg(-1)); + return (0); + } + return (1); +} + static void hex_dump(struct readelf *re) { @@ -6862,9 +6943,12 @@ s->name); continue; } + addr = s->addr; + if (re->options & RE_Z) { + decompress_section(s, (unsigned char **) &d->d_buf, &d->d_size); + } buf = d->d_buf; sz = d->d_size; - addr = s->addr; printf("\nHex dump of section '%s':\n", s->name); while (sz > 0) { printf(" 0x%8.8jx ", (uintmax_t)addr); @@ -6919,9 +7003,12 @@ s->name); continue; } - buf_end = (unsigned char *) d->d_buf + d->d_size; - start = (unsigned char *) d->d_buf; found = 0; + if (re->options & RE_Z) { + decompress_section(s, (unsigned char **) &d->d_buf, &d->d_size); + } + start = (unsigned char *) d->d_buf; + buf_end = start + d->d_size; printf("\nString dump of section '%s':\n", s->name); for (;;) { while (start < buf_end && !isprint(*start)) @@ -7601,7 +7688,7 @@ memset(re, 0, sizeof(*re)); STAILQ_INIT(&re->v_dumpop); - while ((opt = getopt_long(argc, argv, "AacDdegHhIi:lNnp:rSstuVvWw::x:", + while ((opt = getopt_long(argc, argv, "AacDdegHhIi:lNnp:rSstuVvWw::x:z", longopts, NULL)) != -1) { switch(opt) { case '?': @@ -7698,6 +7785,9 @@ add_dumpop(re, 0, optarg, HEX_DUMP, DUMP_BY_NAME); break; + case 'z': + re->options |= RE_Z; + break; case OPTION_DEBUG_DUMP: re->options |= RE_W; parse_dwarf_op_long(re, optarg); Index: lib/libelf/Makefile =================================================================== --- lib/libelf/Makefile +++ lib/libelf/Makefile @@ -38,6 +38,7 @@ elf_update.c \ elf_version.c \ gelf_cap.c \ + gelf_chdr.c \ gelf_checksum.c \ gelf_dyn.c \ gelf_ehdr.c \ @@ -57,6 +58,7 @@ libelf_allocate.c \ libelf_ar.c \ libelf_ar_util.c \ + libelf_chdr.c \ libelf_checksum.c \ libelf_data.c \ libelf_ehdr.c \ Index: usr.bin/readelf/Makefile =================================================================== --- usr.bin/readelf/Makefile +++ usr.bin/readelf/Makefile @@ -15,6 +15,7 @@ .if ${MK_CASPER} != "no" LIBADD+= casper LIBADD+= cap_fileargs +LIBADD+= z CFLAGS+= -DWITH_CASPER .endif