readelf: Add option to display the names of sections referenced by symbols.
authorNick Clifton <nickc@redhat.com>
Tue, 5 Sep 2023 10:08:23 +0000 (11:08 +0100)
committerNick Clifton <nickc@redhat.com>
Tue, 5 Sep 2023 10:08:23 +0000 (11:08 +0100)
  PR 30684
  * readelf.c (extra_sym_info): New variable. (section_name_valid): Also check for filedata being NULL. (section_name_print): Delete. (section_index_real): New function.  Returns true if the given section index references a real section. (print_symbol): Rename to print_sumbol_name. (printable_section_name): Use a rotating array of static buffers for the return string. (printable_section_name_from_index): Merge code from dump_relocations and get_symbol_index_type into here. (long_option_values): Add OPTION_NO_EXTRA_SYM_INFO. (options): Add "extra-sym-info" and "no-extra-sym-info". (usage): Mention new options. (parse_args): Parse new options. (get_symbol_index_type): Delete. (print_dynamic_symbol_size): Rename to print_symbol_size. (print_dynamic_symbol): Rename to print_symbol. (print_symbol_table_heading): New function. (process_symbol_table): Use new function.
  * doc/binutils.texi: Document the new option.
  * NEWS: Mention the new feature.

binutils/ChangeLog
binutils/NEWS
binutils/doc/binutils.texi
binutils/readelf.c

index eab6f5d02f6fe22403b7868592752f1feb5d36d5..ac14aff1827b2399bddd8fed302ac7c10f376ddf 100644 (file)
@@ -1,3 +1,28 @@
+2023-09-05  Nick Clifton  <nickc@redhat.com>
+
+       PR 30684
+       * readelf.c (extra_sym_info): New variable.
+       (section_name_valid): Also check for filedata being NULL.
+       (section_name_print): Delete.
+       (section_index_real): New function.  Returns true if the given
+       section index references a real section.
+       (print_symbol): Rename to print_sumbol_name.
+       (printable_section_name): Use a rotating array of static buffers
+       for the return string.
+       (printable_section_name_from_index): Merge code from
+       dump_relocations and get_symbol_index_type into here.
+       (long_option_values): Add OPTION_NO_EXTRA_SYM_INFO.
+       (options): Add "extra-sym-info" and "no-extra-sym-info".
+       (usage): Mention new options.
+       (parse_args): Parse new options.
+       (get_symbol_index_type): Delete.
+       (print_dynamic_symbol_size): Rename to print_symbol_size.
+       (print_dynamic_symbol): Rename to print_symbol.
+       (print_symbol_table_heading): New function.
+       (process_symbol_table): Use new function.
+       * doc/binutils.texi: Document the new option.
+       * NEWS: Mention the new feature.
+
 2023-08-23  Nick Clifton  <nickc@redhat.com>
 
        PR 30781
index d64cae009eb46120004f85347717c008d61a6d8a..1aae340ea2a8c6670392013992fe826218fbc8ee 100644 (file)
@@ -1,5 +1,11 @@
 -*- text -*-
 
+* 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
+  index field (st_shndx).  In the future more information may also be displayed
+  when this option is enabled.
+
 * objcopy --set-section-flags now supports "large" to set SHF_X86_64_LARGE
   for ELF x86-64 objects.
 
index 9f80f398c9de95ef0f83e25241889e8878ec8ba3..56394b2d344f6ecfe9bc5b3af0b3fb627747ebe0 100644 (file)
@@ -4961,6 +4961,7 @@ readelf [@option{-a}|@option{--all}]
         [@option{--quiet}]
         [@option{--recurse-limit}|@option{--no-recurse-limit}]
         [@option{-U} @var{method}|@option{--unicode=}@var{method}]
+        [@option{-X}|@option{--extra-sym-info}|@option{--no-extra-sym-info}]
         [@option{-n}|@option{--notes}]
         [@option{-r}|@option{--relocs}]
         [@option{-u}|@option{--unwind}]
@@ -5152,6 +5153,20 @@ assuming that colouring is supported by the output device.  The
 colouring is intended to draw attention to the presence of unicode
 sequences when they might not be expected.
 
+@item -X
+@itemx --extra-sym-info
+When displaying details of symbols, include extra information not
+normally presented.  Currently this just adds the name of the section
+referenced by the symbol's index field, if there is one.  In the
+future more information may be displayed when this option is enabled.
+
+Enabling this option effectively enables the @option{--wide} option as
+well, at least when displaying symbol information.
+
+@item --no-extra-sym-info
+Disables the effect of the @option{--extra-sym-info} option.  This
+is the default.
+
 @item -e
 @itemx --headers
 Display all the headers in the file.  Equivalent to @option{-h -l -S}.
index c0015ca196f161eb61f1a4543b30cbb6fa1ff544..5c69efcbcd78e6632d03f065374af1da9c44271e 100644 (file)
@@ -248,6 +248,7 @@ static bool do_not_show_symbol_truncation = false;
 static bool do_demangle = false;       /* Pretty print C++ symbol names.  */
 static bool process_links = false;
 static bool dump_any_debugging = false;
+static bool extra_sym_info = false;
 static int demangle_flags = DMGL_ANSI | DMGL_PARAMS;
 static int sym_base = 0;
 
