}
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) \
unsigned long nsyms,
char * strtab,
unsigned long strtablen,
- int is_rela)
+ int is_rela,
+ int is_dynsym)
{
unsigned int i;
Elf_Internal_Rela * rels;
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)
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
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)
{
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);
}
}
}
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;
}
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)
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 (' ');
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');