public inbox for binutils-cvs@sourceware.org
 help / color / mirror / Atom feed
* [binutils-gdb] Improve objdump's handling of compressed sections.
@ 2023-11-14 10:59 Nick Clifton
  0 siblings, 0 replies; only message in thread
From: Nick Clifton @ 2023-11-14 10:59 UTC (permalink / raw)
  To: bfd-cvs

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=fab62191f84583780c2c6d024d0e583400881770

commit fab62191f84583780c2c6d024d0e583400881770
Author: Nick Clifton <nickc@redhat.com>
Date:   Tue Nov 14 10:57:58 2023 +0000

    Improve objdump's handling of compressed sections.
    
      PR 31062
      * objdump.c (decompressed_dumps): New local variable. (usage): Mention the -z/--decompress option. (long_options): Add --decompress. (dump_section_header): Add "COMPRESSED" to the Flags field of any compressed section. (dump_section): Warn users when dumping a compressed section. (display_any_bfd): Decompress the section if decompressed_dumps is true. (main): Handle the -z/--decompress option.
      * NEWS: Mention the new feature.
      * doc/binutils.texi: Document the new feature.
      * testsuite/binutils-all/objdump.s: Update expected output.
      * testsuite/binutils-all/objdump.exp: Add test of -Z -s.
      * testsuite/binutils-all/objdump.Zs: New file.
      * readelf.c (maybe_expand_or_relocate_section): New function. Contains common code found in dump functions.  Adds a note message if a compressed section is not being decompressed. (dump_section_as_strings): Use new function. (dump_section_as_bytes): Likewise.

Diff:
---
 binutils/ChangeLog                          |  24 +++
 binutils/NEWS                               |   8 +
 binutils/doc/binutils.texi                  |  15 +-
 binutils/objdump.c                          |  17 +-
 binutils/readelf.c                          | 230 ++++++++++------------------
 binutils/testsuite/binutils-all/objdump.Zs  |   9 ++
 binutils/testsuite/binutils-all/objdump.exp |  16 ++
 binutils/testsuite/binutils-all/objdump.s   |   1 +
 8 files changed, 171 insertions(+), 149 deletions(-)

diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 57a8fa73ee3..d695d3b7496 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,27 @@
+2023-11-14  Nick Clifton  <nickc@redhat.com>
+
+	PR 31062
+	* objdump.c (decompressed_dumps): New local variable.
+	(usage): Mention the -z/--decompress option.
+	(long_options): Add --decompress.
+	(dump_section_header): Add "COMPRESSED" to the Flags field of any
+	compressed section.
+	(dump_section): Warn users when dumping a compressed section.
+	(display_any_bfd): Decompress the section if decompressed_dumps is
+	true.
+	(main): Handle the -z/--decompress option.
+	* NEWS: Mention the new feature.
+	* doc/binutils.texi: Document the new feature.
+	* testsuite/binutils-all/objdump.s: Update expected output.
+	* testsuite/binutils-all/objdump.exp: Add test of -Z -s.
+	* testsuite/binutils-all/objdump.Zs: New file.
+
+	* readelf.c (maybe_expand_or_relocate_section): New function.
+	Contains common code found in dump functions.  Adds a note message
+	if a compressed section is not being decompressed.
+	(dump_section_as_strings): Use new function.
+	(dump_section_as_bytes): Likewise.
+
 2023-11-10  Simon Marchi  <simon.marchi@efficios.com>
 
 	* readelf.c (decode_AMDGPU_machine_flags): Handle gfx1100,
diff --git a/binutils/NEWS b/binutils/NEWS
index 1aae340ea2a..3bf3b568179 100644
--- a/binutils/NEWS
+++ b/binutils/NEWS
@@ -1,5 +1,13 @@
 -*- text -*-
 
+* The objdump program has a new command line option -Z/--decompress which
+  changes the behaviour of the -s/--full-contents option, forcing it to
+  decompress the contents of any compressed section before they are displayed.
+
+  In addition when objdump is displaying sections headers (via the -h/--headers
+  command line option) it will now display "COMPRESSED" in the Flags field of
+  any compressed section.
+
 * The readelf program has a new command line option --extra-sym-info which
   extends the information displayed by the --symbols option.  When enabled
   the display will include the name of the section referenced by a symbol's
diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
index f94693631c7..ec23a78470e 100644
--- a/binutils/doc/binutils.texi
+++ b/binutils/doc/binutils.texi
@@ -2269,6 +2269,7 @@ objdump [@option{-a}|@option{--archive-headers}]
         [@option{-r}|@option{--reloc}]
         [@option{-R}|@option{--dynamic-reloc}]
         [@option{-s}|@option{--full-contents}]
+        [@option{-Z}|@option{--decompress}]
         [@option{-W[lLiaprmfFsoORtUuTgAck]}|
          @option{--dwarf}[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=str-offsets,=loc,=Ranges,=pubtypes,=trace_info,=trace_abbrev,=trace_aranges,=gdb_index,=addr,=cu_index,=links]]
         [@option{-WK}|@option{--dwarf=follow-links}]
@@ -2800,7 +2801,10 @@ disassembly.
 @cindex object file sections
 Display the full contents of sections, often used in combination with
 @option{-j} to request specific sections.  By default all non-empty
-non-bss sections are displayed.
+non-bss sections are displayed.  By default any compressed section
+will be displayed in its compressed form.  In order to see the
+contents in a decompressed form add the @option{-Z} option to the
+command line.
 
 @item -S
 @itemx --source
@@ -3056,6 +3060,15 @@ Also do not truncate symbol names when they are displayed.
 Normally the disassembly output will skip blocks of zeroes.  This
 option directs the disassembler to disassemble those blocks, just like
 any other data.
+
+@item -Z
+@itemx --decompress
+@cindex sections, full contents
+@cindex object file sections
+@cindex compressed section contents
+The @option{-Z} option is meant to be used in conunction with the
+@option{-s} option.  It instructs @command{objdump} to decompress any
+compressed sections before displaying their contents.
 @end table
 
 @c man end
diff --git a/binutils/objdump.c b/binutils/objdump.c
index 60813426566..640ccb5dbc1 100644
--- a/binutils/objdump.c
+++ b/binutils/objdump.c
@@ -137,6 +137,7 @@ static bool color_output = false;	/* --visualize-jumps=color.  */
 static bool extended_color_output = false; /* --visualize-jumps=extended-color.  */
 static int process_links = false;       /* --process-links.  */
 static int show_all_symbols;            /* --show-all-symbols.  */
+static bool decompressed_dumps = false; /* -Z, --decompress.  */
 
 static enum color_selection
   {
@@ -278,6 +279,8 @@ usage (FILE *stream, int status)
   fprintf (stream, _("\
   -s, --full-contents      Display the full contents of all sections requested\n"));
   fprintf (stream, _("\
+  -Z, --decompress         Decompress section(s) before displaying their contents\n"));
+  fprintf (stream, _("\
   -g, --debugging          Display debug information in object file\n"));
   fprintf (stream, _("\
   -e, --debugging-tags     Display debug information using ctags style\n"));
@@ -500,6 +503,7 @@ static struct option long_options[]=
 #endif
   {"debugging", no_argument, NULL, 'g'},
   {"debugging-tags", no_argument, NULL, 'e'},
+  {"decompress", no_argument, NULL, 'Z'},
   {"demangle", optional_argument, NULL, 'C'},
   {"disassemble", optional_argument, NULL, 'd'},
   {"disassemble-all", no_argument, NULL, 'D'},
@@ -930,6 +934,9 @@ dump_section_header (bfd *abfd, asection *section, void *data)
       comma = ", ";
     }
 
+  if (bfd_is_section_compressed (abfd, section))
+    printf ("%sCOMPRESSED", comma);
+
   printf ("\n");
 #undef PF
 }
@@ -5024,6 +5031,9 @@ dump_section (bfd *abfd, asection *section, void *dummy ATTRIBUTE_UNUSED)
 	    (unsigned long) (section->filepos + start_offset));
   printf ("\n");
 
