From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2124) id 3514D3858D20; Thu, 11 Apr 2024 14:57:43 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3514D3858D20 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1712847463; bh=DhHZI5o5Yyg39WCWZnSYEFDGcSL14R3x/HMKQQ8aUyo=; h=From:To:Subject:Date:From; b=T3ZtpqdoFpTijznsbdtirJYv3GT5p7I4hyqZ5kotwp3Pmf3hk4fJqVHwnq20opGtT igAJSWGlc+ODkgc5m+Gj7R8mb3G5gogwfOIO9oRJT0Hgpm2/Bp9vhpLKVq7ebGUp/M sNM8vjurGvWo2yh6e0jZjXwXemSP2n2AqXcl8A/4= Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Nick Clifton To: binutils-cvs@sourceware.org Subject: [binutils-gdb] Add -j/--display-section option to readelf. X-Act-Checkin: binutils-gdb X-Git-Author: Nick Clifton X-Git-Refname: refs/heads/master X-Git-Oldrev: 31c21e2c13d85793b525f74aa911eb28700ed89c X-Git-Newrev: 8e8d0b63ff15896cc2c228c01f18dfcf2a4a9305 Message-Id: <20240411145743.3514D3858D20@sourceware.org> Date: Thu, 11 Apr 2024 14:57:43 +0000 (GMT) List-Id: https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3D8e8d0b63ff15= 896cc2c228c01f18dfcf2a4a9305 commit 8e8d0b63ff15896cc2c228c01f18dfcf2a4a9305 Author: Nick Clifton Date: Thu Apr 11 15:57:26 2024 +0100 Add -j/--display-section option to readelf. Diff: --- binutils/NEWS | 4 + binutils/doc/binutils.texi | 22 ++ binutils/elfcomm.c | 14 ++ binutils/elfcomm.h | 1 + binutils/readelf.c | 371 ++++++++++++++++++------= ---- binutils/testsuite/binutils-all/readelf.exp | 8 + 6 files changed, 287 insertions(+), 133 deletions(-) diff --git a/binutils/NEWS b/binutils/NEWS index 9c7c8f1f603..be744e3b2c4 100644 --- a/binutils/NEWS +++ b/binutils/NEWS @@ -1,5 +1,9 @@ -*- text -*- =20 +* Readelf now has a -j/--display-section option which takes the name or in= dex + of a section and displays its contents according to its type. The optio= n 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 disassemb= ly. =20 * 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 79461559a56..4e67b6e0da9 100644 --- a/binutils/doc/binutils.texi +++ b/binutils/doc/binutils.texi @@ -5012,6 +5012,7 @@ readelf [@option{-a}|@option{--all}] [@option{-x} |@option{--hex-dump=3D}] [@option{-p} |@option{--string-dump=3D}] [@option{-R} |@option{--relocated-dump=3D}] + [@option{-j} |@option{--display-section=3D}] [@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. =20 @item -R @itemx --relocated-dump=3D @@ -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. =20 @item -p @itemx --string-dump=3D 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 +@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. =20 @item -z @itemx --decompress diff --git a/binutils/elfcomm.c b/binutils/elfcomm.c index ad7c5744f20..b8289b77161 100644 --- a/binutils/elfcomm.c +++ b/binutils/elfcomm.c @@ -63,6 +63,20 @@ warn (const char *message, ...) va_end (args); } =20 +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); =20 void diff --git a/binutils/elfcomm.h b/binutils/elfcomm.h index 4cda2a7b6a8..9728d6166d9 100644 --- a/binutils/elfcomm.h +++ b/binutils/elfcomm.h @@ -28,6 +28,7 @@ =20 extern void error (const char *, ...) ATTRIBUTE_PRINTF_1; extern void warn (const char *, ...) ATTRIBUTE_PRINTF_1; +extern void inform (const char *, ...) ATTRIBUTE_PRINTF_1; =20 extern void (*byte_put) (unsigned char *, uint64_t, unsigned int); extern void byte_put_little_endian (unsigned char *, uint64_t, unsigned in= t); diff --git a/binutils/readelf.c b/binutils/readelf.c index c1006480b7b..fa0de3a7e0d 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -188,12 +188,15 @@ typedef struct elf_section_list =20 /* 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. */ =20 typedef unsigned char dump_type; =20 @@ -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 *); =20 +static bool process_notes_at + (Filedata *, Elf_Internal_Shdr *, uint64_t, uint64_t, uint64_t); + #define UNKNOWN -1 =20 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, unsigne= d 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"; =20 default: if ((sh_type >=3D SHT_LOPROC) && (sh_type <=3D SHT_HIPROC)) @@ -5595,6 +5607,7 @@ static struct option options[] =3D {"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 \n")); fprintf (stream, _("\ -z --decompress Decompress section before dumping it\n")); + fprintf (stream, _("\n\ + -j --display-section=3D\n\ + Display the contents of the indicated section. Can be repeated= \n")); fprintf (stream, _("\ -w --debug-dump[a/=3Dabbrev, A/=3Daddr, r/=3Daranges, c/=3Dcu_index, L/= =3Ddecodedline,\n\ f/=3Dframes, F/=3Dframes-interp, g/=3Dgdb_index, i/=3Din= fo, o/=3Dloc,\n\ @@ -5893,7 +5909,7 @@ parse_args (struct dump_data *dumpdata, int argc, cha= r ** argv) usage (stderr); =20 while ((c =3D getopt_long - (argc, argv, "ACDHILNPR:STU:VWXacdeghi:lnp:rstuvw::x:z", options, NULL)= ) !=3D EOF) + (argc, argv, "ACDHILNPR:STU:VWXacdeghi:j:lnp:rstuvw::x:z", options, NUL= L)) !=3D EOF) { switch (c) { @@ -5976,6 +5992,9 @@ parse_args (struct dump_data *dumpdata, int argc, cha= r ** argv) do_follow_links =3D true; dump_any_debugging =3D 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 } }; =20 +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 !=3D SHT_RELA + && section->sh_type !=3D SHT_REL + && section->sh_type !=3D SHT_RELR) + return false; + + uint64_t rel_size =3D section->sh_size; + + if (rel_size =3D=3D 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 =3D=3D NULL) + printf ("%d", section->sh_name); + else + printf ("'%s'", printable_section_name (filedata, section)); + + uint64_t num_rela =3D rel_size / section->sh_entsize; + uint64_t rel_offset =3D 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 =3D rel_type_from_sh_type (section->sh_type); + + if (section->sh_link =3D=3D 0 + || section->sh_link >=3D 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 */); + =20 + Elf_Internal_Shdr * symsec =3D filedata->section_headers + section->sh_l= ink; + + if (symsec->sh_type !=3D SHT_SYMTAB + && symsec->sh_type !=3D SHT_DYNSYM) + return false; + + Elf_Internal_Sym * symtab; + uint64_t nsyms; + uint64_t strtablen =3D 0; + char * strtab =3D NULL; + + if (!get_symtab (filedata, symsec, &symtab, &nsyms, &strtab, &strtablen)) + return false; + + bool res =3D dump_relocations (filedata, rel_offset, rel_size, + symtab, nsyms, strtab, strtablen, + rel_type, + symsec->sh_type =3D=3D SHT_DYNSYM); + free (strtab); + free (symtab); + + return res; +} + /* Process the reloc section. */ =20 static bool @@ -8968,72 +9067,8 @@ process_relocs (Filedata * filedata) i < filedata->file_header.e_shnum; i++, section++) { - if ( section->sh_type !=3D SHT_RELA - && section->sh_type !=3D SHT_REL - && section->sh_type !=3D SHT_RELR) - continue; - - rel_offset =3D section->sh_offset; - rel_size =3D 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 =3D=3D NULL) - printf ("%d", section->sh_name); - else - printf ("'%s'", printable_section_name (filedata, section)); - - num_rela =3D 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 =3D section->sh_type =3D=3D SHT_RELA ? reltype_rela : - section->sh_type =3D=3D SHT_REL ? reltype_rel : reltype_relr; - - if (section->sh_link !=3D 0 - && section->sh_link < filedata->file_header.e_shnum) - { - Elf_Internal_Shdr *symsec; - Elf_Internal_Sym *symtab; - uint64_t nsyms; - uint64_t strtablen =3D 0; - char *strtab =3D NULL; - - symsec =3D filedata->section_headers + section->sh_link; - if (symsec->sh_type !=3D SHT_SYMTAB - && symsec->sh_type !=3D 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 =3D=3D SHT_DYNSYM); - free (strtab); - free (symtab); - } - else - dump_relocations (filedata, rel_offset, rel_size, - NULL, 0, NULL, 0, rel_type, false /* is_dynamic */); - - found =3D true; - } + if (display_relocations (section, filedata)) + found =3D true; } =20 if (! found) @@ -14098,6 +14133,77 @@ print_symbol_table_heading (void) } } =20 +static bool +dump_symbol_section (Elf_Internal_Shdr * section, + Filedata * filedata) +{ + if (section->sh_entsize =3D=3D 0) + { + printf (_("\nSymbol table '%s' has a sh_entsize of zero!\n"), + printable_section_name (filedata, section)); + return false; + } + + uint64_t num_syms =3D 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 =3D get_elf_symbols (filedata, section, & num_= syms); + if (symtab =3D=3D NULL) + /* An error message will have already been displayed. */ + return false; + + char * strtab =3D NULL; + uint64_t strtab_size =3D 0; + + if (section->sh_link =3D=3D filedata->file_header.e_shstrndx) + { + strtab =3D filedata->string_table; + strtab_size =3D filedata->string_table_length; + } + else if (section->sh_link < filedata->file_header.e_shnum) + { + Elf_Internal_Shdr * string_sec; + + string_sec =3D filedata->section_headers + section->sh_link; + + strtab =3D (char *) get_data (NULL, filedata, string_sec->sh_offset, + 1, string_sec->sh_size, + _("string table")); + strtab_size =3D strtab !=3D NULL ? string_sec->sh_size : 0; + } + + uint64_t si; + + for (si =3D 0; si < num_syms; si++) + print_symbol (filedata, si, symtab, section, strtab, strtab_size); + + free (symtab); + + if (strtab !=3D filedata->string_table) + free (strtab); + + return true; +} + /* Dump the symbol table. */ =20 static bool @@ -14152,74 +14258,13 @@ process_symbol_table (Filedata * filedata) i < filedata->file_header.e_shnum; i++, section++) { - char * strtab =3D NULL; - uint64_t strtab_size =3D 0; - Elf_Internal_Sym * symtab; - uint64_t si, num_syms; - if ((section->sh_type !=3D SHT_SYMTAB && section->sh_type !=3D SHT_DYNSYM) || (!do_syms && section->sh_type =3D=3D SHT_SYMTAB)) continue; =20 - if (section->sh_entsize =3D=3D 0) - { - printf (_("\nSymbol table '%s' has a sh_entsize of zero!\n"), - printable_section_name (filedata, section)); - continue; - } - - num_syms =3D 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 =3D get_elf_symbols (filedata, section, & num_syms); - if (symtab =3D=3D NULL) - continue; - - if (section->sh_link =3D=3D filedata->file_header.e_shstrndx) - { - strtab =3D filedata->string_table; - strtab_size =3D filedata->string_table_length; - } - else if (section->sh_link < filedata->file_header.e_shnum) - { - Elf_Internal_Shdr * string_sec; - - string_sec =3D filedata->section_headers + section->sh_link; - - strtab =3D (char *) get_data (NULL, filedata, string_sec->sh_offset, - 1, string_sec->sh_size, - _("string table")); - strtab_size =3D strtab !=3D NULL ? string_sec->sh_size : 0; - } - - for (si =3D 0; si < num_syms; si++) - print_symbol (filedata, si, symtab, section, - strtab, strtab_size); - - free (symtab); - if (strtab !=3D 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 &=3D DEBUG_DUMP; =20 + 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 &=3D disassemble_section (section, filedata); +#else + res &=3D dump_section_as_bytes (section, filedata, false); +#endif + break; + + case SHT_DYNSYM: + case SHT_SYMTAB: + res &=3D dump_symbol_section (section, filedata); + break; + + case SHT_STRTAB: + res &=3D dump_section_as_strings (section, filedata); + break; + + case SHT_RELA: + case SHT_REL: + case SHT_RELR: + res &=3D display_relocations (section, filedata); + break; + + case SHT_NOTE: + res &=3D 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 =3D false; + break; + } + } + #ifdef SUPPORT_DISASSEMBLY if (dump & DISASS_DUMP) { @@ -17622,7 +17726,8 @@ display_arm_attribute (unsigned char * p, =20 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/testsui= te/binutils-all/readelf.exp index 399b3c7f276..b91134b4326 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=3D.rel.debug_info} $te= mpfile display-section.r +readelf_test --display-section=3D0 $tempfile display-section.0 + +