diff options
author | Nick Clifton <nickc@redhat.com> | 2024-04-11 15:57:26 +0100 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2024-04-11 15:57:26 +0100 |
commit | 8e8d0b63ff15896cc2c228c01f18dfcf2a4a9305 (patch) | |
tree | 1ab0338b6e5574386ef805bc7ae9a350082c3f87 /binutils | |
parent | 31c21e2c13d85793b525f74aa911eb28700ed89c (diff) | |
download | gdb-8e8d0b63ff15896cc2c228c01f18dfcf2a4a9305.zip gdb-8e8d0b63ff15896cc2c228c01f18dfcf2a4a9305.tar.gz gdb-8e8d0b63ff15896cc2c228c01f18dfcf2a4a9305.tar.bz2 |
Add -j/--display-section option to readelf.
Diffstat (limited to 'binutils')
-rw-r--r-- | binutils/NEWS | 4 | ||||
-rw-r--r-- | binutils/doc/binutils.texi | 22 | ||||
-rw-r--r-- | binutils/elfcomm.c | 14 | ||||
-rw-r--r-- | binutils/elfcomm.h | 1 | ||||
-rw-r--r-- | binutils/readelf.c | 371 | ||||
-rw-r--r-- | binutils/testsuite/binutils-all/readelf.exp | 8 |
6 files changed, 287 insertions, 133 deletions
diff --git a/binutils/NEWS b/binutils/NEWS index 9c7c8f1..be744e3 100644 --- a/binutils/NEWS +++ b/binutils/NEWS @@ -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 diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi index 7946155..4e67b6e 100644 --- a/binutils/doc/binutils.texi +++ b/binutils/doc/binutils.texi @@ -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 diff --git a/binutils/elfcomm.c b/binutils/elfcomm.c index ad7c574..b8289b7 100644 --- a/binutils/elfcomm.c +++ b/binutils/elfcomm.c @@ -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 diff --git a/binutils/elfcomm.h b/binutils/elfcomm.h index 4cda2a7..9728d61 100644 --- a/binutils/elfcomm.h +++ b/binutils/elfcomm.h @@ -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); diff --git a/binutils/readelf.c b/binutils/readelf.c index c100648..fa0de3a 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -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; diff --git a/binutils/testsuite/binutils-all/readelf.exp b/binutils/testsuite/binutils-all/readelf.exp index 399b3c7..b91134b 100644 --- a/binutils/testsuite/binutils-all/readelf.exp +++ b/binutils/testsuite/binutils-all/readelf.exp @@ -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 + + |