+  if (bfd_is_section_compressed (abfd, section) && ! decompressed_dumps)
+    printf (_(" NOTE: This section is compressed, but its contents have NOT been expanded for this dump.\n"));
+
   if (!bfd_get_full_section_contents (abfd, section, &data))
     {
       non_fatal (_("Reading section %s failed because: %s"),
@@ -5780,7 +5790,7 @@ static void
 display_any_bfd (bfd *file, int level)
 {
   /* Decompress sections unless dumping the section contents.  */
-  if (!dump_section_contents)
+  if (!dump_section_contents || decompressed_dumps)
     file->flags |= BFD_DECOMPRESS;
 
   /* If the file is an archive, process all of its elements.  */
@@ -5897,7 +5907,7 @@ main (int argc, char **argv)
   set_default_bfd_target ();
 
   while ((c = getopt_long (argc, argv,
-			   "CDE:FGHI:LM:P:RSTU:VW::ab:defghij:lm:prstvwxz",
+			   "CDE:FGHI:LM:P:RSTU:VW::Zab:defghij:lm:prstvwxz",
 			   long_options, (int *) 0))
 	 != EOF)
     {
@@ -5908,6 +5918,9 @@ main (int argc, char **argv)
 	case 'm':
 	  machine = optarg;
 	  break;
+	case 'Z':
+	  decompressed_dumps = true;
+	  break;
 	case 'M':
 	  {
 	    char *options;
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 661ef0aab18..775106fb99c 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -15961,35 +15961,18 @@ uncompress_section_contents (bool              is_zstd,
   return false;
 }
 
-static bool
-dump_section_as_strings (Elf_Internal_Shdr * section, Filedata * filedata)
+static uint64_t
+maybe_expand_or_relocate_section (Elf_Internal_Shdr *  section,
+				  Filedata *           filedata,
+				  unsigned char **     start_ptr,
+				  bool                 relocate)
 {
-  Elf_Internal_Shdr *relsec;
-  uint64_t num_bytes;
-  unsigned char *data;
-  unsigned char *end;
-  unsigned char *real_start;
-  unsigned char *start;
-  bool some_strings_shown;
-
-  real_start = start = (unsigned char *) get_section_contents (section, filedata);
-  if (start == NULL)
-    /* PR 21820: Do not fail if the section was empty.  */
-    return section->sh_size == 0 || section->sh_type == SHT_NOBITS;
-
-  num_bytes = section->sh_size;
-
-  if (filedata->is_separate)
-    printf (_("\nString dump of section '%s' in linked file %s:\n"),
-	    printable_section_name (filedata, section),
-	    filedata->file_name);
-  else
-    printf (_("\nString dump of section '%s':\n"),
-	    printable_section_name (filedata, section));
-
+  uint64_t         section_size = section->sh_size;
+  unsigned char *  start = * start_ptr;
+  
   if (decompress_dumps)
     {
-      uint64_t new_size = num_bytes;
+      uint64_t new_size = section_size;
       uint64_t uncompressed_size = 0;
       bool is_zstd = false;
 
@@ -15997,12 +15980,12 @@ dump_section_as_strings (Elf_Internal_Shdr * section, Filedata * filedata)
 	{
 	  Elf_Internal_Chdr chdr;
 	  unsigned int compression_header_size
-	    = get_compression_header (& chdr, (unsigned char *) start,
-				      num_bytes);
+	    = get_compression_header (& chdr, start, section_size);
+
 	  if (compression_header_size == 0)
 	    /* An error message will have already been generated
 	       by get_compression_header.  */
-	    goto error_out;
+	    return (uint64_t) -1;
 
 	  if (chdr.ch_type == ch_compress_zlib)
 	    ;
@@ -16014,8 +15997,9 @@ dump_section_as_strings (Elf_Internal_Shdr * section, Filedata * filedata)
 	    {
 	      warn (_("section '%s' has unsupported compress type: %d\n"),
 		    printable_section_name (filedata, section), chdr.ch_type);
-	      goto error_out;
+	      return (uint64_t) -1;
 	    }
+
 	  uncompressed_size = chdr.ch_size;
 	  start += compression_header_size;
 	  new_size -= compression_header_size;
@@ -16041,38 +16025,86 @@ dump_section_as_strings (Elf_Internal_Shdr * section, Filedata * filedata)
 	{
 	  if (uncompress_section_contents (is_zstd, &start, uncompressed_size,
 					   &new_size, filedata->file_size))
-	    num_bytes = new_size;
+	    section_size = new_size;
 	  else
 	    {
 	      error (_("Unable to decompress section %s\n"),
 		     printable_section_name (filedata, section));
-	      goto error_out;
+	      return (uint64_t) -1;
 	    }
 	}
       else
-	start = real_start;
+	start = * start_ptr;
+    }
+  else if (((section->sh_flags & SHF_COMPRESSED) != 0)
+	   || (section_size > 12 && streq ((char *) start, "ZLIB")))
+    {
+      printf (_(" NOTE: This section is compressed, but its contents have NOT been expanded for this dump.\n"));
     }
 
-  /* 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.
-     FIXME: Maybe we ought to have an option that dumps a section with
-     relocs applied ?  */
-  for (relsec = filedata->section_headers;
-       relsec < filedata->section_headers + filedata->file_header.e_shnum;
-       ++relsec)
+  if (relocate)
     {
-      if ((relsec->sh_type != SHT_RELA && relsec->sh_type != SHT_REL)
-	  || relsec->sh_info >= filedata->file_header.e_shnum
-	  || filedata->section_headers + relsec->sh_info != section
-	  || relsec->sh_size == 0
-	  || relsec->sh_link >= filedata->file_header.e_shnum)
-	continue;
+      if (! apply_relocations (filedata, section, start, section_size, NULL, NULL))
+	return (uint64_t) -1;
+    }
+  else
+    {
+      Elf_Internal_Shdr *relsec;
 
-      printf (_("  Note: This section has relocations against it, but these have NOT been applied to this dump.\n"));
-      break;
+      /* 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.
+	 FIXME: Maybe we ought to have an option that dumps a section with
+	 relocs applied ?  */
+      for (relsec = filedata->section_headers;
+	   relsec < filedata->section_headers + filedata->file_header.e_shnum;
+	   ++relsec)
+	{
+	  if ((relsec->sh_type != SHT_RELA && relsec->sh_type != SHT_REL)
+	      || relsec->sh_info >= filedata->file_header.e_shnum
+	      || filedata->section_headers + relsec->sh_info != section
+	      || relsec->sh_size == 0
+	      || relsec->sh_link >= filedata->file_header.e_shnum)
+	    continue;
+
+	  printf (_(" NOTE: This section has relocations against it, but these have NOT been applied to this dump.\n"));
+	  break;
+	}
     }
 
+  * start_ptr = start;
+  return section_size;
+}
+
+static bool
+dump_section_as_strings (Elf_Internal_Shdr * section, Filedata * filedata)
+{
+  uint64_t num_bytes;
+  unsigned char *data;
+  unsigned char *end;
+  unsigned char *real_start;
+  unsigned char *start;
+  bool some_strings_shown;
+
+  real_start = start = (unsigned char *) get_section_contents (section, filedata);
+  if (start == NULL)
+    /* PR 21820: Do not fail if the section was empty.  */
+    return section->sh_size == 0 || section->sh_type == SHT_NOBITS;
+
+  num_bytes = section->sh_size;
+
+  if (filedata->is_separate)
+    printf (_("\nString dump of section '%s' in linked file %s:\n"),
+	    printable_section_name (filedata, section),
+	    filedata->file_name);
+  else
+    printf (_("\nString dump of section '%s':\n"),
+	    printable_section_name (filedata, section));
+
+  num_bytes = maybe_expand_or_relocate_section (section, filedata, & start, false);
+  if (num_bytes == (uint64_t) -1)
+    goto error_out;
+
   data = start;
   end  = start + num_bytes;
   some_strings_shown = false;
@@ -16187,7 +16219,6 @@ dump_section_as_bytes (Elf_Internal_Shdr *section,
 		       Filedata *filedata,
 		       bool relocate)
 {
-  Elf_Internal_Shdr *relsec;
   size_t bytes;
   uint64_t section_size;
   uint64_t addr;
@@ -16210,102 +16241,9 @@ dump_section_as_bytes (Elf_Internal_Shdr *section,
     printf (_("\nHex dump of section '%s':\n"),
 	    printable_section_name (filedata, section));
 
-  if (decompress_dumps)
-    {
-      uint64_t new_size = section_size;
-      uint64_t uncompressed_size = 0;
-      bool is_zstd = false;
-
-      if ((section->sh_flags & SHF_COMPRESSED) != 0)
-	{
-	  Elf_Internal_Chdr chdr;
-	  unsigned int compression_header_size
-	    = get_compression_header (& chdr, start, section_size);
-
-	  if (compression_header_size == 0)
-	    /* An error message will have already been generated
-	       by get_compression_header.  */
-	    goto error_out;
-
-	  if (chdr.ch_type == ch_compress_zlib)
-	    ;
-#ifdef HAVE_ZSTD
-	  else if (chdr.ch_type == ch_compress_zstd)
-	    is_zstd = true;
-#endif
-	  else
-	    {
-	      warn (_("section '%s' has unsupported compress type: %d\n"),
-		    printable_section_name (filedata, section), chdr.ch_type);
-	      goto error_out;
-	    }
-	  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)
-	{
-	  if (uncompress_section_contents (is_zstd, &start, uncompressed_size,
-					   &new_size, filedata->file_size))
-	    {
-	      section_size = new_size;
-	    }
-	  else
-	    {
-	      error (_("Unable to decompress section %s\n"),
-		     printable_section_name (filedata, section));
-	      /* FIXME: Print the section anyway ?  */
-	      goto error_out;
-	    }
-	}
-      else
-	start = real_start;
-    }
-
-  if (relocate)
-    {
-      if (! apply_relocations (filedata, section, start, section_size, NULL, NULL))
-	goto error_out;
-    }
-  else
-    {
-      /* 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.
-	 FIXME: Maybe we ought to have an option that dumps a section with
-	 relocs applied ?  */
-      for (relsec = filedata->section_headers;
-	   relsec < filedata->section_headers + filedata->file_header.e_shnum;
-	   ++relsec)
-	{
-	  if ((relsec->sh_type != SHT_RELA && relsec->sh_type != SHT_REL)
-	      || relsec->sh_info >= filedata->file_header.e_shnum
-	      || filedata->section_headers + relsec->sh_info != section
-	      || relsec->sh_size == 0
-	      || relsec->sh_link >= filedata->file_header.e_shnum)
-	    continue;
-
-	  printf (_(" NOTE: This section has relocations against it, but these have NOT been applied to this dump.\n"));
-	  break;
-	}
-    }
+  section_size = maybe_expand_or_relocate_section (section, filedata, & start, relocate);
+  if (section_size == (uint64_t) -1)
+    goto error_out;
 
   addr = section->sh_addr;
   bytes = section_size;
diff --git a/binutils/testsuite/binutils-all/objdump.Zs b/binutils/testsuite/binutils-all/objdump.Zs
new file mode 100644
index 00000000000..32905b53a2c
--- /dev/null
+++ b/binutils/testsuite/binutils-all/objdump.Zs
@@ -0,0 +1,9 @@
+
+.*dw2-compressed.o:     file format .*
+
+Contents of section .zdebug_abbrev:
+ 0000 01110110 06120111 01030825 08130b00  ...........%....
+ 0010 00022e00 3f0c3a0b 3b0b0308 49131101  ....\?.:.;...I...
+ 0020 1201400a 00000324 0003080b 0b3e0b00  ..@....\$.....>..
+ 0030 000000                               ...             
+#pass
diff --git a/binutils/testsuite/binutils-all/objdump.exp b/binutils/testsuite/binutils-all/objdump.exp
index 4fe9e499d49..7071e965ca3 100644
--- a/binutils/testsuite/binutils-all/objdump.exp
+++ b/binutils/testsuite/binutils-all/objdump.exp
@@ -466,6 +466,22 @@ if { ![is_elf_format] } then {
     } else {
 	pass "objdump -W"
     }
+
+    # Test objdump -Z -s on a file that contains some compressed .debug sections
+
+    set got [remote_exec host "$OBJDUMP $OBJDUMPFLAGS -Z -s -j .zdebug_abbrev $compressed_testfile" "" "/dev/null" "objdump.out"]
+
+    if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+	fail "objdump -Z -s (reason: unexpected output)"
+	send_log $got
+	send_log "\n"
+    }
+
+    if { [regexp_diff objdump.out $srcdir/$subdir/objdump.Zs] } then {
+	fail "objdump -Z -s"
+    } else {
+	pass "objdump -Z -s"
+    }
 }
 
 # Test objdump -WL on a file that contains line information for multiple files and search directories.
diff --git a/binutils/testsuite/binutils-all/objdump.s b/binutils/testsuite/binutils-all/objdump.s
index aea35dfa5a6..f80f8c54a61 100644
--- a/binutils/testsuite/binutils-all/objdump.s
+++ b/binutils/testsuite/binutils-all/objdump.s
@@ -2,6 +2,7 @@
 .*dw2-compressed.o:     file format .*
 
 Contents of section .zdebug_abbrev:
+ NOTE: This section is compressed, but its contents have NOT been expanded for this dump.
  0000 5a4c4942 00000000 00000033 785e6314  ZLIB.......3x\^c.
  0010 64146013 62146464 e650e510 e6666060  d.`.b.dd.P...f``
  0020 d263b0e7 b1e2b6e6 66e6f014 16641462  .c......f....d.b

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-11-14 10:59 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-11-14 10:59 [binutils-gdb] Improve objdump's handling of compressed sections Nick Clifton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).