aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2023-11-14 10:57:58 +0000
committerNick Clifton <nickc@redhat.com>2023-11-14 10:57:58 +0000
commitfab62191f84583780c2c6d024d0e583400881770 (patch)
tree8d3f4bec0f333cfab0808a08f8e435cdc2bc9171
parent319b460545dc79280e2904dcc280057cf71fb753 (diff)
downloadgdb-fab62191f84583780c2c6d024d0e583400881770.zip
gdb-fab62191f84583780c2c6d024d0e583400881770.tar.gz
gdb-fab62191f84583780c2c6d024d0e583400881770.tar.bz2
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.
-rw-r--r--binutils/ChangeLog24
-rw-r--r--binutils/NEWS8
-rw-r--r--binutils/doc/binutils.texi15
-rw-r--r--binutils/objdump.c17
-rw-r--r--binutils/readelf.c230
-rw-r--r--binutils/testsuite/binutils-all/objdump.Zs9
-rw-r--r--binutils/testsuite/binutils-all/objdump.exp16
-rw-r--r--binutils/testsuite/binutils-all/objdump.s1
8 files changed, 171 insertions, 149 deletions
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 57a8fa7..d695d3b 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 1aae340..3bf3b56 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 f946936..ec23a78 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 6081342..640ccb5 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 661ef0a..775106f 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 0000000..32905b5
--- /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 4fe9e499..7071e96 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 aea35df..f80f8c5 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