@@ -412,23 +413,25 @@ section_name (const Filedata *filedata, const Elf_Internal_Shdr *hdr)
 static inline bool
 section_name_valid (const Filedata *filedata, const Elf_Internal_Shdr *hdr)
 {
-  return (hdr != NULL
+  return (filedata != NULL
+         && hdr != NULL
          && filedata->string_table != NULL
          && hdr->sh_name < filedata->string_table_length);
 }
 
-static inline const char *
-section_name_print (const Filedata *filedata, const Elf_Internal_Shdr *hdr)
+/* Returns true if the given index is real/valid.  Note: "real" here
+   means "references a real section in the section header" and not
+   "is a valid section index as per the ELF standard".  */
+
+static inline bool
+section_index_real (const Filedata *filedata, unsigned int ndx)
 {
-  if (hdr == NULL)
-    return _("<none>");
-  if (filedata->string_table == NULL)
-    return _("<no-strings>");
-  if (hdr->sh_name >= filedata->string_table_length)
-    return _("<corrupt>");
-  return section_name (filedata, hdr);
+  return (filedata != NULL
+         && filedata->section_headers != NULL
+         && ndx < filedata->file_header.e_shnum
+         && ndx > 0);
 }
-
 #define DT_VERSIONTAGIDX(tag)  (DT_VERNEEDNUM - (tag)) /* Reverse order!  */
 
 static inline bool
@@ -612,7 +615,8 @@ print_vma (uint64_t vma, print_mode mode)
 /* Display a symbol on stdout.  Handles the display of control characters and
    multibye characters (assuming the host environment supports them).
 
-   Display at most abs(WIDTH) characters, truncating as necessary, unless do_wide is true.
+   Display at most abs(WIDTH) characters, truncating as necessary,
+   unless do_wide or extra_sym_info is true.
 
    If truncation will happen and do_not_show_symbol_truncation is FALSE then display
    abs(WIDTH) - 5 characters followed by "[...]".
@@ -623,7 +627,7 @@ print_vma (uint64_t vma, print_mode mode)
    Returns the number of emitted characters.  */
 
 static unsigned int
-print_symbol (signed int width, const char * symbol)
+print_symbol_name (signed int width, const char * symbol)
 {
   bool extra_padding = false;
   bool do_dots = false;
@@ -643,13 +647,14 @@ print_symbol (signed int width, const char * symbol)
   else if (width == 0)
     return 0;
 
-  if (do_wide)
+  if (do_wide || extra_sym_info)
     /* Set the remaining width to a very large value.
        This simplifies the code below.  */
     width_remaining = INT_MAX;
   else
     {
       width_remaining = width;
+
       if (! do_not_show_symbol_truncation
          && (int) strlen (symbol) > width)
        {
@@ -876,13 +881,37 @@ print_symbol (signed int width, const char * symbol)
 static const char *
 printable_section_name (Filedata * filedata, const Elf_Internal_Shdr * sec)
 {
-#define MAX_PRINT_SEC_NAME_LEN 256
-  static char  sec_name_buf [MAX_PRINT_SEC_NAME_LEN + 1];
-  const char * name = section_name_print (filedata, sec);
-  char *       buf = sec_name_buf;
+#define NUM_SEC_NAME_BUFS       5
+#define MAX_PRINT_SEC_NAME_LEN  256
+  
+  static int   sec_name_buf_index = 0;
+  /* We use a rotating array of static buffers, so that multiple successive calls
+     to printable_section_name() will still work.  eg when used in a printf.  */
+  static char  sec_name_buf [NUM_SEC_NAME_BUFS][MAX_PRINT_SEC_NAME_LEN + 1];
+  
+  const char * name;
+  char *       buf;
+  char *       buf_start;
   char         c;
   unsigned int remaining = MAX_PRINT_SEC_NAME_LEN;
 
+  /* Validate the input parameters.  */
+  if (filedata == NULL)
+    return _("<internal error>");
+  if (sec == NULL)
+    return _("<none>");
+  if (filedata->string_table == NULL)
+    return _("<no-strings>");
+  if (sec->sh_name >= filedata->string_table_length)
+    return _("<corrupt>");
+
+  /* Select a buffer to use.  */
+  buf_start = buf = sec_name_buf[sec_name_buf_index];
+  if (++sec_name_buf_index >= NUM_SEC_NAME_BUFS)
+    sec_name_buf_index = 0;
+
+  name = section_name (filedata, sec);
+
   while ((c = * name ++) != 0)
     {
       if (ISCNTRL (c))
@@ -917,16 +946,101 @@ printable_section_name (Filedata * filedata, const Elf_Internal_Shdr * sec)
     }
 
   * buf = 0;
-  return sec_name_buf;
+  return buf_start;
+}
+
+/* Return TRUE if the current file is for IA-64 machine and OpenVMS ABI.
+   This OS has so many departures from the ELF standard that we test it at
+   many places.  */
+
+static inline bool
+is_ia64_vms (Filedata * filedata)
+{
+  return filedata->file_header.e_machine == EM_IA_64
+    && filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_OPENVMS;
 }
 
 static const char *
-printable_section_name_from_index (Filedata *filedata, size_t ndx)
+printable_section_name_from_index (Filedata *  filedata,
+                                  size_t      ndx,
+                                  bool *      is_special)
 {
-  if (ndx >= filedata->file_header.e_shnum)
-    return _("<corrupt>");
+  if (is_special != NULL)
+    * is_special = true;
+
+  switch (ndx)
+    {
+    case SHN_UNDEF:    return "UND";
+    case SHN_ABS:      return "ABS";
+    case SHN_COMMON:   return "COM";
+      break;
+    }
 
-  return printable_section_name (filedata, filedata->section_headers + ndx);
+  if (filedata != NULL)
+    {
+      switch (filedata->file_header.e_machine)
+       {
+       case EM_MIPS:
+         if (ndx == SHN_MIPS_SCOMMON)
+           return "SCOMMON";
+         if (ndx == SHN_MIPS_SUNDEFINED)
+           return "SUNDEF";
+         break;
+
+       case EM_TI_C6000:
+         if (ndx == SHN_TIC6X_SCOMMON)
+           return "SCOM";
+         break;
+
+       case EM_X86_64:
+       case EM_L1OM:
+       case EM_K1OM:
+         if (ndx == SHN_X86_64_LCOMMON)
+           return "LARGE_COM";
+         break;
+
+       case EM_IA_64:
+         if (filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_HPUX
+             && ndx == SHN_IA_64_ANSI_COMMON)
+           return "ANSI_COM";
+
+         if (is_ia64_vms (filedata) && ndx == SHN_IA_64_VMS_SYMVEC)
+           return "VMS_SYMVEC";
+         break;
+
+       default:
+         break;
+       }
+
+      if (filedata->section_headers != NULL
+         && ndx < filedata->file_header.e_shnum)
+       {
+         const char * res;
+
+         res = printable_section_name (filedata, filedata->section_headers + ndx);
+         if (is_special != NULL)
+           * is_special = (res[0] == '<');
+
+         return res;
+       }
+    }
+
+  static char name_buf[40];
+  unsigned int short_ndx = (unsigned int) (ndx & 0xffff);
+
+  if (ndx >= SHN_LOPROC && ndx <= SHN_HIPROC)
+    sprintf (name_buf, "PRC[0x%04x]", short_ndx);
+  else if (ndx >= SHN_LOOS && ndx <= SHN_HIOS)
+    sprintf (name_buf, "OS [0x%04x]", short_ndx);
+  else if (ndx >= SHN_LORESERVE)
+    sprintf (name_buf, "RSV[0x%04x]", short_ndx);
+  else if (filedata->file_header.e_shnum != 0
+          && ndx >= filedata->file_header.e_shnum)
+    sprintf (name_buf, _("BAD[0x%lx]"), (long) ndx);
+  else
+    sprintf (name_buf, "<section 0x%lx>", (long) ndx);
+
+  return name_buf;
 }
 
 /* Return a pointer to section NAME, or NULL if no such section exists.  */
@@ -1018,17 +1132,6 @@ find_section_in_set (Filedata * filedata, const char * name, unsigned int * set)
   return find_section (filedata, name);
 }
 
-/* Return TRUE if the current file is for IA-64 machine and OpenVMS ABI.
-   This OS has so many departures from the ELF standard that we test it at
-   many places.  */
-
-static inline bool
-is_ia64_vms (Filedata * filedata)
-{
-  return filedata->file_header.e_machine == EM_IA_64
-    && filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_OPENVMS;
-}
-
 /* Guess the relocation size commonly used by the specific machines.  */
 
 static bool
@@ -2011,7 +2114,7 @@ dump_relocations (Filedata *filedata,
                  else
                    name = strtab + psym->st_name;
 
-                 len = print_symbol (width, name);
+                 len = print_symbol_name (width, name);
                  if (version_string)
                    printf (sym_info == symbol_public ? "@@%s" : "@%s",
                            version_string);
@@ -2027,47 +2130,12 @@ dump_relocations (Filedata *filedata,
              if (psym->st_name == 0)
                {
                  const char * sec_name = "<null>";
-                 char name_buf[40];
 
                  if (ELF_ST_TYPE (psym->st_info) == STT_SECTION)
-                   {
-                     if (psym->st_shndx < filedata->file_header.e_shnum
-                         && filedata->section_headers != NULL)
-                       sec_name = section_name_print (filedata,
-                                                      filedata->section_headers
-                                                      + psym->st_shndx);
-                     else if (psym->st_shndx == SHN_ABS)
-                       sec_name = "ABS";
-                     else if (psym->st_shndx == SHN_COMMON)
-                       sec_name = "COMMON";
-                     else if ((filedata->file_header.e_machine == EM_MIPS
-                               && psym->st_shndx == SHN_MIPS_SCOMMON)
-                              || (filedata->file_header.e_machine == EM_TI_C6000
-                                  && psym->st_shndx == SHN_TIC6X_SCOMMON))
-                       sec_name = "SCOMMON";
-                     else if (filedata->file_header.e_machine == EM_MIPS
-                              && psym->st_shndx == SHN_MIPS_SUNDEFINED)
-                       sec_name = "SUNDEF";
-                     else if ((filedata->file_header.e_machine == EM_X86_64
-                               || filedata->file_header.e_machine == EM_L1OM
-                               || filedata->file_header.e_machine == EM_K1OM)
-                              && psym->st_shndx == SHN_X86_64_LCOMMON)
-                       sec_name = "LARGE_COMMON";
-                     else if (filedata->file_header.e_machine == EM_IA_64
-                              && filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_HPUX
-                              && psym->st_shndx == SHN_IA_64_ANSI_COMMON)
-                       sec_name = "ANSI_COM";
-                     else if (is_ia64_vms (filedata)
-                              && psym->st_shndx == SHN_IA_64_VMS_SYMVEC)
-                       sec_name = "VMS_SYMVEC";
-                     else
-                       {
-                         sprintf (name_buf, "<section 0x%x>",
-                                  (unsigned int) psym->st_shndx);
-                         sec_name = name_buf;
-                       }
-                   }
-                 print_symbol (22, sec_name);
+                   sec_name = printable_section_name_from_index
+                     (filedata, psym->st_shndx, NULL);
+
+                 print_symbol_name (22, sec_name);
                }
              else if (strtab == NULL)
                printf (_("<string table index: %3ld>"), psym->st_name);
@@ -2079,7 +2147,7 @@ dump_relocations (Filedata *filedata,
                }
              else
                {
-                 print_symbol (22, strtab + psym->st_name);
+                 print_symbol_name (22, strtab + psym->st_name);
                  if (version_string)
                    printf (sym_info == symbol_public ? "@@%s" : "@%s",
                            version_string);
@@ -5484,6 +5552,7 @@ enum long_option_values
   OPTION_RECURSE_LIMIT,
   OPTION_NO_RECURSE_LIMIT,
   OPTION_NO_DEMANGLING,
+  OPTION_NO_EXTRA_SYM_INFO,
   OPTION_SYM_BASE
 };
 
@@ -5523,10 +5592,12 @@ static struct option options[] =
   {"version-info",     no_argument, 0, 'V'},
   {"version",         no_argument, 0, 'v'},
   {"wide",            no_argument, 0, 'W'},
+  {"extra-sym-info",   no_argument, 0, 'X'},
   {"hex-dump",        required_argument, 0, 'x'},
   {"decompress",       no_argument, 0, 'z'},
 
   {"no-demangle",      no_argument, 0, OPTION_NO_DEMANGLING},
+  {"no-extra-sym-info",no_argument, 0, OPTION_NO_EXTRA_SYM_INFO},
   {"recurse-limit",    no_argument, NULL, OPTION_RECURSE_LIMIT},
   {"no-recurse-limit", no_argument, NULL, OPTION_NO_RECURSE_LIMIT},
   {"no-recursion-limit", no_argument, NULL, OPTION_NO_RECURSE_LIMIT},
@@ -5601,7 +5672,11 @@ usage (FILE * stream)
                           escape sequences, or treat them as invalid and display as\n\
                           \"{hex sequences}\"\n"));
   fprintf (stream, _("\
-  -n --notes             Display the core notes (if present)\n"));
+     -X --extra-sym-info Display extra information when showing symbols\n"));
+  fprintf (stream, _("\
+     --no-extra-sym-info Do not display extra information when showing symbols (default)\n"));              
+  fprintf (stream, _("\
+  -n --notes             Display the contents of note sections (if present)\n"));
   fprintf (stream, _("\
   -r --relocs            Display the relocations (if present)\n"));
   fprintf (stream, _("\
@@ -5794,7 +5869,7 @@ parse_args (struct dump_data *dumpdata, int argc, char ** argv)
     usage (stderr);
 
   while ((c = getopt_long
-         (argc, argv, "ACDHILNPR:STU:VWacdeghi:lnp:rstuvw::x:z", options, NULL)) != EOF)
+         (argc, argv, "ACDHILNPR:STU:VWXacdeghi:lnp:rstuvw::x:z", options, NULL)) != EOF)
     {
       switch (c)
        {
@@ -5977,6 +6052,13 @@ parse_args (struct dump_data *dumpdata, int argc, char ** argv)
        case OPTION_LTO_SYMS:
          do_lto_syms = true;
          break;
+       case 'X':
+         extra_sym_info = true;
+         break;
+       case OPTION_NO_EXTRA_SYM_INFO:
+         extra_sym_info = false;
+         break;
+         
 #ifdef SUPPORT_DISASSEMBLY
        case 'i':
          request_dump (dumpdata, DISASS_DUMP);
@@ -7652,7 +7734,7 @@ process_section_headers (Filedata * filedata)
        i < filedata->file_header.e_shnum;
        i++, section++)
     {
-      const char *name = section_name_print (filedata, section);
+      const char *name = printable_section_name (filedata, section);
 
       /* Run some sanity checks on the headers and
         possibly fill in some file data as well.  */
@@ -7999,7 +8081,7 @@ process_section_headers (Filedata * filedata)
       if (do_section_details)
        printf ("%s\n      ", printable_section_name (filedata, section));
       else
-       print_symbol (-17, section_name_print (filedata, section));
+       print_symbol_name (-17, printable_section_name (filedata, section));
 
       printf (do_wide ? " %-15s " : " %-15.15s ",
              get_section_type_name (filedata, section->sh_type));
@@ -8424,9 +8506,9 @@ process_section_groups (Filedata * filedata)
                  continue;
                }
 
-             group_name = section_name_print (filedata,
-                                              filedata->section_headers
-                                              + sym->st_shndx);
+             group_name = printable_section_name (filedata,
+                                                  filedata->section_headers
+                                                  + sym->st_shndx);
              strtab_sec = NULL;
              free (strtab);
              strtab = NULL;
@@ -12530,7 +12612,7 @@ process_version_sections (Filedata * filedata)
            printf (_(" Addr: 0x%016" PRIx64), section->sh_addr);
            printf (_("  Offset: 0x%08" PRIx64 "  Link: %u (%s)\n"),
                    section->sh_offset, section->sh_link,
-                   printable_section_name_from_index (filedata, section->sh_link));
+                   printable_section_name_from_index (filedata, section->sh_link, NULL));
 
            edefs = (Elf_External_Verdef *)
                 get_data (NULL, filedata, section->sh_offset, 1,section->sh_size,
@@ -12676,7 +12758,7 @@ process_version_sections (Filedata * filedata)
            printf (_(" Addr: 0x%016" PRIx64), section->sh_addr);
            printf (_("  Offset: 0x%08" PRIx64 "  Link: %u (%s)\n"),
                    section->sh_offset, section->sh_link,
-                   printable_section_name_from_index (filedata, section->sh_link));
+                   printable_section_name_from_index (filedata, section->sh_link, NULL));
 
            eneed = (Elf_External_Verneed *) get_data (NULL, filedata,
                                                        section->sh_offset, 1,
@@ -13348,51 +13430,6 @@ get_symbol_other (Filedata * filedata, unsigned int other)
   return buff;
 }
 
-static const char *
-get_symbol_index_type (Filedata * filedata, unsigned int type)
-{
-  static char buff[32];
-
-  switch (type)
-    {
-    case SHN_UNDEF:    return "UND";
-    case SHN_ABS:      return "ABS";
-    case SHN_COMMON:   return "COM";
-    default:
-      if (type == SHN_IA_64_ANSI_COMMON
-         && filedata->file_header.e_machine == EM_IA_64
-         && filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_HPUX)
-       return "ANSI_COM";
-      else if ((filedata->file_header.e_machine == EM_X86_64
-               || filedata->file_header.e_machine == EM_L1OM
-               || filedata->file_header.e_machine == EM_K1OM)
-              && type == SHN_X86_64_LCOMMON)
-       return "LARGE_COM";
-      else if ((type == SHN_MIPS_SCOMMON
-               && filedata->file_header.e_machine == EM_MIPS)
-              || (type == SHN_TIC6X_SCOMMON
-                  && filedata->file_header.e_machine == EM_TI_C6000))
-       return "SCOM";
-      else if (type == SHN_MIPS_SUNDEFINED
-              && filedata->file_header.e_machine == EM_MIPS)
-       return "SUND";
-      else if (type >= SHN_LOPROC && type <= SHN_HIPROC)
-       sprintf (buff, "PRC[0x%04x]", type & 0xffff);
-      else if (type >= SHN_LOOS && type <= SHN_HIOS)
-       sprintf (buff, "OS [0x%04x]", type & 0xffff);
-      else if (type >= SHN_LORESERVE)
-       sprintf (buff, "RSV[0x%04x]", type & 0xffff);
-      else if (filedata->file_header.e_shnum != 0
-              && type >= filedata->file_header.e_shnum)
-       sprintf (buff, _("bad section index[%3d]"), type);
-      else
-       sprintf (buff, "%3d", type);
-      break;
-    }
-
-  return buff;
-}
-
 static const char *
 get_symbol_version_string (Filedata *filedata,
                           bool is_dynsym,
@@ -13570,7 +13607,7 @@ get_symbol_version_string (Filedata *filedata,
 /* Display a symbol size on stdout.  Format is based on --sym-base setting.  */
 
 static unsigned int
-print_dynamic_symbol_size (uint64_t vma, int base)
+print_symbol_size (uint64_t vma, int base)
 {
   switch (base)
     {
@@ -13589,23 +13626,28 @@ print_dynamic_symbol_size (uint64_t vma, int base)
     }
 }
 
+/* Print information on a single symbol.  */
+
 static void
-print_dynamic_symbol (Filedata *filedata, uint64_t si,
-                     Elf_Internal_Sym *symtab,
-                     Elf_Internal_Shdr *section,
-                     char *strtab, size_t strtab_size)
+print_symbol (Filedata *           filedata,
+             uint64_t             symbol_index,
+             Elf_Internal_Sym *   symtab,
+             Elf_Internal_Shdr *  section,
+             char *               strtab,
+             size_t               strtab_size)
 {
   const char *version_string;
   enum versioned_symbol_info sym_info;
   unsigned short vna_other;
-  bool is_valid;
   const char * sstr;
-  Elf_Internal_Sym *psym = symtab + si;
+  Elf_Internal_Sym *psym = symtab + symbol_index;
 
-  printf ("%6" PRId64 ": ", si);
+  /* FIXME: We should have a table of field widths,
+     rather than using hard coded constants.  */
+  printf ("%6" PRId64 ": ", symbol_index);
   print_vma (psym->st_value, LONG_HEX);
   putchar (' ');
-  print_dynamic_symbol_size (psym->st_size, sym_base);
+  print_symbol_size (psym->st_size, sym_base);
   printf (" %-7s", get_symbol_type (filedata, ELF_ST_TYPE (psym->st_info)));
   printf (" %-6s", get_symbol_binding (filedata, ELF_ST_BIND (psym->st_info)));
   if (filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_SOLARIS)
@@ -13615,29 +13657,61 @@ print_dynamic_symbol (Filedata *filedata, uint64_t si,
       unsigned int vis = ELF_ST_VISIBILITY (psym->st_other);
 
       printf (" %-7s", get_symbol_visibility (vis));
+
       /* Check to see if any other bits in the st_other field are set.
-        Note - displaying this information disrupts the layout of the
-        table being generated, but for the moment this case is very rare.  */
+        FIXME: Displaying this information here disrupts the layout
+        of the table being generated.  */
       if (psym->st_other ^ vis)
        printf (" [%s] ", get_symbol_other (filedata, psym->st_other ^ vis));
     }
-  printf (" %4s ", get_symbol_index_type (filedata, psym->st_shndx));
 
+  bool is_special;
+
+  sstr = printable_section_name_from_index (filedata, psym->st_shndx, & is_special);
+
+  /* Print the symbol's section index.  If the index is special
+     then print the index's name rather than its number.  */
+  if (is_special)
+    {
+      int printed;
+
+      /* Special case: If there are no section headers, and the printable
+        name is "<section 0x...." then just display the section number
+        as a decimal.  This happens when objcopy --strip -section-headers
+        is used.  */
+      if (filedata->file_header.e_shnum == 0 && startswith (sstr, "<section"))
+       printed = printf (" %4d ", psym->st_shndx);
+      else
+       printed = printf (" %4s ", sstr);
+
+      if (extra_sym_info && printed < 16)
+       printf ("%*s", 16 - printed, "");
+    }
+  else
+    {
+      printf (" %4u ", psym->st_shndx);
+
+      if (extra_sym_info)
+       {
+         /* Display the section name referenced by the section index.  */
+         int printed = printf ("(%s) ", sstr);
+         if (printed < 10)
+           printf ("%*s", 10 - printed, "");
+       }
+    }
+  
+  /* Get the symbol's name.  For section symbols without a
+     specific name use the (already computed) section name.  */
   if (ELF_ST_TYPE (psym->st_info) == STT_SECTION
-      && psym->st_shndx < filedata->file_header.e_shnum
-      && filedata->section_headers != NULL
+      && section_index_real (filedata, psym->st_shndx)
       && psym->st_name == 0)
     {
-      is_valid
-       = section_name_valid (filedata,
-                             filedata->section_headers + psym->st_shndx);
-      sstr = is_valid ?
-       section_name_print (filedata,
-                           filedata->section_headers + psym->st_shndx)
-       : _("<corrupt>");
+      ;
     }
   else
     {
+      bool is_valid;
+
       is_valid = valid_symbol_name (strtab, strtab_size, psym->st_name);
       sstr = is_valid  ? strtab + psym->st_name : _("<corrupt>");
     }
@@ -13646,7 +13720,7 @@ print_dynamic_symbol (Filedata *filedata, uint64_t si,
     = get_symbol_version_string (filedata,
                                 (section == NULL
                                  || section->sh_type == SHT_DYNSYM),
-                                strtab, strtab_size, si,
+                                strtab, strtab_size, symbol_index,
                                 psym, &sym_info, &vna_other);
 
   int len_avail = 21;
@@ -13662,7 +13736,7 @@ print_dynamic_symbol (Filedata *filedata, uint64_t si,
        len_avail -= 1;
     }
 
-  print_symbol (len_avail, sstr);
+  print_symbol_name (len_avail, sstr);
 
   if (version_string)
     {
@@ -13677,14 +13751,14 @@ print_dynamic_symbol (Filedata *filedata, uint64_t si,
 
   if (ELF_ST_BIND (psym->st_info) == STB_LOCAL
       && section != NULL
-      && si >= section->sh_info
+      && symbol_index >= section->sh_info
       /* Irix 5 and 6 MIPS binaries are known to ignore this requirement.  */
       && filedata->file_header.e_machine != EM_MIPS
       /* Solaris binaries have been found to violate this requirement as
         well.  Not sure if this is a bug or an ABI requirement.  */
       && filedata->file_header.e_ident[EI_OSABI] != ELFOSABI_SOLARIS)
     warn (_("local symbol %" PRIu64 " found at index >= %s's sh_info value of %u\n"),
-         si, printable_section_name (filedata, section), section->sh_info);
+         symbol_index, printable_section_name (filedata, section), section->sh_info);
 }
 
 static const char *
@@ -13881,7 +13955,7 @@ display_lto_symtab (Filedata *           filedata,
                      slot,
                      get_lto_sym_type (sym_type),
                      sec_kind);
-             print_symbol (6, (const char *) sym_name);
+             print_symbol_name (6, (const char *) sym_name);
            }
          else
            {
@@ -13898,7 +13972,7 @@ display_lto_symtab (Filedata *           filedata,
                  get_lto_visibility (visibility),
                  size,
                  slot);
-         print_symbol (21, (const char *) sym_name);
+         print_symbol_name (21, (const char *) sym_name);
        }
       putchar ('\n');
     }
@@ -13947,6 +14021,57 @@ process_lto_symbol_tables (Filedata * filedata)
   return res;
 }
 
+static void
+print_symbol_table_heading (void)
+{
+  /* FIXME: We should store the size of each field in the display in a table and
+     then use the values inside print_symbol(), instead of that function using
+     hard coded constants.  */
+  if (is_32bit_elf)
+    {
+      if (extra_sym_info)
+       {
+         printf (_("   Num:    Value  Size Type    Bind   Vis+Other  Ndx(SecName) Name [+ Version Info]\n"));
+         /*         |--6-|: |--8---| |-5-| |--7--| |-6--| |--7--| |---8--| |----13.....| |...........  */
+         /* eg:          5: 00000000    14 FUNC    LOCAL  DEFAULT            1 (.text)   get_sections  */
+       }
+      else if (do_wide)
+       {
+         printf (_("   Num:    Value  Size Type    Bind   Vis      Ndx Name\n"));
+         /*         |--6-|: |--8---| |-5-| |--7--| |-6--| |--7--| |-4| |...........  */
+         /* eg:          5: 00000000    14 FUNC    LOCAL  DEFAULT      1 get_sections  */
+       }
+      else
+       {
+         printf (_("   Num:    Value  Size Type    Bind   Vis      Ndx Name\n"));
+         /*         |--6-|: |--8---| |-5-| |--7--| |-6--| |--7--| |-4| |------------29-------------|  */
+         /* eg:          5: 00000000    14 FUNC    LOCAL  DEFAULT    1 get_sections  */
+       }
+    }
+  else
+    {
+      if (extra_sym_info)
+       {
+         printf (_("   Num:    Value          Size Type    Bind   Vis+Other Ndx(SecName) Name [+ Version Info]\n"));
+         /*         |--6-|: |------16------| |-5-| |--7--| |-6--| |--7--| |-------14---| |..... */
+         /* eg:          2: 0000000000000000     0 FUNC    LOCAL  DEFAULT    1 (.text)   .very_long_function_name  */
+
+       }
+      else if (do_wide)
+       {
+         printf (_("   Num:    Value          Size Type    Bind   Vis      Ndx Name\n"));
+         /*         |--6-|: |------16------| |-5-| |--7--| |-6--| |--7--| |-4| |...........  */
+         /* eg:          5: 0000000000000000    14 FUNC    LOCAL  DEFAULT    1  very_long_function_name  */
+       }
+      else
+       {
+         printf (_("   Num:    Value          Size Type    Bind   Vis      Ndx Name\n"));
+         /*         |--6-|: |------16------| |-5-| |--7--| |-6--| |--7--| |-4| |--------21---------|  */
+         /* eg:          5: 0000000000000000    14 FUNC    LOCAL  DEFAULT    1 very_long_functi[...]  */
+       }
+    }
+}
+
 /* Dump the symbol table.  */
 
 static bool
@@ -13984,15 +14109,13 @@ process_symbol_table (Filedata * filedata)
                            filedata->num_dynamic_syms),
                  filedata->num_dynamic_syms);
        }
-      if (is_32bit_elf)
-       printf (_("   Num:    Value  Size Type    Bind   Vis      Ndx Name\n"));
-      else
-       printf (_("   Num:    Value          Size Type    Bind   Vis      Ndx Name\n"));
+
+      print_symbol_table_heading ();
 
       for (si = 0; si < filedata->num_dynamic_syms; si++)
-       print_dynamic_symbol (filedata, si, filedata->dynamic_symbols, NULL,
-                             filedata->dynamic_strings,
-                             filedata->dynamic_strings_length);
+       print_symbol (filedata, si, filedata->dynamic_symbols, NULL,
+                     filedata->dynamic_strings,
+                     filedata->dynamic_strings_length);
     }
   else if ((do_dyn_syms || (do_syms && !do_using_dynamic))
           && filedata->section_headers != NULL)
