Display symbol version when dumping dynrelocs
[deliverable/binutils-gdb.git] / binutils / readelf.c
index e8ce2793404b783772d8f7fbfd0556189ed1d3de..71fc827f28eef535fb382131729c4fd65c6b3a8c 100644 (file)
@@ -272,6 +272,20 @@ typedef enum print_mode
 }
 print_mode;
 
+/* Versioned symbol info.  */
+enum versioned_symbol_info
+{
+  symbol_undefined,
+  symbol_hidden,
+  symbol_public
+};
+
+static const char *get_symbol_version_string
+  (FILE *file, int is_dynsym, const char *strtab,
+   unsigned long int strtab_size, unsigned int si,
+   Elf_Internal_Sym *psym, enum versioned_symbol_info *sym_info,
+   unsigned short *vna_other);
+
 #define UNKNOWN -1
 
 #define SECTION_NAME(X)                                                \
@@ -1015,7 +1029,8 @@ dump_relocations (FILE * file,
                  unsigned long nsyms,
                  char * strtab,
                  unsigned long strtablen,
-                 int is_rela)
+                 int is_rela,
+                 int is_dynsym)
 {
   unsigned int i;
   Elf_Internal_Rela * rels;
@@ -1448,9 +1463,20 @@ dump_relocations (FILE * file,
          else
            {
              Elf_Internal_Sym * psym;
+             const char * version_string;
+             enum versioned_symbol_info sym_info;
+             unsigned short vna_other;
 
              psym = symtab + symtab_index;
 
+             version_string
+               = get_symbol_version_string (file, is_dynsym,
+                                            strtab, strtablen,
+                                            symtab_index,
+                                            psym,
+                                            &sym_info,
+                                            &vna_other);
+
              printf (" ");
 
              if (ELF_ST_TYPE (psym->st_info) == STT_GNU_IFUNC)
@@ -1477,6 +1503,9 @@ dump_relocations (FILE * file,
                    name = strtab + psym->st_name;
 
                  len = print_symbol (width, name);
+                 if (version_string)
+                   printf (sym_info == symbol_public ? "@@%s" : "@%s",
+                           version_string);
                  printf ("()%-*s", len <= width ? (width + 1) - len : 1, " ");
                }
              else
@@ -1533,7 +1562,12 @@ dump_relocations (FILE * file,
              else if (psym->st_name >= strtablen)
                printf (_("<corrupt string table index: %3ld>"), psym->st_name);
              else
-               print_symbol (22, strtab + psym->st_name);
+               {
+                 print_symbol (22, strtab + psym->st_name);
+                 if (version_string)
+                   printf (sym_info == symbol_public ? "@@%s" : "@%s",
+                           version_string);
+               }
 
              if (is_rela)
                {
@@ -6097,7 +6131,8 @@ process_relocs (FILE * file)
                                offset_from_vma (file, rel_offset, rel_size),
                                rel_size,
                                dynamic_symbols, num_dynamic_syms,
-                               dynamic_strings, dynamic_strings_length, is_rela);
+                               dynamic_strings, dynamic_strings_length,
+                               is_rela, 1);
            }
        }
 
@@ -6172,14 +6207,16 @@ process_relocs (FILE * file)
                    }
 
                  dump_relocations (file, rel_offset, rel_size,
-                                   symtab, nsyms, strtab, strtablen, is_rela);
+                                   symtab, nsyms, strtab, strtablen,
+                                   is_rela,
+                                   symsec->sh_type == SHT_DYNSYM);
                  if (strtab)
                    free (strtab);
                  free (symtab);
                }
              else
                dump_relocations (file, rel_offset, rel_size,
-                                 NULL, 0, NULL, 0, is_rela);
+                                 NULL, 0, NULL, 0, is_rela, 0);
 
              found = 1;
            }
@@ -9879,6 +9916,181 @@ print_dynamic_symbol (bfd_vma si, unsigned long hn)
   putchar ('\n');
 }
 
