From 0e602686df5677fee06cbd1718b4a7aa5379cd2a Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Fri, 15 May 2015 17:16:31 +0100 Subject: [PATCH] Add --decompress option to readelf to decompress sections before they are dumped. bin * readelf.c (options): Add "decompress". (usage): Mention -z/--decompress. (parse_args): Handle -z. (uncompress_section_contents): Move to earlier in the file. (dump_section_as_strings): If requested, decompress the section before dumping. (dump_section_as_bytes): Likewise. * doc/binutils.texi: Document the new option. tests * binutils-all/z.s: New test. Checks the --decompress option to readelf. * binutils-all/readelf.exp: Run the test. * binutils-all/readelf.z: Expected output from readelf. --- binutils/ChangeLog | 11 ++ binutils/doc/binutils.texi | 7 + binutils/readelf.c | 241 +++++++++++++++++++--------- binutils/testsuite/ChangeLog | 7 + binutils/testsuite/binutils-all/readelf.exp | 46 ++++-- binutils/testsuite/binutils-all/readelf.z | 8 + binutils/testsuite/binutils-all/z.s | 70 ++++++++ 7 files changed, 303 insertions(+), 87 deletions(-) create mode 100644 binutils/testsuite/binutils-all/readelf.z create mode 100644 binutils/testsuite/binutils-all/z.s diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 5d017a1..ee2ddf0 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,14 @@ +2015-05-15 Nick Clifton + + * readelf.c (options): Add "decompress". + (usage): Mention -z/--decompress. + (parse_args): Handle -z. + (uncompress_section_contents): Move to earlier in the file. + (dump_section_as_strings): If requested, decompress the section + before dumping. + (dump_section_as_bytes): Likewise. + * doc/binutils.texi: Document the new option. + 2015-05-14 Peter Bergner * MAINTAINERS: Add myself as PPC maintainer. diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi index 601de48..619c28e 100644 --- a/binutils/doc/binutils.texi +++ b/binutils/doc/binutils.texi @@ -4344,6 +4344,7 @@ readelf [@option{-a}|@option{--all}] [@option{-x} |@option{--hex-dump=}] [@option{-p} |@option{--string-dump=}] [@option{-R} |@option{--relocated-dump=}] + [@option{-z}|@option{--decompress}] [@option{-c}|@option{--archive-index}] [@option{-w[lLiaprmfFsoRt]}| @option{--debug-dump}[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=loc,=Ranges,=pubtypes,=trace_info,=trace_abbrev,=trace_aranges,=gdb_index]] @@ -4492,6 +4493,12 @@ Displays the contents of the indicated section as printable strings. A number identifies a particular section by index in the section table; any other string identifies all sections with that name in the object file. +@item -z +@itemx --decompress +Requests that the section(s) being dumped by @option{x}, @option{R} or +@option{p} options are decompressed before being displayed. If the +section(s) are not compressed then they are displayed as is. + @item -c @itemx --archive-index @cindex Archive file symbol index information diff --git a/binutils/readelf.c b/binutils/readelf.c index e299e1b..4bb31eb 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -209,6 +209,7 @@ static int do_arch; static int do_notes; static int do_archive_index; static int is_32bit_elf; +static int decompress_dumps; struct group_list { @@ -3960,6 +3961,7 @@ static struct option options[] = {"hex-dump", required_argument, 0, 'x'}, {"relocated-dump", required_argument, 0, 'R'}, {"string-dump", required_argument, 0, 'p'}, + {"decompress", no_argument, 0, 'z'}, #ifdef SUPPORT_DISASSEMBLY {"instruction-dump", required_argument, 0, 'i'}, #endif @@ -4007,6 +4009,7 @@ usage (FILE * stream) Dump the contents of section as strings\n\ -R --relocated-dump=\n\ Dump the contents of section as relocated bytes\n\ + -z --decompress Decompress section before dumping it\n\ -w[lLiaprmfFsoRt] or\n\ --debug-dump[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,\n\ =frames-interp,=str,=loc,=Ranges,=pubtypes,\n\ @@ -4117,7 +4120,7 @@ parse_args (int argc, char ** argv) usage (stderr); while ((c = getopt_long - (argc, argv, "ADHINR:SVWacdeghi:lnp:rstuvw::x:", options, NULL)) != EOF) + (argc, argv, "ADHINR:SVWacdeghi:lnp:rstuvw::x:z", options, NULL)) != EOF) { switch (c) { @@ -4200,6 +4203,9 @@ parse_args (int argc, char ** argv) case 'R': request_dump (RELOC_DUMP); break; + case 'z': + decompress_dumps++; + break; case 'w': do_dump++; if (optarg == 0) @@ -11939,23 +11945,120 @@ get_section_contents (Elf_Internal_Shdr * section, FILE * file) _("section contents")); } +/* Uncompresses a section that was compressed using zlib, in place. */ + +static bfd_boolean +uncompress_section_contents (unsigned char **buffer, + dwarf_size_type uncompressed_size, + dwarf_size_type *size) +{ + dwarf_size_type compressed_size = *size; + unsigned char * compressed_buffer = *buffer; + unsigned char * uncompressed_buffer; + z_stream strm; + int rc; + + /* It is possible the section consists of several compressed + buffers concatenated together, so we uncompress in a loop. */ + /* PR 18313: The state field in the z_stream structure is supposed + to be invisible to the user (ie us), but some compilers will + still complain about it being used without initialisation. So + we first zero the entire z_stream structure and then set the fields + that we need. */ + memset (& strm, 0, sizeof strm); + strm.avail_in = compressed_size; + strm.next_in = (Bytef *) compressed_buffer; + strm.avail_out = uncompressed_size; + uncompressed_buffer = (unsigned char *) xmalloc (uncompressed_size); + + rc = inflateInit (& strm); + while (strm.avail_in > 0) + { + if (rc != Z_OK) + goto fail; + strm.next_out = ((Bytef *) uncompressed_buffer + + (uncompressed_size - strm.avail_out)); + rc = inflate (&strm, Z_FINISH); + if (rc != Z_STREAM_END) + goto fail; + rc = inflateReset (& strm); + } + rc = inflateEnd (& strm); + if (rc != Z_OK + || strm.avail_out != 0) + goto fail; + + *buffer = uncompressed_buffer; + *size = uncompressed_size; + return TRUE; + + fail: + free (uncompressed_buffer); + /* Indicate decompression failure. */ + *buffer = NULL; + return FALSE; +} static void dump_section_as_strings (Elf_Internal_Shdr * section, FILE * file) { - Elf_Internal_Shdr * relsec; - bfd_size_type num_bytes; - char * data; - char * end; - char * start; - bfd_boolean some_strings_shown; - - start = get_section_contents (section, file); + Elf_Internal_Shdr * relsec; + bfd_size_type num_bytes; + char * data; + char * end; + char * real_start; + char * start; + bfd_boolean some_strings_shown; + + real_start = start = get_section_contents (section, file); if (start == NULL) return; + num_bytes = section->sh_size; printf (_("\nString dump of section '%s':\n"), printable_section_name (section)); + if (decompress_dumps) + { + dwarf_size_type new_size = num_bytes; + dwarf_size_type uncompressed_size = 0; + + if ((section->sh_flags & SHF_COMPRESSED) != 0) + { + Elf_Internal_Chdr chdr; + unsigned int compression_header_size + = get_compression_header (& chdr, (unsigned char *) start); + + if (chdr.ch_type == ELFCOMPRESS_ZLIB + && chdr.ch_addralign == section->sh_addralign) + { + uncompressed_size = chdr.ch_size; + start += compression_header_size; + new_size -= compression_header_size; + } + } + else if (new_size > 12 && streq ((char *) start, "ZLIB")) + { + /* Read the zlib header. In this case, it should be "ZLIB" + followed by the uncompressed section size, 8 bytes in + big-endian order. */ + uncompressed_size = start[4]; uncompressed_size <<= 8; + uncompressed_size += start[5]; uncompressed_size <<= 8; + uncompressed_size += start[6]; uncompressed_size <<= 8; + uncompressed_size += start[7]; uncompressed_size <<= 8; + uncompressed_size += start[8]; uncompressed_size <<= 8; + uncompressed_size += start[9]; uncompressed_size <<= 8; + uncompressed_size += start[10]; uncompressed_size <<= 8; + uncompressed_size += start[11]; + start += 12; + new_size -= 12; + } + + if (uncompressed_size + && uncompress_section_contents ((unsigned char **) & start, + uncompressed_size, & new_size)) + num_bytes = new_size; + } + /* If the section being dumped has relocations against it the user might be expecting these relocations to have been applied. Check for this case and issue a warning message in order to avoid confusion. @@ -11976,7 +12079,6 @@ dump_section_as_strings (Elf_Internal_Shdr * section, FILE * file) break; } - num_bytes = section->sh_size; data = start; end = start + num_bytes; some_strings_shown = FALSE; @@ -12016,7 +12118,7 @@ dump_section_as_strings (Elf_Internal_Shdr * section, FILE * file) if (! some_strings_shown) printf (_(" No strings found in this section.")); - free (start); + free (real_start); putchar ('\n'); } @@ -12027,20 +12129,65 @@ dump_section_as_bytes (Elf_Internal_Shdr * section, bfd_boolean relocate) { Elf_Internal_Shdr * relsec; - bfd_size_type bytes; - bfd_vma addr; - unsigned char * data; - unsigned char * start; - - start = (unsigned char *) get_section_contents (section, file); + bfd_size_type bytes; + bfd_size_type section_size; + bfd_vma addr; + unsigned char * data; + unsigned char * real_start; + unsigned char * start; + + real_start = start = (unsigned char *) get_section_contents (section, file); if (start == NULL) return; + section_size = section->sh_size; printf (_("\nHex dump of section '%s':\n"), printable_section_name (section)); + if (decompress_dumps) + { + dwarf_size_type new_size = section_size; + dwarf_size_type uncompressed_size = 0; + + if ((section->sh_flags & SHF_COMPRESSED) != 0) + { + Elf_Internal_Chdr chdr; + unsigned int compression_header_size + = get_compression_header (& chdr, start); + + if (chdr.ch_type == ELFCOMPRESS_ZLIB + && chdr.ch_addralign == section->sh_addralign) + { + uncompressed_size = chdr.ch_size; + start += compression_header_size; + new_size -= compression_header_size; + } + } + else if (new_size > 12 && streq ((char *) start, "ZLIB")) + { + /* Read the zlib header. In this case, it should be "ZLIB" + followed by the uncompressed section size, 8 bytes in + big-endian order. */ + uncompressed_size = start[4]; uncompressed_size <<= 8; + uncompressed_size += start[5]; uncompressed_size <<= 8; + uncompressed_size += start[6]; uncompressed_size <<= 8; + uncompressed_size += start[7]; uncompressed_size <<= 8; + uncompressed_size += start[8]; uncompressed_size <<= 8; + uncompressed_size += start[9]; uncompressed_size <<= 8; + uncompressed_size += start[10]; uncompressed_size <<= 8; + uncompressed_size += start[11]; + start += 12; + new_size -= 12; + } + + if (uncompressed_size + && uncompress_section_contents (& start, uncompressed_size, + & new_size)) + section_size = new_size; + } + if (relocate) { - apply_relocations (file, section, start, section->sh_size, NULL, NULL); + apply_relocations (file, section, start, section_size, NULL, NULL); } else { @@ -12066,7 +12213,7 @@ dump_section_as_bytes (Elf_Internal_Shdr * section, } addr = section->sh_addr; - bytes = section->sh_size; + bytes = section_size; data = start; while (bytes) @@ -12106,65 +12253,11 @@ dump_section_as_bytes (Elf_Internal_Shdr * section, bytes -= lbytes; } - free (start); + free (real_start); putchar ('\n'); } -/* Uncompresses a section that was compressed using zlib, in place. */ - -static int -uncompress_section_contents (unsigned char **buffer, - dwarf_size_type uncompressed_size, - dwarf_size_type *size) -{ - dwarf_size_type compressed_size = *size; - unsigned char * compressed_buffer = *buffer; - unsigned char * uncompressed_buffer; - z_stream strm; - int rc; - - /* It is possible the section consists of several compressed - buffers concatenated together, so we uncompress in a loop. */ - /* PR 18313: The state field in the z_stream structure is supposed - to be invisible to the user (ie us), but some compilers will - still complain about it being used without initialisation. So - we first zero the entire z_stream structure and then set the fields - that we need. */ - memset (& strm, 0, sizeof strm); - strm.avail_in = compressed_size; - strm.next_in = (Bytef *) compressed_buffer; - strm.avail_out = uncompressed_size; - uncompressed_buffer = (unsigned char *) xmalloc (uncompressed_size); - - rc = inflateInit (& strm); - while (strm.avail_in > 0) - { - if (rc != Z_OK) - goto fail; - strm.next_out = ((Bytef *) uncompressed_buffer - + (uncompressed_size - strm.avail_out)); - rc = inflate (&strm, Z_FINISH); - if (rc != Z_STREAM_END) - goto fail; - rc = inflateReset (& strm); - } - rc = inflateEnd (& strm); - if (rc != Z_OK - || strm.avail_out != 0) - goto fail; - - *buffer = uncompressed_buffer; - *size = uncompressed_size; - return 1; - - fail: - free (uncompressed_buffer); - /* Indicate decompression failure. */ - *buffer = NULL; - return 0; -} - static int load_specific_debug_section (enum dwarf_section_display_enum debug, const Elf_Internal_Shdr * sec, void * file) diff --git a/binutils/testsuite/ChangeLog b/binutils/testsuite/ChangeLog index ad8d8ad..99801e2 100644 --- a/binutils/testsuite/ChangeLog +++ b/binutils/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2015-05-15 Nick Clifton + + * binutils-all/z.s: New test. Checks the --decompress option to + readelf. + * binutils-all/readelf.exp: Run the test. + * binutils-all/readelf.z: Expected output from readelf. + 2015-05-14 H.J. Lu * binutils-all/compress.exp: Replace "$OBJDUMP -s -j .debug_info" diff --git a/binutils/testsuite/binutils-all/readelf.exp b/binutils/testsuite/binutils-all/readelf.exp index 58e140c..59fd556 100644 --- a/binutils/testsuite/binutils-all/readelf.exp +++ b/binutils/testsuite/binutils-all/readelf.exp @@ -346,29 +346,49 @@ readelf_dump_test if {![binutils_assemble $srcdir/$subdir/version.s tmpdir/version.o]} then { perror "could not assemble version note test file" unresolved "readelf - failed to assemble" - return -} - -if ![is_remote host] { - set tempfile tmpdir/version.o + fail "readelf -n" } else { - set tempfile [remote_download host tmpdir/version.o] + + if ![is_remote host] { + set tempfile tmpdir/version.o + } else { + set tempfile [remote_download host tmpdir/version.o] + } + + readelf_test -n $tempfile readelf.n {} } -readelf_test -n $tempfile readelf.n {} # PR 18374 - Check that relocations against the .debug_loc section # do not prevent readelf from displaying all the location lists. if {![binutils_assemble $srcdir/$subdir/pr18374.s tmpdir/pr18374.o]} then { perror "could not assemble PR18374 test file" unresolved "readelf - failed to assemble" - return + fail "readelf --debug-loc" +} else { + + if ![is_remote host] { + set tempfile tmpdir/pr18374.o + } else { + set tempfile [remote_download host tmpdir/pr18374.o] + } + + readelf_test --debug-dump=loc $tempfile readelf.pr18374 {} } -if ![is_remote host] { - set tempfile tmpdir/pr18374.o + +# Check that decompressed dumps work. +if {![binutils_assemble $srcdir/$subdir/z.s tmpdir/z.o]} then { + perror "could not assemble decompress dump test file" + unresolved "readelf - failed to assemble" + fail "readelf -z" } else { - set tempfile [remote_download host tmpdir/pr18374.o] -} -readelf_test --debug-dump=loc $tempfile readelf.pr18374 {} + if ![is_remote host] { + set tempfile tmpdir/z.o + } else { + set tempfile [remote_download host tmpdir/z.o] + } + + readelf_test {--decompress --hex-dump .debug_loc} $tempfile readelf.z {} +} diff --git a/binutils/testsuite/binutils-all/readelf.z b/binutils/testsuite/binutils-all/readelf.z new file mode 100644 index 0000000..0843444 --- /dev/null +++ b/binutils/testsuite/binutils-all/readelf.z @@ -0,0 +1,8 @@ +Hex dump of section '.debug_loc': + 0x00000000 00000000 00000000 01005000 00000000 ..........P..... + 0x00000010 00000004 00f30150 9f000000 00000000 .......P........ + 0x00000020 00000000 00000000 00010051 00000000 ...........Q.... + 0x00000030 00000000 0300717f 9f000000 00000000 ......q......... + 0x00000040 000b0070 0020f301 51227000 229f0000 ...p. ..Q"p."... + 0x00000050 00000000 00000b00 70002070 0022f301 ........p. p.".. + 0x00000060 51229f00 00000000 000000 Q"......... diff --git a/binutils/testsuite/binutils-all/z.s b/binutils/testsuite/binutils-all/z.s new file mode 100644 index 0000000..2d24f33 --- /dev/null +++ b/binutils/testsuite/binutils-all/z.s @@ -0,0 +1,70 @@ + .section .debug_loc,"",%progbits + + .byte 0x5a + .byte 0x4c + .byte 0x49 + .byte 0x42 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x6b + .byte 0x78 + .byte 0x9c + .byte 0x63 + .byte 0x60 + .byte 0x80 + .byte 0x00 + .byte 0x46 + .byte 0x86 + .byte 0x00 + .byte 0x28 + .byte 0x8b + .byte 0x81 + .byte 0x85 + .byte 0xe1 + .byte 0x33 + .byte 0x63 + .byte 0xc0 + .byte 0x7c + .byte 0x06 + .byte 0x34 + .byte 0xc0 + .byte 0xc8 + .byte 0x10 + .byte 0x08 + .byte 0x63 + .byte 0x32 + .byte 0x33 + .byte 0x14 + .byte 0xd6 + .byte 0xc3 + .byte 0xe5 + .byte 0xb9 + .byte 0x19 + .byte 0x0a + .byte 0x18 + .byte 0x14 + .byte 0x3e + .byte 0x33 + .byte 0x06 + .byte 0x2a + .byte 0x15 + .byte 0x30 + .byte 0x28 + .byte 0xa1 + .byte 0x0a + .byte 0x02 + .byte 0x05 + .byte 0x40 + .byte 0xe2 + .byte 0x70 + .byte 0x41 + .byte 0x00 + .byte 0xc1 + .byte 0x6a + .byte 0x0a + .byte 0x83 -- 2.7.4