Index: contrib/elftoolchain/readelf/readelf.1 =================================================================== --- contrib/elftoolchain/readelf/readelf.1 +++ contrib/elftoolchain/readelf/readelf.1 @@ -24,7 +24,7 @@ .\" .\" $Id: readelf.1 3753 2019-06-28 01:13:13Z emaste $ .\" -.Dd June 27, 2019 +.Dd October 26, 2020 .Dt READELF 1 .Os .Sh NAME @@ -49,6 +49,7 @@ .Fl -debug-dump Ns Op Ns = Ns Ar long-option-name , Ns ... .Oc .Op Fl x Ar section | Fl -hex-dump Ns = Ns Ar section +.Op Fl z | Fl -decompress .Op Fl A | Fl -arch-specific .Op Fl D | Fl -use-dynamic .Op Fl H | Fl -help @@ -157,6 +158,13 @@ The argument .Ar section should be the name of a section or a numeric section index. +.It Fl z | Fl -decompress +Decompress contents of section specified by: +.Fl x +or +.Fl p +before displaying. +If the specified section is not compressed, it is displayed as is. .It Fl A | Fl -arch-specific This option is accepted but is currently unimplemented. .It Fl D | Fl -use-dynamic Index: contrib/elftoolchain/readelf/readelf.c =================================================================== --- contrib/elftoolchain/readelf/readelf.c +++ contrib/elftoolchain/readelf/readelf.c @@ -40,12 +40,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include @@ -87,6 +89,7 @@ #define RE_WW 0x00040000 #define RE_W 0x00080000 #define RE_X 0x00100000 +#define RE_Z 0x00200000 /* * dwarf dump options. @@ -189,6 +192,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,17 +6837,96 @@ return (sym.st_value); } +/* + * Decompress a data section if needed (using ZLIB). + * Returns true if sucessful, false otherwise. + */ +static bool 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 (false); + } + + 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 (true); + fail: + inflateEnd(&strm); + if (strm.msg) + warnx("%s", strm.msg); + else + warnx("ZLIB error: %d", ret); + free(uncompressed_data_buffer); + return (false); + } + return (false); +} + 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; for (i = 1; (size_t) i < re->shnum; i++) { + new_buf = NULL; s = &re->sl[i]; if (find_dumpop(re, (size_t) i, s->name, HEX_DUMP, -1) == NULL) continue; @@ -6865,6 +6948,11 @@ buf = d->d_buf; sz = d->d_size; addr = s->addr; + if (re->options & RE_Z) { + if (decompress_section(s, d->d_buf, d->d_size, + &new_buf, &sz)) + buf = new_buf; + } printf("\nHex dump of section '%s':\n", s->name); while (sz > 0) { printf(" 0x%8.8jx ", (uintmax_t)addr); @@ -6888,6 +6976,9 @@ addr += nbytes; sz -= nbytes; } + if (new_buf) { + free(new_buf); + } } } @@ -6896,11 +6987,13 @@ { 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++) { + new_buf = NULL; s = &re->sl[i]; if (find_dumpop(re, (size_t) i, s->name, STR_DUMP, -1) == NULL) continue; @@ -6919,9 +7012,15 @@ 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) { + if (decompress_section(s, d->d_buf, d->d_size, + &new_buf, &sz)) + 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 +7041,9 @@ break; start = end + 1; } + if (new_buf) { + free(new_buf); + } if (!found) printf(" No strings found in this section."); putchar('\n'); @@ -7567,6 +7669,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 +7704,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 +7801,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