+static const char *
+get_symbol_version_string (FILE *file, int is_dynsym,
+                          const char *strtab,
+                          unsigned long int strtab_size,
+                          unsigned int si, Elf_Internal_Sym *psym,
+                          enum versioned_symbol_info *sym_info,
+                          unsigned short *vna_other)
+{
+  const char *version_string = NULL;
+
+  if (is_dynsym
+      && version_info[DT_VERSIONTAGIDX (DT_VERSYM)] != 0)
+    {
+      unsigned char data[2];
+      unsigned short vers_data;
+      unsigned long offset;
+      int is_nobits;
+      int check_def;
+
+      offset = offset_from_vma
+       (file, version_info[DT_VERSIONTAGIDX (DT_VERSYM)],
+        sizeof data + si * sizeof (vers_data));
+
+      if (get_data (&data, file, offset + si * sizeof (vers_data),
+                   sizeof (data), 1, _("version data")) == NULL)
+       return NULL;
+
+      vers_data = byte_get (data, 2);
+
+      is_nobits = (psym->st_shndx < elf_header.e_shnum
+                  && section_headers[psym->st_shndx].sh_type
+                  == SHT_NOBITS);
+
+      check_def = (psym->st_shndx != SHN_UNDEF);
+
+      if ((vers_data & VERSYM_HIDDEN) || vers_data > 1)
+       {
+         if (version_info[DT_VERSIONTAGIDX (DT_VERNEED)]
+             && (is_nobits || ! check_def))
+           {
+             Elf_External_Verneed evn;
+             Elf_Internal_Verneed ivn;
+             Elf_Internal_Vernaux ivna;
+
+             /* We must test both.  */
+             offset = offset_from_vma
+               (file, version_info[DT_VERSIONTAGIDX (DT_VERNEED)],
+                sizeof evn);
+
+             do
+               {
+                 unsigned long vna_off;
+
+                 if (get_data (&evn, file, offset, sizeof (evn), 1,
+                               _("version need")) == NULL)
+                   {
+                     ivna.vna_next = 0;
+                     ivna.vna_other = 0;
+                     ivna.vna_name = 0;
+                     break;
+                   }
+
+                 ivn.vn_aux  = BYTE_GET (evn.vn_aux);
+                 ivn.vn_next = BYTE_GET (evn.vn_next);
+
+                 vna_off = offset + ivn.vn_aux;
+
+                 do
+                   {
+                     Elf_External_Vernaux evna;
+
+                     if (get_data (&evna, file, vna_off,
+                                   sizeof (evna), 1,
+                                   _("version need aux (3)")) == NULL)
+                       {
+                         ivna.vna_next = 0;
+                         ivna.vna_other = 0;
+                         ivna.vna_name = 0;
+                       }
+                     else
+                       {
+                         ivna.vna_other = BYTE_GET (evna.vna_other);
+                         ivna.vna_next  = BYTE_GET (evna.vna_next);
+                         ivna.vna_name  = BYTE_GET (evna.vna_name);
+                       }
+
+                     vna_off += ivna.vna_next;
+                   }
+                 while (ivna.vna_other != vers_data
+                        && ivna.vna_next != 0);
+
+                 if (ivna.vna_other == vers_data)
+                   break;
+
+                 offset += ivn.vn_next;
+               }
+             while (ivn.vn_next != 0);
+
+             if (ivna.vna_other == vers_data)
+               {
+                 *sym_info = symbol_undefined;
+                 *vna_other = ivna.vna_other;
+                 version_string = (ivna.vna_name < strtab_size
+                                   ? strtab + ivna.vna_name
+                                   : _("<corrupt>"));
+                 check_def = 0;
+               }
+             else if (! is_nobits)
+               error (_("bad dynamic symbol\n"));
+             else
+               check_def = 1;
+           }
+
+         if (check_def)
+           {
+             if (vers_data != 0x8001
+                 && version_info[DT_VERSIONTAGIDX (DT_VERDEF)])
+               {
+                 Elf_Internal_Verdef ivd;
+                 Elf_Internal_Verdaux ivda;
+                 Elf_External_Verdaux evda;
+                 unsigned long off;
+
+                 off = offset_from_vma
+                   (file,
+                    version_info[DT_VERSIONTAGIDX (DT_VERDEF)],
+                    sizeof (Elf_External_Verdef));
+
+                 do
+                   {
+                     Elf_External_Verdef evd;
+
+                     if (get_data (&evd, file, off, sizeof (evd),
+                                   1, _("version def")) == NULL)
+                       {
+                         ivd.vd_ndx = 0;
+                         ivd.vd_aux = 0;
+                         ivd.vd_next = 0;
+                       }
+                     else
+                       {
+                         ivd.vd_ndx = BYTE_GET (evd.vd_ndx);
+                         ivd.vd_aux = BYTE_GET (evd.vd_aux);
+                         ivd.vd_next = BYTE_GET (evd.vd_next);
+                       }
+
+                     off += ivd.vd_next;
+                   }
+                 while (ivd.vd_ndx != (vers_data & VERSYM_VERSION)
+                        && ivd.vd_next != 0);
+
+                 off -= ivd.vd_next;
+                 off += ivd.vd_aux;
+
+                 if (get_data (&evda, file, off, sizeof (evda),
+                               1, _("version def aux")) == NULL)
+                   return version_string;
+
+                 ivda.vda_name = BYTE_GET (evda.vda_name);
+
+                 if (psym->st_name != ivda.vda_name)
+                   {
+                     *sym_info = ((vers_data & VERSYM_HIDDEN) != 0
+                                  ? symbol_hidden : symbol_public);
+                     version_string = (ivda.vda_name < strtab_size
+                                       ? strtab + ivda.vda_name
+                                       : _("<corrupt>"));
+                   }
+               }
+           }
+       }
+    }
+  return version_string;
+}
+
 /* Dump the symbol table.  */
 static int
 process_symbol_table (FILE * file)