@@ -14041,10 +14164,7 @@ process_symbol_table (Filedata * filedata)
                    printable_section_name (filedata, section),
                    num_syms);
 
-         if (is_32bit_elf)
-           printf (_("   Num:    Value  Size Type    Bind   Vis      Ndx Name\n"));
-         else
-           printf (_("   Num:    Value          Size Type    Bind   Vis      Ndx Name\n"));
+         print_symbol_table_heading ();
 
          symtab = get_elf_symbols (filedata, section, & num_syms);
          if (symtab == NULL)
@@ -14068,8 +14188,8 @@ process_symbol_table (Filedata * filedata)
            }
 
          for (si = 0; si < num_syms; si++)
-           print_dynamic_symbol (filedata, si, symtab, section,
-                                 strtab, strtab_size);
+           print_symbol (filedata, si, symtab, section,
+                         strtab, strtab_size);
 
          free (symtab);
          if (strtab != filedata->string_table)
@@ -14297,7 +14417,7 @@ process_syminfo (Filedata * filedata)
       if (i >= filedata->num_dynamic_syms)
        printf (_("<corrupt index>"));
       else if (valid_dynamic_name (filedata, filedata->dynamic_symbols[i].st_name))
-       print_symbol (30, get_dynamic_name (filedata,
+       print_symbol_name (30, get_dynamic_name (filedata,
                                            filedata->dynamic_symbols[i].st_name));
       else
        printf (_("<corrupt: %19ld>"), filedata->dynamic_symbols[i].st_name);
@@ -14317,7 +14437,7 @@ process_syminfo (Filedata * filedata)
              && valid_dynamic_name (filedata,
                                     filedata->dynamic_section[filedata->dynamic_syminfo[i].si_boundto].d_un.d_val))
            {
-             print_symbol (10, get_dynamic_name (filedata,
+             print_symbol_name (10, get_dynamic_name (filedata,
                                                  filedata->dynamic_section[filedata->dynamic_syminfo[i].si_boundto].d_un.d_val));
              putchar (' ' );
            }
@@ -16215,7 +16335,7 @@ dump_section_as_bytes (Elf_Internal_Shdr *section,
 static ctf_sect_t *
 shdr_to_ctf_sect (ctf_sect_t *buf, Elf_Internal_Shdr *shdr, Filedata *filedata)
 {
-  buf->cts_name = section_name_print (filedata, shdr);
+  buf->cts_name = printable_section_name (filedata, shdr);
   buf->cts_size = shdr->sh_size;
   buf->cts_entsize = shdr->sh_entsize;
 
@@ -17046,7 +17166,7 @@ display_tag_value (signed int tag,
       putchar ('"');
       if (maxlen > 0)
        {
-         print_symbol ((int) maxlen, (const char *) p);
+         print_symbol_name ((int) maxlen, (const char *) p);
          p += strnlen ((char *) p, maxlen) + 1;
        }
       else
@@ -17471,7 +17591,7 @@ display_arm_attribute (unsigned char * p,
                  {
                    size_t maxlen = (end - p) - 1;
 
-                   print_symbol ((int) maxlen, (const char *) p);
+                   print_symbol_name ((int) maxlen, (const char *) p);
                    p += strnlen ((char *) p, maxlen) + 1;
                  }
                else
@@ -17560,7 +17680,7 @@ display_gnu_attribute (unsigned char * p,
            {
              size_t maxlen = (end - p) - 1;
 
-             print_symbol ((int) maxlen, (const char *) p);
+             print_symbol_name ((int) maxlen, (const char *) p);
              p += strnlen ((char *) p, maxlen) + 1;
            }
          else
@@ -18153,7 +18273,7 @@ display_tic6x_attribute (unsigned char * p,
          {
            size_t maxlen = (end - p) - 1;
 
-           print_symbol ((int) maxlen, (const char *) p);
+           print_symbol_name ((int) maxlen, (const char *) p);
            p += strnlen ((char *) p, maxlen) + 1;
          }
        else
@@ -18172,7 +18292,7 @@ display_tic6x_attribute (unsigned char * p,
          {
            size_t maxlen = (end - p) - 1;
 
-           print_symbol ((int) maxlen, (const char *) p);
+           print_symbol_name ((int) maxlen, (const char *) p);
            p += strnlen ((char *) p, maxlen) + 1;
          }
        else
@@ -18291,7 +18411,7 @@ display_msp430_attribute (unsigned char * p,
            {
              size_t maxlen = (end - p) - 1;
 
-             print_symbol ((int) maxlen, (const char *) p);
+             print_symbol_name ((int) maxlen, (const char *) p);
              p += strnlen ((char *) p, maxlen) + 1;
            }
          else
@@ -18613,7 +18733,7 @@ process_attributes (Filedata * filedata,
                }
 
              printf (_("Attribute Section: "));
-             print_symbol (INT_MAX, (const char *) p);
+             print_symbol_name (INT_MAX, (const char *) p);
              putchar ('\n');
 
              if (public_name && streq ((char *) p, public_name))
@@ -19180,7 +19300,7 @@ process_mips_specific (Filedata * filedata)
 
              printf ("%3zu: ", cnt);
              if (valid_dynamic_name (filedata, liblist.l_name))
-               print_symbol (20, get_dynamic_name (filedata, liblist.l_name));
+               print_symbol_name (20, get_dynamic_name (filedata, liblist.l_name));
              else
                printf (_("<corrupt: %9ld>"), liblist.l_name);
              printf (" %s %#10lx %-7ld", timebuf, liblist.l_checksum,
@@ -19559,7 +19679,7 @@ process_mips_specific (Filedata * filedata)
              print_vma (psym->st_value, FULL_HEX);
              putchar (' ');
              if (valid_dynamic_name (filedata, psym->st_name))
-               print_symbol (25, get_dynamic_name (filedata, psym->st_name));
+               print_symbol_name (25, get_dynamic_name (filedata, psym->st_name));
              else
                printf (_("<corrupt: %14ld>"), psym->st_name);
            }
@@ -19680,12 +19800,17 @@ process_mips_specific (Filedata * filedata)
                  Elf_Internal_Sym * psym = filedata->dynamic_symbols + i;
 
                  print_vma (psym->st_value, LONG_HEX);
-                 printf (" %-7s %3s ",
-                         get_symbol_type (filedata, ELF_ST_TYPE (psym->st_info)),
-                         get_symbol_index_type (filedata, psym->st_shndx));
+                 printf (" %-7s ", get_symbol_type (filedata, ELF_ST_TYPE (psym->st_info)));
+
+                 bool is_special;
+                 const char * s = printable_section_name_from_index (filedata, psym->st_shndx, & is_special);
+                 if (is_special)
+                   printf ("%3s ", s);
+                 else
+                   printf ("%3u ", psym->st_shndx);
 
                  if (valid_dynamic_name (filedata, psym->st_name))
-                   print_symbol (sym_width,
+                   print_symbol_name (sym_width,
                                  get_dynamic_name (filedata, psym->st_name));
                  else
                    printf (_("<corrupt: %14ld>"), psym->st_name);
@@ -19771,9 +19896,9 @@ process_mips_specific (Filedata * filedata)
              print_vma (psym->st_value, LONG_HEX);
              printf (" %-7s %3s ",
                      get_symbol_type (filedata, ELF_ST_TYPE (psym->st_info)),
-                     get_symbol_index_type (filedata, psym->st_shndx));
+                     printable_section_name_from_index (filedata, psym->st_shndx, NULL));
              if (valid_dynamic_name (filedata, psym->st_name))
-               print_symbol (sym_width,
+               print_symbol_name (sym_width,
                              get_dynamic_name (filedata, psym->st_name));
              else
                printf (_("<corrupt: %14ld>"), psym->st_name);
@@ -21774,7 +21899,7 @@ print_gnu_build_attribute_name (Elf_Internal_Note * pnote)
   if (name == NULL || pnote->namesz < 2)
     {
       error (_("corrupt name field in GNU build attribute note: size = %ld\n"), pnote->namesz);
-      print_symbol (-20, _("  <corrupt name>"));
+      print_symbol_name (-20, _("  <corrupt name>"));
       return false;
     }
 
@@ -21789,7 +21914,7 @@ print_gnu_build_attribute_name (Elf_Internal_Note * pnote)
       if (pnote->namesz < 4)
        {
          error (_("corrupt name field in GNU build attribute note: size = %ld\n"), pnote->namesz);
-         print_symbol (-20, _("  <corrupt name>"));
+         print_symbol_name (-20, _("  <corrupt name>"));
          return false;
        }
 
@@ -21809,7 +21934,7 @@ print_gnu_build_attribute_name (Elf_Internal_Note * pnote)
       break;
     default:
       error (_("unrecognised attribute type in name field: %d\n"), name_type);
-      print_symbol (-20, _("<unknown name type>"));
+      print_symbol_name (-20, _("<unknown name type>"));
       return false;
     }
 
@@ -21963,7 +22088,7 @@ print_gnu_build_attribute_name (Elf_Internal_Note * pnote)
 
        if (decoded != NULL)
          {
-           print_symbol (-left, decoded);
+           print_symbol_name (-left, decoded);
            left = 0;
          }
        else if (val == 0)
@@ -21981,13 +22106,13 @@ print_gnu_build_attribute_name (Elf_Internal_Note * pnote)
       }
       break;
     case GNU_BUILD_ATTRIBUTE_TYPE_STRING:
-      left -= print_symbol (- left, name);
+      left -= print_symbol_name (- left, name);
       break;
     case GNU_BUILD_ATTRIBUTE_TYPE_BOOL_TRUE:
-      left -= print_symbol (- left, "true");
+      left -= print_symbol_name (- left, "true");
       break;
     case GNU_BUILD_ATTRIBUTE_TYPE_BOOL_FALSE:
-      left -= print_symbol (- left, "false");
+      left -= print_symbol_name (- left, "false");
       break;
     }
 
@@ -22275,7 +22400,7 @@ process_note (Elf_Internal_Note *  pnote,
          || pnote->type == NT_GNU_BUILD_ATTRIBUTE_FUNC))
     print_gnu_build_attribute_name (pnote);
   else
-    print_symbol (-20, name);
+    print_symbol_name (-20, name);
 
   if (do_wide)
     printf (" 0x%08lx\t%s\t", pnote->descsz, nt);