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. @@ -189,6 +191,7 @@ {"arch-specific", no_argument, NULL, 'A'}, {"archive-index", no_argument, NULL, 'c'}, {"debug-dump", optional_argument, NULL, OPTION_DEBUG_DUMP}, + {"decompress", no_argument, 0, 'z'}, {"dynamic", no_argument, NULL, 'd'}, {"file-header", no_argument, NULL, 'h'}, {"full-section-name", no_argument, NULL, 'N'}, @@ -6833,6 +6836,86 @@ return (sym.st_value); } +/* + * Decompress a data section if needed (using ZLIB). + * Returns 0 if sucessful, 1 otherwise. + */ +static int decompress_section(struct section *s, + unsigned char *compressed_data_buffer, + uint64_t compressed_size, + unsigned char **ret_buf, + uint64_t *ret_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 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) { + warnx("unknown compression type: %d", chdr.ch_type); + return (1); + } + + 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) + warnx("Warning: wrong info in compression header."); + ret = inflateEnd(&strm); + if (ret != Z_OK) + goto fail; + *ret_buf = uncompressed_data_buffer; + *ret_sz = uncompressed_size; + return (0); + fail: + inflateEnd(&strm); + if (strm.msg) + warnx("%s", strm.msg); + else + warnx("ZLIB error: %d", ret); + free(uncompressed_data_buffer); + return (1); + } + return (1); +} + static void hex_dump(struct readelf *re) { @@ -6865,6 +6948,10 @@ buf = d->d_buf; sz = d->d_size; addr = s->addr; + if (re->options & RE_Z) { + (void)decompress_section(s, d->d_buf, d->d_size, + &buf, &sz); + } printf("\nHex dump of section '%s':\n", s->name); while (sz > 0) { printf(" 0x%8.8jx ", (uintmax_t)addr); @@ -6898,6 +6985,7 @@ Elf_Data *d; unsigned char *start, *end, *buf_end; unsigned int len; + size_t sz; int i, j, elferr, found; for (i = 1; (size_t) i < re->shnum; i++) { @@ -6919,9 +7007,14 @@ s->name); continue; } - buf_end = (unsigned char *) d->d_buf + d->d_size; - start = (unsigned char *) d->d_buf; found = 0; + start = d->d_buf; + sz = d->d_size; + if (re->options & RE_Z) { + (void)decompress_section(s, d->d_buf, d->d_size, + &start, &sz); + } + buf_end = start + sz; printf("\nString dump of section '%s':\n", s->name); for (;;) { while (start < buf_end && !isprint(*start)) @@ -7601,7 +7694,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 +7791,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: usr.bin/readelf/Makefile =================================================================== --- usr.bin/readelf/Makefile +++ usr.bin/readelf/Makefile @@ -10,7 +10,7 @@ PROG= readelf SRCS= readelf.c -LIBADD= dwarf elftc elf +LIBADD= dwarf elftc elf z .if ${MK_CASPER} != "no" LIBADD+= casper