@@ -1,5 +1,9 @@
-*- text -*-
+* Readelf now has a -j/--display-section option which takes the name or index
+ of a section and displays its contents according to its type. The option can
+ be used multiple times on the command line to display multiple sections.
+
* Base register 0 is now printed as "0" instead of "%r0" in s390 disassembly.
* When objdump or readelf are used to display the contents of a .eh_frame
@@ -5012,6 +5012,7 @@ readelf [@option{-a}|@option{--all}]
[@option{-x} <number or name>|@option{--hex-dump=}<number or name>]
[@option{-p} <number or name>|@option{--string-dump=}<number or name>]
[@option{-R} <number or name>|@option{--relocated-dump=}<number or name>]
+ [@option{-j} <number or name>|@option{--display-section=}<number or name>]
[@option{-z}|@option{--decompress}]
[@option{-c}|@option{--archive-index}]
[@option{-w[lLiaprmfFsoORtUuTgAck]}|
@@ -5270,6 +5271,8 @@ displayed.
Displays the contents of the indicated section as a hexadecimal bytes.
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.
+This option can be repeated multiple times on the command line in
+order to request multiple hex dumps.
@item -R <number or name>
@itemx --relocated-dump=<number or name>
@@ -5278,12 +5281,31 @@ bytes. 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. The contents of the section will be relocated
before they are displayed.
+This option can be repeated multiple times on the command line in
+order to request multiple relocated dumps.
@item -p <number or name>
@itemx --string-dump=<number or name>
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.
+This option can be repeated multiple times on the command line in
+order to request multiple string dumps.
+
+@item -j <number or name>
+@itemx --display-section
+Displays the contents of the indicated section according to its
+section header type. Sections containing relocations will be
+displayed as if the @option{--relocations} option had been used,
+sections contains symbols will be displayed as if the @option{--syms}
+option had been used and so on.
+
+A number identifies a particular section by index in the section
+table; any other string identifies all sections with that name in the
+input file(s).
+
+This option can be repeated multiple times on the command line in
+order to request multiple section dumps.
@item -z
@itemx --decompress
@@ -63,6 +63,20 @@ warn (const char *message, ...)
va_end (args);
}
+void
+inform (const char *message, ...)
+{
+ va_list args;
+
+ /* Try to keep info messages in sync with the program's normal output. */
+ fflush (stdout);
+
+ va_start (args, message);
+ fprintf (stderr, _("%s: Info: "), program_name);
+ vfprintf (stderr, message, args);
+ va_end (args);
+}
+
void (*byte_put) (unsigned char *, uint64_t, unsigned int);
void
@@ -28,6 +28,7 @@
extern void error (const char *, ...) ATTRIBUTE_PRINTF_1;
extern void warn (const char *, ...) ATTRIBUTE_PRINTF_1;
+extern void inform (const char *, ...) ATTRIBUTE_PRINTF_1;
extern void (*byte_put) (unsigned char *, uint64_t, unsigned int);
extern void byte_put_little_endian (unsigned char *, uint64_t, unsigned int);
@@ -188,12 +188,15 @@ typedef struct elf_section_list
/* Flag bits indicating particular types of dump. */
#define HEX_DUMP (1 << 0) /* The -x command line switch. */
+#ifdef SUPPORT_DISASSEMBLY
#define DISASS_DUMP (1 << 1) /* The -i command line switch. */
+#endif
#define DEBUG_DUMP (1 << 2) /* The -w command line switch. */
#define STRING_DUMP (1 << 3) /* The -p command line switch. */
#define RELOC_DUMP (1 << 4) /* The -R command line switch. */
#define CTF_DUMP (1 << 5) /* The --ctf command line switch. */
#define SFRAME_DUMP (1 << 6) /* The --sframe command line switch. */
+#define AUTO_DUMP (1 << 7) /* The -j command line switch. */
typedef unsigned char dump_type;
@@ -402,6 +405,9 @@ static const char * get_symbol_version_string
(Filedata *, bool, const char *, size_t, unsigned,
Elf_Internal_Sym *, enum versioned_symbol_info *, unsigned short *);
+static bool process_notes_at
+ (Filedata *, Elf_Internal_Shdr *, uint64_t, uint64_t, uint64_t);
+
#define UNKNOWN -1
static inline const char *
@@ -5414,7 +5420,6 @@ get_section_type_name (Filedata * filedata, unsigned int sh_type)
case SHT_SYMTAB: return "SYMTAB";
case SHT_STRTAB: return "STRTAB";
case SHT_RELA: return "RELA";
- case SHT_RELR: return "RELR";
case SHT_HASH: return "HASH";
case SHT_DYNAMIC: return "DYNAMIC";
case SHT_NOTE: return "NOTE";
@@ -5422,20 +5427,27 @@ get_section_type_name (Filedata * filedata, unsigned int sh_type)
case SHT_REL: return "REL";
case SHT_SHLIB: return "SHLIB";
case SHT_DYNSYM: return "DYNSYM";
+ /* 12 and 13 are not defined. */
case SHT_INIT_ARRAY: return "INIT_ARRAY";
case SHT_FINI_ARRAY: return "FINI_ARRAY";
case SHT_PREINIT_ARRAY: return "PREINIT_ARRAY";
- case SHT_GNU_HASH: return "GNU_HASH";
case SHT_GROUP: return "GROUP";
case SHT_SYMTAB_SHNDX: return "SYMTAB SECTION INDICES";
+ case SHT_RELR: return "RELR";
+ /* End of generic section types. */
+
+ /* OS specific section types: */
case SHT_GNU_verdef: return "VERDEF";
case SHT_GNU_verneed: return "VERNEED";
case SHT_GNU_versym: return "VERSYM";
+ case SHT_GNU_INCREMENTAL_INPUTS: return "GNU_INCREMENTAL_INPUTS";
case 0x6ffffff0: return "VERSYM";
+ case SHT_GNU_ATTRIBUTES: return "GNU_ATTRIBUTES";
+ case SHT_GNU_HASH: return "GNU_HASH";
+ case SHT_GNU_LIBLIST: return "GNU_LIBLIST";
case 0x6ffffffc: return "VERDEF";
case 0x7ffffffd: return "AUXILIARY";
case 0x7fffffff: return "FILTER";
- case SHT_GNU_LIBLIST: return "GNU_LIBLIST";
default:
if ((sh_type >= SHT_LOPROC) && (sh_type <= SHT_HIPROC))
@@ -5595,6 +5607,7 @@ static struct option options[] =
{"help", no_argument, 0, 'H'},
{"file-header", no_argument, 0, 'h'},
{"histogram", no_argument, 0, 'I'},
+ {"display-section", required_argument, 0, 'j'},
{"lint", no_argument, 0, 'L'},
{"enable-checks", no_argument, 0, 'L'},
{"program-headers", no_argument, 0, 'l'},
@@ -5729,6 +5742,9 @@ usage (FILE * stream)
Dump the relocated contents of section <number|name>\n"));
fprintf (stream, _("\
-z --decompress Decompress section before dumping it\n"));
+ fprintf (stream, _("\n\
+ -j --display-section=<name|number>\n\
+ Display the contents of the indicated section. Can be repeated\n"));
fprintf (stream, _("\
-w --debug-dump[a/=abbrev, A/=addr, r/=aranges, c/=cu_index, L/=decodedline,\n\
f/=frames, F/=frames-interp, g/=gdb_index, i/=info, o/=loc,\n\
@@ -5893,7 +5909,7 @@ parse_args (struct dump_data *dumpdata, int argc, char ** argv)
usage (stderr);
while ((c = getopt_long
- (argc, argv, "ACDHILNPR:STU:VWXacdeghi:lnp:rstuvw::x:z", options, NULL)) != EOF)
+ (argc, argv, "ACDHILNPR:STU:VWXacdeghi:j:lnp:rstuvw::x:z", options, NULL)) != EOF)
{
switch (c)
{
@@ -5976,6 +5992,9 @@ parse_args (struct dump_data *dumpdata, int argc, char ** argv)
do_follow_links = true;
dump_any_debugging = true;
break;
+ case 'j':
+ request_dump (dumpdata, AUTO_DUMP);
+ break;
case 'x':
request_dump (dumpdata, HEX_DUMP);
break;
@@ -8877,6 +8896,86 @@ static struct
{ "PLT", DT_JMPREL, DT_PLTRELSZ, reltype_unknown }
};
+static relocation_type
+rel_type_from_sh_type (unsigned int sh_type)
+{
+ switch (sh_type)
+ {
+ case SHT_RELA: return reltype_rela;
+ case SHT_REL: return reltype_rel;
+ case SHT_RELR: return reltype_relr;
+ default: return reltype_unknown;
+ }
+}
+
+static bool
+display_relocations (Elf_Internal_Shdr * section,
+ Filedata * filedata)
+{
+ if (section->sh_type != SHT_RELA
+ && section->sh_type != SHT_REL
+ && section->sh_type != SHT_RELR)
+ return false;
+
+ uint64_t rel_size = section->sh_size;
+
+ if (rel_size == 0)
+ return false;
+
+ if (filedata->is_separate)
+ printf (_("\nIn linked file '%s' relocation section "),
+ filedata->file_name);
+ else
+ printf (_("\nRelocation section "));
+
+ if (filedata->string_table == NULL)
+ printf ("%d", section->sh_name);
+ else
+ printf ("'%s'", printable_section_name (filedata, section));
+
+ uint64_t num_rela = rel_size / section->sh_entsize;
+ uint64_t rel_offset = section->sh_offset;
+
+ printf (ngettext (" at offset %#" PRIx64
+ " contains %" PRIu64 " entry:\n",
+ " at offset %#" PRIx64
+ " contains %" PRId64 " entries:\n",
+ num_rela),
+ rel_offset, num_rela);
+
+ relocation_type rel_type = rel_type_from_sh_type (section->sh_type);
+
+ if (section->sh_link == 0
+ || section->sh_link >= filedata->file_header.e_shnum)
+ /* Symbol data not available. */
+ return dump_relocations (filedata, rel_offset, rel_size,
+ NULL, 0, NULL, 0, rel_type,
+ false /* is_dynamic */);
+
+ Elf_Internal_Shdr * symsec = filedata->section_headers + section->sh_link;
+
+ if (symsec->sh_type != SHT_SYMTAB
+ && symsec->sh_type != SHT_DYNSYM)
+ return false;
+
+ Elf_Internal_Sym * symtab;
+ uint64_t nsyms;
+ uint64_t strtablen = 0;
+ char * strtab = NULL;
+
+ if (!get_symtab (filedata, symsec, &symtab, &nsyms, &strtab, &strtablen))
+ return false;
+
+ bool res = dump_relocations (filedata, rel_offset, rel_size,
+ symtab, nsyms, strtab, strtablen,
+ rel_type,
+ symsec->sh_type == SHT_DYNSYM);
+ free (strtab);
+ free (symtab);
+
+ return res;
+}
+
/* Process the reloc section. */
static bool
@@ -8968,72 +9067,8 @@ process_relocs (Filedata * filedata)
i < filedata->file_header.e_shnum;
i++, section++)
{
- if ( section->sh_type != SHT_RELA
- && section->sh_type != SHT_REL
- && section->sh_type != SHT_RELR)
- continue;
-
- rel_offset = section->sh_offset;
- rel_size = section->sh_size;
-
- if (rel_size)
- {
- relocation_type rel_type;
- uint64_t num_rela;
-
- if (filedata->is_separate)
- printf (_("\nIn linked file '%s' relocation section "),
- filedata->file_name);
- else
- printf (_("\nRelocation section "));
-
- if (filedata->string_table == NULL)
- printf ("%d", section->sh_name);
- else
- printf ("'%s'", printable_section_name (filedata, section));
-
- num_rela = rel_size / section->sh_entsize;
- printf (ngettext (" at offset %#" PRIx64
- " contains %" PRIu64 " entry:\n",
- " at offset %#" PRIx64
- " contains %" PRId64 " entries:\n",
- num_rela),
- rel_offset, num_rela);
-
- rel_type = section->sh_type == SHT_RELA ? reltype_rela :
- section->sh_type == SHT_REL ? reltype_rel : reltype_relr;
-
- if (section->sh_link != 0
- && section->sh_link < filedata->file_header.e_shnum)
- {
- Elf_Internal_Shdr *symsec;
- Elf_Internal_Sym *symtab;
- uint64_t nsyms;
- uint64_t strtablen = 0;
- char *strtab = NULL;
-
- symsec = filedata->section_headers + section->sh_link;
- if (symsec->sh_type != SHT_SYMTAB
- && symsec->sh_type != SHT_DYNSYM)
- continue;
-
- if (!get_symtab (filedata, symsec,
- &symtab, &nsyms, &strtab, &strtablen))
- continue;
-
- dump_relocations (filedata, rel_offset, rel_size,
- symtab, nsyms, strtab, strtablen,
- rel_type,
- symsec->sh_type == SHT_DYNSYM);
- free (strtab);
- free (symtab);
- }
- else
- dump_relocations (filedata, rel_offset, rel_size,
- NULL, 0, NULL, 0, rel_type, false /* is_dynamic */);
-
- found = true;
- }
+ if (display_relocations (section, filedata))
+ found = true;
}
if (! found)
@@ -14098,6 +14133,77 @@ print_symbol_table_heading (void)
}
}
+static bool
+dump_symbol_section (Elf_Internal_Shdr * section,
+ Filedata * filedata)
+{
+ if (section->sh_entsize == 0)
+ {
+ printf (_("\nSymbol table '%s' has a sh_entsize of zero!\n"),
+ printable_section_name (filedata, section));
+ return false;
+ }
+
+ uint64_t num_syms = section->sh_size / section->sh_entsize;
+
+ if (filedata->is_separate)
+ printf (ngettext ("\nIn linked file '%s' symbol section '%s'"
+ " contains %" PRIu64 " entry:\n",
+ "\nIn linked file '%s' symbol section '%s'"
+ " contains %" PRIu64 " entries:\n",
+ num_syms),
+ filedata->file_name,
+ printable_section_name (filedata, section),
+ num_syms);
+ else
+ printf (ngettext ("\nSymbol table '%s' contains %" PRIu64
+ " entry:\n",
+ "\nSymbol table '%s' contains %" PRIu64
+ " entries:\n",
+ num_syms),
+ printable_section_name (filedata, section),
+ num_syms);
+
+ print_symbol_table_heading ();
+
+ Elf_Internal_Sym * symtab = get_elf_symbols (filedata, section, & num_syms);
+ if (symtab == NULL)
+ /* An error message will have already been displayed. */
+ return false;
+
+ char * strtab = NULL;
+ uint64_t strtab_size = 0;
+
+ if (section->sh_link == filedata->file_header.e_shstrndx)
+ {
+ strtab = filedata->string_table;
+ strtab_size = filedata->string_table_length;
+ }
+ else if (section->sh_link < filedata->file_header.e_shnum)
+ {
+ Elf_Internal_Shdr * string_sec;
+
+ string_sec = filedata->section_headers + section->sh_link;
+
+ strtab = (char *) get_data (NULL, filedata, string_sec->sh_offset,
+ 1, string_sec->sh_size,
+ _("string table"));
+ strtab_size = strtab != NULL ? string_sec->sh_size : 0;
+ }
+
+ uint64_t si;
+
+ for (si = 0; si < num_syms; si++)
+ print_symbol (filedata, si, symtab, section, strtab, strtab_size);
+
+ free (symtab);
+
+ if (strtab != filedata->string_table)
+ free (strtab);
+
+ return true;
+}
+
/* Dump the symbol table. */
static bool
@@ -14152,74 +14258,13 @@ process_symbol_table (Filedata * filedata)
i < filedata->file_header.e_shnum;
i++, section++)
{
- char * strtab = NULL;
- uint64_t strtab_size = 0;
- Elf_Internal_Sym * symtab;
- uint64_t si, num_syms;
-
if ((section->sh_type != SHT_SYMTAB
&& section->sh_type != SHT_DYNSYM)
|| (!do_syms
&& section->sh_type == SHT_SYMTAB))
continue;
- if (section->sh_entsize == 0)
- {
- printf (_("\nSymbol table '%s' has a sh_entsize of zero!\n"),
- printable_section_name (filedata, section));
- continue;
- }
-
- num_syms = section->sh_size / section->sh_entsize;
-
- if (filedata->is_separate)
- printf (ngettext ("\nIn linked file '%s' symbol section '%s'"
- " contains %" PRIu64 " entry:\n",
- "\nIn linked file '%s' symbol section '%s'"
- " contains %" PRIu64 " entries:\n",
- num_syms),
- filedata->file_name,
- printable_section_name (filedata, section),
- num_syms);
- else
- printf (ngettext ("\nSymbol table '%s' contains %" PRIu64
- " entry:\n",
- "\nSymbol table '%s' contains %" PRIu64
- " entries:\n",
- num_syms),
- printable_section_name (filedata, section),
- num_syms);
-
- print_symbol_table_heading ();
-
- symtab = get_elf_symbols (filedata, section, & num_syms);
- if (symtab == NULL)
- continue;
-
- if (section->sh_link == filedata->file_header.e_shstrndx)
- {
- strtab = filedata->string_table;
- strtab_size = filedata->string_table_length;
- }
- else if (section->sh_link < filedata->file_header.e_shnum)
- {
- Elf_Internal_Shdr * string_sec;
-
- string_sec = filedata->section_headers + section->sh_link;
-
- strtab = (char *) get_data (NULL, filedata, string_sec->sh_offset,
- 1, string_sec->sh_size,
- _("string table"));
- strtab_size = strtab != NULL ? string_sec->sh_size : 0;
- }
-
- for (si = 0; si < num_syms; si++)
- print_symbol (filedata, si, symtab, section,
- strtab, strtab_size);
-
- free (symtab);
- if (strtab != filedata->string_table)
- free (strtab);
+ dump_symbol_section (section, filedata);
}
}
else if (do_syms)
@@ -17016,6 +17061,65 @@ process_section_contents (Filedata * filedata)
if (filedata->is_separate && ! process_links)
dump &= DEBUG_DUMP;
+ if (dump & AUTO_DUMP)
+ {
+ switch (section->sh_type)
+ {
+ case SHT_PROGBITS:
+ /* FIXME: There are lots of different type of section that have
+ SHT_PROGBITS set in their header - code, debug info, etc. So
+ we should check the section's name and interpret its contents
+ that way, rather than just defaulting to a byte dump. */
+#ifdef SUPPORT_DISASSEMBLY
+ res &= disassemble_section (section, filedata);
+#else
+ res &= dump_section_as_bytes (section, filedata, false);
+#endif
+ break;
+
+ case SHT_DYNSYM:
+ case SHT_SYMTAB:
+ res &= dump_symbol_section (section, filedata);
+ break;
+
+ case SHT_STRTAB:
+ res &= dump_section_as_strings (section, filedata);
+ break;
+
+ case SHT_RELA:
+ case SHT_REL:
+ case SHT_RELR:
+ res &= display_relocations (section, filedata);
+ break;
+
+ case SHT_NOTE:
+ res &= process_notes_at (filedata, section, section->sh_offset,
+ section->sh_size, section->sh_addralign);
+ break;
+
+ case SHT_NULL:
+ inform (_("Unable to display section %d - it has a NULL type\n"), i);
+ break;
+
+ case SHT_NOBITS:
+ inform (_("Unable to display section %d - it has no contents\n"), i);
+ break;
+
+ case SHT_HASH:
+ case SHT_DYNAMIC:
+ case SHT_GROUP:
+ case SHT_GNU_ATTRIBUTES:
+ /* FIXME: Implement these. */
+ /* Fall through. */
+ default:
+ /* FIXME: Add Proc and OS specific section types ? */
+ warn (_("Unable to determine how to dump section %d (type %#x)\n"),
+ i, section->sh_type);
+ res = false;
+ break;
+ }
+ }
+
#ifdef SUPPORT_DISASSEMBLY
if (dump & DISASS_DUMP)
{
@@ -17622,7 +17726,8 @@ display_arm_attribute (unsigned char * p,
static unsigned char *
display_gnu_attribute (unsigned char * p,
- unsigned char * (* display_proc_gnu_attribute) (unsigned char *, unsigned int, const unsigned char * const),
+ unsigned char * (* display_proc_gnu_attribute)
+ (unsigned char *, unsigned int, const unsigned char * const),
const unsigned char * const end)
{
unsigned int tag;
@@ -634,3 +634,11 @@ readelf_find_size $tempfile 2
# Make sure that readelf can decode the contents.
readelf_test -wi $tempfile dw5-op.W
}
+
+# Test the -j/--display-section option.
+# Check that multiple options accumulate.
+# Check that both numbers and names can be used.
+readelf_test {-j .rela.debug_info --display-section=.rel.debug_info} $tempfile display-section.r
+readelf_test --display-section=0 $tempfile display-section.0
+
+
@@ -0,0 +1,4 @@
+.*: Warning: Section '.*' was not dumped because it does not exist
+
+Relocation section '.*' at offset 0x.* contains .* entries:
+#...
@@ -0,0 +1 @@
+.*: Info: Unable to display section 0 - it has a NULL type