@@ -10179,6 +10391,10 @@ process_symbol_table (FILE * file)
 
          for (si = 0, psym = symtab; si < num_syms; si++, psym++)
            {
+             const char *version_string;
+             enum versioned_symbol_info sym_info;
+             unsigned short vna_other;
+
              printf ("%6d: ", si);
              print_vma (psym->st_value, LONG_HEX);
              putchar (' ');
@@ -10195,163 +10411,18 @@ process_symbol_table (FILE * file)
              print_symbol (25, psym->st_name < strtab_size
                            ? strtab + psym->st_name : _("<corrupt>"));
 
-             if (section->sh_type == SHT_DYNSYM
-                 && version_info[DT_VERSIONTAGIDX (DT_VERSYM)] != 0)
+             version_string
+               = get_symbol_version_string (file,
+                                            section->sh_type == SHT_DYNSYM,
+                                            strtab, strtab_size, si,
+                                            psym, &sym_info, &vna_other);
+             if (version_string)
                {
-                 unsigned char data[2];
-                 unsigned short vers_data;
-                 unsigned long offset;
-                 int is_nobits;
-                 int check_def;
-
-                 offset = offset_from_vma
-                   (file, version_info[DT_VERSIONTAGIDX (DT_VERSYM)],
-                    sizeof data + si * sizeof (vers_data));
-
-                 if (get_data (&data, file, offset + si * sizeof (vers_data),
-                               sizeof (data), 1, _("version data")) == NULL)
-                   break;
-
-                 vers_data = byte_get (data, 2);
-
-                 is_nobits = (psym->st_shndx < elf_header.e_shnum
-                              && section_headers[psym->st_shndx].sh_type
-                                 == SHT_NOBITS);
-
-                 check_def = (psym->st_shndx != SHN_UNDEF);
-
-                 if ((vers_data & VERSYM_HIDDEN) || vers_data > 1)
-                   {
-                     if (version_info[DT_VERSIONTAGIDX (DT_VERNEED)]
-                         && (is_nobits || ! check_def))
-                       {
-                         Elf_External_Verneed evn;
-                         Elf_Internal_Verneed ivn;
-                         Elf_Internal_Vernaux ivna;
-
-                         /* We must test both.  */
-                         offset = offset_from_vma
-                           (file, version_info[DT_VERSIONTAGIDX (DT_VERNEED)],
-                            sizeof evn);
-
-                         do
-                           {
-                             unsigned long vna_off;
-
-                             if (get_data (&evn, file, offset, sizeof (evn), 1,
-                                           _("version need")) == NULL)
-                               {
-                                 ivna.vna_next = 0;
-                                 ivna.vna_other = 0;
-                                 ivna.vna_name = 0;
-                                 break;
-                               }
-
-                             ivn.vn_aux  = BYTE_GET (evn.vn_aux);
-                             ivn.vn_next = BYTE_GET (evn.vn_next);
-
-                             vna_off = offset + ivn.vn_aux;
-
-                             do
-                               {
-                                 Elf_External_Vernaux evna;
-
-                                 if (get_data (&evna, file, vna_off,
-                                               sizeof (evna), 1,
-                                               _("version need aux (3)")) == NULL)
-                                   {
-                                     ivna.vna_next = 0;
-                                     ivna.vna_other = 0;
-                                     ivna.vna_name = 0;
-                                   }
-                                 else
-                                   {
-                                     ivna.vna_other = BYTE_GET (evna.vna_other);
-                                     ivna.vna_next  = BYTE_GET (evna.vna_next);
-                                     ivna.vna_name  = BYTE_GET (evna.vna_name);
-                                   }
-
-                                 vna_off += ivna.vna_next;
-                               }
-                             while (ivna.vna_other != vers_data
-                                    && ivna.vna_next != 0);
-
-                             if (ivna.vna_other == vers_data)
-                               break;
-
-                             offset += ivn.vn_next;
-                           }
-                         while (ivn.vn_next != 0);
-
-                         if (ivna.vna_other == vers_data)
-                           {
-                             printf ("@%s (%d)",
-                                     ivna.vna_name < strtab_size
-                                     ? strtab + ivna.vna_name : _("<corrupt>"),
-                                     ivna.vna_other);
-                             check_def = 0;
-                           }
-                         else if (! is_nobits)
-                           error (_("bad dynamic symbol\n"));
-                         else
-                           check_def = 1;
-                       }
-
-                     if (check_def)
-                       {
-                         if (vers_data != 0x8001
-                             && version_info[DT_VERSIONTAGIDX (DT_VERDEF)])
-                           {
-                             Elf_Internal_Verdef ivd;
-                             Elf_Internal_Verdaux ivda;
-                             Elf_External_Verdaux evda;
-                             unsigned long off;
-
-                             off = offset_from_vma
-                               (file,
-                                version_info[DT_VERSIONTAGIDX (DT_VERDEF)],
-                                sizeof (Elf_External_Verdef));
-
-                             do
-                               {
-                                 Elf_External_Verdef evd;
-
-                                 if (get_data (&evd, file, off, sizeof (evd),
-                                               1, _("version def")) == NULL)
-                                   {
-                                     ivd.vd_ndx = 0;
-                                     ivd.vd_aux = 0;
-                                     ivd.vd_next = 0;
-                                   }
-                                 else
-                                   {
-                                     ivd.vd_ndx = BYTE_GET (evd.vd_ndx);
-                                     ivd.vd_aux = BYTE_GET (evd.vd_aux);
-                                     ivd.vd_next = BYTE_GET (evd.vd_next);
-                                   }
-
-                                 off += ivd.vd_next;
-                               }
-                             while (ivd.vd_ndx != (vers_data & VERSYM_VERSION)
-                                    && ivd.vd_next != 0);
-
-                             off -= ivd.vd_next;
-                             off += ivd.vd_aux;
-
-                             if (get_data (&evda, file, off, sizeof (evda),
-                                           1, _("version def aux")) == NULL)
-                               break;
-
-                             ivda.vda_name = BYTE_GET (evda.vda_name);
-
-                             if (psym->st_name != ivda.vda_name)
-                               printf ((vers_data & VERSYM_HIDDEN)
-                                       ? "@%s" : "@@%s",
-                                       ivda.vda_name < strtab_size
-                                       ? strtab + ivda.vda_name : _("<corrupt>"));
-                           }
-                       }
-                   }
+                 if (sym_info == symbol_undefined)
+                   printf ("@%s (%d)", version_string, vna_other);
+                 else
+                   printf (sym_info == symbol_hidden ? "@%s" : "@@%s",
+                           version_string);
                }
 
              putchar ('\n');
This page took 0.032788 seconds and 4 git commands to generate.