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,12 +6836,93 @@ 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) { struct section *s; Elf_Data *d; - uint8_t *buf; + uint8_t *buf, *new_buf; size_t sz, nbytes; uint64_t addr; int elferr, i, j; @@ -6865,6 +6949,13 @@ buf = d->d_buf; sz = d->d_size; addr = s->addr; + if (re->options & RE_Z) { + new_buf = NULL; + decompress_section(s, d->d_buf, d->d_size, + &new_buf, &sz); + if (new_buf) + buf = new_buf; + } printf("\nHex dump of section '%s':\n", s->name); while (sz > 0) { printf(" 0x%8.8jx ", (uintmax_t)addr); @@ -6888,6 +6979,8 @@ addr += nbytes; sz -= nbytes; } + if (new_buf) + free(new_buf); } } @@ -6896,8 +6989,9 @@ { struct section *s; Elf_Data *d; - unsigned char *start, *end, *buf_end; + unsigned char *start, *end, *buf_end, *new_buf; unsigned int len; + size_t sz; int i, j, elferr, found; for (i = 1; (size_t) i < re->shnum; i++) { @@ -6919,9 +7013,17 @@ 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) { + new_buf = NULL; + decompress_section(s, d->d_buf, d->d_size, + &new_buf, &sz); + if (new_buf) + start = new_buf; + } + buf_end = start + sz; printf("\nString dump of section '%s':\n", s->name); for (;;) { while (start < buf_end && !isprint(*start)) @@ -6942,6 +7044,8 @@ break; start = end + 1; } + if (new_buf) + free(new_buf); if (!found) printf(" No strings found in this section."); putchar('\n'); @@ -7567,6 +7671,7 @@ Display DWARF information.\n\ -x INDEX | --hex-dump=INDEX\n\ Display contents of a section as hexadecimal.\n\ + -z | --decompress Decompress the contents of a section before displaying it.\n\ -A | --arch-specific (accepted, but ignored)\n\ -D | --use-dynamic Print the symbol table specified by the DT_SYMTAB\n\ entry in the \".dynamic\" section.\n\ @@ -7601,7 +7706,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 +7803,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