SYMINFO_FLG_INTERPOSE=0x80
SYMINFO_FLG_CAP=0x100
SYMINFO_FLG_DEFERRED=0x200
+
+class VER_FLAGS(object):
+ VER_FLG_BASE=0x1
+ VER_FLG_WEAK=0x2
+ VER_FLG_INFO=0x4
from .enums import (
ENUM_D_TAG, ENUM_E_VERSION, ENUM_RELOC_TYPE_i386, ENUM_RELOC_TYPE_x64
)
-from .constants import P_FLAGS, SH_FLAGS, SUNW_SYMINFO_FLAGS
+from .constants import P_FLAGS, SH_FLAGS, SUNW_SYMINFO_FLAGS, VER_FLAGS
from ..common.py3compat import iteritems
def describe_symbol_boundto(x):
return _DESCR_SYMINFO_BOUNDTO.get(x, '%3s' % x)
+def describe_ver_flags(x):
+ s = ''
+ for flag in (
+ VER_FLAGS.VER_FLG_WEAK,
+ VER_FLAGS.VER_FLG_BASE,
+ VER_FLAGS.VER_FLG_INFO):
+ if x & flag:
+ if s:
+ s += ' | '
+ s += _DESCR_VER_FLAGS[flag]
+ return s
+
#-------------------------------------------------------------------------------
_unknown = '<unknown>'
SYMINFO_BT_EXTERN='<extern>',
)
+_DESCR_VER_FLAGS = {
+ 0: '',
+ VER_FLAGS.VER_FLG_BASE: 'BASE',
+ VER_FLAGS.VER_FLG_WEAK: 'WEAK',
+ VER_FLAGS.VER_FLG_INFO: 'INFO',
+}
+
_DESCR_RELOC_TYPE_i386 = dict(
(v, k) for k, v in iteritems(ENUM_RELOC_TYPE_i386))
from .structs import ELFStructs
from .sections import (
Section, StringTableSection, SymbolTableSection,
- SUNWSyminfoTableSection, NullSection)
+ SUNWSyminfoTableSection, VerneedTableSection,
+ VerdefTableSection, VersymTableSection,
+ NullSection)
from .dynamic import DynamicSection, DynamicSegment
from .relocation import RelocationSection, RelocationHandler
from .segments import Segment, InterpSegment
return self._make_symbol_table_section(section_header, name)
elif sectype == 'SHT_SUNW_syminfo':
return self._make_sunwsyminfo_table_section(section_header, name)
+ elif sectype == 'SHT_GNU_verneed':
+ return self._make_verneed_table_section(section_header, name)
+ elif sectype == 'SHT_GNU_verdef':
+ return self._make_verdef_table_section(section_header, name)
+ elif sectype == 'SHT_GNU_versym':
+ return self._make_versym_table_section(section_header, name)
elif sectype in ('SHT_REL', 'SHT_RELA'):
return RelocationSection(
section_header, name, self.stream, self)
elffile=self,
symboltable=strtab_section)
+ def _make_verneed_table_section(self, section_header, name):
+ """ Create a VerneedTableSection
+ """
+ linked_strtab_index = section_header['sh_link']
+ strtab_section = self.get_section(linked_strtab_index)
+ return VerneedTableSection(
+ section_header, name, self.stream,
+ elffile=self,
+ stringtable=strtab_section)
+
+ def _make_verdef_table_section(self, section_header, name):
+ """ Create a VerdefTableSection
+ """
+ linked_strtab_index = section_header['sh_link']
+ strtab_section = self.get_section(linked_strtab_index)
+ return VerdefTableSection(
+ section_header, name, self.stream,
+ elffile=self,
+ stringtable=strtab_section)
+
+ def _make_versym_table_section(self, section_header, name):
+ """ Create a VersymTableSection
+ """
+ linked_strtab_index = section_header['sh_link']
+ strtab_section = self.get_section(linked_strtab_index)
+ return VersymTableSection(
+ section_header, name, self.stream,
+ elffile=self,
+ symboltable=strtab_section)
+
def _get_segment_header(self, n):
""" Find the header of segment #n, parse it and return the struct
"""
SHT_NUM=19,
SHT_LOOS=0x60000000,
SHT_GNU_HASH=0x6ffffff6,
- SHT_GNU_verdef=0x6ffffffd,
- SHT_GNU_verneed=0x6ffffffe,
- SHT_GNU_versym=0x6fffffff,
+ SHT_GNU_verdef=0x6ffffffd, # also SHT_SUNW_verdef
+ SHT_GNU_verneed=0x6ffffffe, # also SHT_SUNW_verneed
+ SHT_GNU_versym=0x6fffffff, # also SHT_SUNW_versym
SHT_LOPROC=0x70000000,
SHT_HIPROC=0x7fffffff,
SHT_LOUSER=0x80000000,
_default_=Pass,
)
+# Versym section, version dependency index
+ENUM_VERSYM = dict(
+ VER_NDX_LOCAL=0,
+ VER_NDX_GLOBAL=1,
+ VER_NDX_LORESERVE=0xff00,
+ VER_NDX_ELIMINATE=0xff01,
+ _default_=Pass,
+)
+# Sunw Syminfo Bound To special values
+ENUM_SUNW_SYMINFO_BOUNDTO = dict(
+ SYMINFO_BT_SELF=0xffff,
+ SYMINFO_BT_PARENT=0xfffe,
+ SYMINFO_BT_NONE=0xfffd,
+ SYMINFO_BT_EXTERN=0xfffc,
+ _default_=Pass,
+)
+
"""
for i in range(1, self.num_symbols() + 1):
yield self.get_symbol(i)
+
+
+class Version(object):
+ """ Version object - representing a version definition or dependency
+ entry from a "Version Needed" or a "Version Dependency" table section.
+
+ This kind of entry contains a pointer to an array of auxiliary entries
+ that store the information about version names or dependencies.
+ These entries are not stored in this object and should be accessed
+ through the appropriate method of a section object which will return
+ an iterator of VersionAuxiliary objects.
+
+ Similarly to Section objects, allows dictionary-like access to
+ verdef/verneed entry
+ """
+ def __init__(self, entry, name=None):
+ self.entry = entry
+ self.name = name
+
+ def __getitem__(self, name):
+ """ Implement dict-like access to entry
+ """
+ return self.entry[name]
+
+
+class VersionAuxiliary(object):
+ """ Version Auxiliary object - representing an auxiliary entry of a version
+ definition or dependency entry
+
+ Similarly to Section objects, allows dictionary-like access to the
+ verdaux/vernaux entry
+ """
+ def __init__(self, entry, name):
+ self.entry = entry
+ self.name = name
+
+ def __getitem__(self, name):
+ """ Implement dict-like access to entries
+ """
+ return self.entry[name]
+
+class VerneedTableSection(Section):
+ """ ELF SUNW or GNU Version Needed table section.
+ Has an associated StringTableSection that's passed in the constructor.
+ """
+ def __init__(self, header, name, stream, elffile, stringtable):
+ super(VerneedTableSection, self).__init__(header, name, stream)
+ self.elffile = elffile
+ self.elfstructs = self.elffile.structs
+ self.stringtable = stringtable
+ self._has_indexes = None
+
+ def num_versions(self):
+ """ Number of version dependency in the table
+ """
+ return self['sh_info']
+
+ def has_indexes(self):
+ """ Return True if at least one version definition entry has an index
+ that is stored in the vna_other field.
+ This information is used for symbol versioning
+ """
+ if self._has_indexes is None:
+ self._has_indexes = False
+ for _, vernaux_iter in self.iter_versions():
+ for vernaux in vernaux_iter:
+ if vernaux['vna_other']:
+ self._has_indexes = True
+ break
+
+ return self._has_indexes
+
+ def get_version(self, index):
+ """ Get the version information located at index #n in the table
+ Return boths the verneed structure and the vernaux structure
+ that contains the name of the version
+ """
+ for verneed, vernaux_iter in self.iter_versions():
+ for vernaux in vernaux_iter:
+ if vernaux['vna_other'] == index:
+ return verneed, vernaux
+
+ return None
+
+
+ def _iter_version_auxiliaries(self, entry_offset, count):
+ """ Yield all auxiliary entries of a version dependency
+ """
+ for _ in range(count):
+ entry = struct_parse(
+ self.elfstructs.Elf_Vernaux,
+ self.stream,
+ stream_pos=entry_offset)
+
+ name = self.stringtable.get_string(entry['vna_name'])
+ version_aux = VersionAuxiliary(entry, name)
+ yield version_aux
+
+ if not entry['vna_next']:
+ break
+
+ entry_offset += entry['vna_next']
+
+
+ def iter_versions(self):
+ """ Yield all the version dependencies entries in the table
+ Each time it returns the main version dependency structure
+ and an iterator to walk through its auxiliaries entries
+ """
+ entry_offset = self['sh_offset']
+ for _ in range(self.num_versions()):
+ entry = struct_parse(
+ self.elfstructs.Elf_Verneed,
+ self.stream,
+ stream_pos=entry_offset)
+
+ name = self.stringtable.get_string(entry['vn_file'])
+ elf_assert(entry['vn_cnt'] > 0,
+ 'Expected number of version names to be > 0 for version definition %s' % name)
+
+ verneed = Version(entry, name)
+ aux_entries_offset = entry_offset + entry['vn_aux']
+ vernaux_iter = self._iter_version_auxiliaries(aux_entries_offset,
+ entry['vn_cnt'])
+ yield verneed, vernaux_iter
+
+ if not entry['vn_next']:
+ break
+
+ entry_offset += entry['vn_next']
+
+
+class VerdefTableSection(Section):
+ """ ELF SUNW or GNU Version Definition table section.
+ Has an associated StringTableSection that's passed in the constructor.
+ """
+ def __init__(self, header, name, stream, elffile, stringtable):
+ super(VerdefTableSection, self).__init__(header, name, stream)
+ self.elffile = elffile
+ self.elfstructs = self.elffile.structs
+ self.stringtable = stringtable
+
+ def num_versions(self):
+ """ Number of version definitions in the table
+ """
+ return self['sh_info']
+
+ def get_version(self, index):
+ """ Get the version information located at index #n in the table
+ Return boths the verdef structure and an iterator to retrieve
+ both the version names and dependencies in the form of
+ verdaux entries
+ """
+ for verdef, verdaux_iter in self.iter_versions():
+ if verdef['vd_ndx'] == index:
+ return verdef, verdaux_iter
+
+ return None
+
+ def _iter_version_auxiliaries(self, entry_offset, count):
+ """ Yield all auxiliary entries of a version definition
+ """
+ for _ in range(count):
+ entry = struct_parse(
+ self.elfstructs.Elf_Verdaux,
+ self.stream,
+ stream_pos=entry_offset)
+
+ name = self.stringtable.get_string(entry['vda_name'])
+ vernaux = VersionAuxiliary(entry, name)
+ yield vernaux
+
+ if not entry['vda_next']:
+ break
+
+ entry_offset += entry['vda_next']
+
+
+ def iter_versions(self):
+ """ Yield all the version definition entries in the table
+ Each time it returns the main version definition structure
+ and an iterator to walk through its auxiliaries entries
+ """
+ entry_offset = self['sh_offset']
+ for _ in range(self.num_versions()):
+ entry = struct_parse(
+ self.elfstructs.Elf_Verdef,
+ self.stream,
+ stream_pos=entry_offset)
+
+ elf_assert(entry['vd_cnt'] > 0,
+ 'Expected number of version names to be > 0'
+ 'for version definition at index %i' % entry['vd_ndx'])
+
+ verdef = Version(entry)
+ aux_entries_offset = entry_offset + entry['vd_aux']
+ verdaux_iter = self._iter_version_auxiliaries(aux_entries_offset,
+ entry['vd_cnt'])
+ yield verdef, verdaux_iter
+
+ if not entry['vd_next']:
+ break
+
+ entry_offset += entry['vd_next']
+
+
+class VersymTableSection(Section):
+ """ ELF SUNW or GNU Versym table section.
+ Has an associated SymbolTableSection that's passed in the constructor.
+ """
+ def __init__(self, header, name, stream, elffile, symboltable):
+ super(VersymTableSection, self).__init__(header, name, stream)
+ self.elffile = elffile
+ self.elfstructs = self.elffile.structs
+ self.symboltable = symboltable
+
+ def num_symbols(self):
+ """ Number of symbols in the table
+ """
+ return self['sh_size'] // self['sh_entsize']
+
+ def get_symbol(self, n):
+ """ Get the symbol at index #n from the table (Symbol object)
+ It begins at 1 and not 0 since the first entry is used to
+ store the current version of the syminfo table
+ """
+ # Grab the symbol's entry from the stream
+ entry_offset = self['sh_offset'] + n * self['sh_entsize']
+ entry = struct_parse(
+ self.elfstructs.Elf_Versym,
+ self.stream,
+ stream_pos=entry_offset)
+ # Find the symbol name in the associated symbol table
+ name = self.symboltable.get_symbol(n).name
+ return Symbol(entry, name)
+
+ def iter_symbols(self):
+ """ Yield all the symbols in the table
+ """
+ for i in range(self.num_symbols()):
+ yield self.get_symbol(i)
+
self._create_rel()
self._create_dyn()
self._create_sunw_syminfo()
+ self._create_version_needed()
+ self._create_version_definition()
+ self._create_version_symbol()
def _create_ehdr(self):
self.Elf_Ehdr = Struct('Elf_Ehdr',
Enum(self.Elf_half('si_boundto'), **ENUM_SUNW_SYMINFO_BOUNDTO),
self.Elf_half('si_flags'),
)
+
+ def _create_version_needed(self):
+ # Structure of "version needed" entries is documented in
+ # Oracle "Linker and Libraries Guide", Chapter 7 Object File Format
+ self.Elf_Verneed = Struct('Elf_Verneed',
+ self.Elf_half('vn_version'),
+ self.Elf_half('vn_cnt'),
+ self.Elf_word('vn_file'),
+ self.Elf_word('vn_aux'),
+ self.Elf_word('vn_next'),
+ )
+ self.Elf_Vernaux = Struct('Elf_Vernaux',
+ self.Elf_word('vna_hash'),
+ self.Elf_half('vna_flags'),
+ self.Elf_half('vna_other'),
+ self.Elf_word('vna_name'),
+ self.Elf_word('vna_next'),
+ )
+
+ def _create_version_definition(self):
+ # Structure off "version definition" entries are documented in
+ # Oracle "Linker and Libraries Guide", Chapter 7 Object File Format
+ self.Elf_Verdef = Struct('Elf_Verdef',
+ self.Elf_half('vd_version'),
+ self.Elf_half('vd_flags'),
+ self.Elf_half('vd_ndx'),
+ self.Elf_half('vd_cnt'),
+ self.Elf_word('vd_hash'),
+ self.Elf_word('vd_aux'),
+ self.Elf_word('vd_next'),
+ )
+ self.Elf_Verdaux = Struct('Elf_Verdaux',
+ self.Elf_word('vda_name'),
+ self.Elf_word('vda_next'),
+ )
+
+ def _create_version_symbol(self):
+ # Structure off "version symbol" entries are documented in
+ # Oracle "Linker and Libraries Guide", Chapter 7 Object File Format
+ self.Elf_Versym = Struct('Elf_Versym',
+ Enum(self.Elf_half('ndx'), **ENUM_VERSYM),
+ )
from elftools.elf.dynamic import DynamicSection, DynamicSegment
from elftools.elf.enums import ENUM_D_TAG
from elftools.elf.segments import InterpSegment
-from elftools.elf.sections import SymbolTableSection
+from elftools.elf.sections import (
+ SymbolTableSection, VersymTableSection,
+ VerdefTableSection, VerneedTableSection,
+ )
from elftools.elf.relocation import RelocationSection
from elftools.elf.descriptions import (
describe_ei_class, describe_ei_data, describe_ei_version,
describe_sh_type, describe_sh_flags,
describe_symbol_type, describe_symbol_bind, describe_symbol_visibility,
describe_symbol_shndx, describe_reloc_type, describe_dyn_tag,
+ describe_ver_flags,
)
from elftools.dwarf.dwarfinfo import DWARFInfo
from elftools.dwarf.descriptions import (
# Lazily initialized if a debug dump is requested
self._dwarfinfo = None
+ self._versioninfo = None
+
+
def display_file_header(self):
""" Display the ELF file header
"""
def display_symbol_tables(self):
""" Display the symbol tables contained in the file
"""
+ self._init_versioninfo()
+
for section in self.elffile.iter_sections():
if not isinstance(section, SymbolTableSection):
continue
bytes2str(section.name)))
continue
+
self._emitline("\nSymbol table '%s' contains %s entries:" % (
bytes2str(section.name), section.num_symbols()))
self._emitline(' Num: Value Size Type Bind Vis Ndx Name')
for nsym, symbol in enumerate(section.iter_symbols()):
+
+ version_info = ''
+ # readelf doesn't display version info for Solaris versioning
+ if (section['sh_type'] == 'SHT_DYNSYM' and
+ self._versioninfo['type'] == 'GNU'):
+ version = self._symbol_version(nsym)
+ if (version['name'] != bytes2str(symbol.name) and
+ version['index'] not in ('VER_NDX_LOCAL',
+ 'VER_NDX_GLOBAL')):
+ if version['filename']:
+ # external symbol
+ version_info = '@%(name)s (%(index)i)' % version
+ else:
+ # internal symbol
+ if version['hidden']:
+ version_info = '@%(name)s' % version
+ else:
+ version_info = '@@%(name)s' % version
+
# symbol names are truncated to 25 chars, similarly to readelf
- self._emitline('%6d: %s %5d %-7s %-6s %-7s %4s %.25s' % (
+ self._emitline('%6d: %s %5d %-7s %-6s %-7s %4s %.25s%s' % (
nsym,
self._format_hex(symbol['st_value'], fullhex=True, lead0x=False),
symbol['st_size'],
describe_symbol_bind(symbol['st_info']['bind']),
describe_symbol_visibility(symbol['st_other']['visibility']),
describe_symbol_shndx(symbol['st_shndx']),
- bytes2str(symbol.name)))
+ bytes2str(symbol.name),
+ version_info))
def display_dynamic_tags(self):
""" Display the dynamic tags contained in the file
if not has_relocation_sections:
self._emitline('\nThere are no relocations in this file.')
+ def display_version_info(self):
+ """ Display the version info contained in the file
+ """
+ self._init_versioninfo()
+
+ if not self._versioninfo['type']:
+ self._emitline("\nNo version information found in this file.")
+ return
+
+ for section in self.elffile.iter_sections():
+ if isinstance(section, VersymTableSection):
+
+ self._print_version_section_header(
+ section, 'Version symbols', lead0x=False)
+
+ num_symbols = section.num_symbols()
+
+ # Symbol version info are printed four by four entries
+ for idx_by_4 in range(0, num_symbols, 4):
+
+ self._emit(' %03x:' % idx_by_4)
+
+ for idx in range(idx_by_4, min(idx_by_4 + 4, num_symbols)):
+
+ symbol_version = self._symbol_version(idx)
+ if symbol_version['index'] == 'VER_NDX_LOCAL':
+ version_index = 0
+ version_name = '(*local*)'
+ elif symbol_version['index'] == 'VER_NDX_GLOBAL':
+ version_index = 1
+ version_name = '(*global*)'
+ else:
+ version_index = symbol_version['index']
+ version_name = '(%(name)s)' % symbol_version
+
+ visibility = 'h' if symbol_version['hidden'] else ' '
+
+ self._emit('%4x%s%-13s' % (
+ version_index, visibility, version_name))
+
+ self._emitline()
+
+ elif isinstance(section, VerdefTableSection):
+
+ self._print_version_section_header(
+ section, 'Version definition', indent=2)
+
+ offset = 0
+ for verdef, verdaux_iter in section.iter_versions():
+ verdaux = next(verdaux_iter)
+
+ name = verdaux.name
+ if verdef['vd_flags']:
+ flags = describe_ver_flags(verdef['vd_flags'])
+ # Mimic exactly the readelf output
+ flags += ' '
+ else:
+ flags = 'none'
+
+ self._emitline(' %s: Rev: %i Flags: %s Index: %i'
+ ' Cnt: %i Name: %s' % (
+ self._format_hex(offset, fieldsize=6,
+ alternate=True),
+ verdef['vd_version'], flags, verdef['vd_ndx'],
+ verdef['vd_cnt'], bytes2str(name)))
+
+ verdaux_offset = (
+ offset + verdef['vd_aux'] + verdaux['vda_next'])
+ for idx, verdaux in enumerate(verdaux_iter, start=1):
+ self._emitline(' %s: Parent %i: %s' %
+ (self._format_hex(verdaux_offset, fieldsize=4),
+ idx, bytes2str(verdaux.name)))
+ verdaux_offset += verdaux['vda_next']
+
+ offset += verdef['vd_next']
+
+ elif isinstance(section, VerneedTableSection):
+
+ self._print_version_section_header(section, 'Version needs')
+
+ offset = 0
+ for verneed, verneed_iter in section.iter_versions():
+
+ self._emitline(' %s: Version: %i File: %s Cnt: %i' % (
+ self._format_hex(offset, fieldsize=6,
+ alternate=True),
+ verneed['vn_version'], bytes2str(verneed.name),
+ verneed['vn_cnt']))
+
+ vernaux_offset = offset + verneed['vn_aux']
+ for idx, vernaux in enumerate(verneed_iter, start=1):
+ if vernaux['vna_flags']:
+ flags = describe_ver_flags(vernaux['vna_flags'])
+ # Mimic exactly the readelf output
+ flags += ' '
+ else:
+ flags = 'none'
+
+ self._emitline(
+ ' %s: Name: %s Flags: %s Version: %i' % (
+ self._format_hex(vernaux_offset, fieldsize=4),
+ bytes2str(vernaux.name), flags,
+ vernaux['vna_other']))
+
+ vernaux_offset += vernaux['vna_next']
+
+ offset += verneed['vn_next']
+
def display_hex_dump(self, section_spec):
""" Display a hex dump of a section. section_spec is either a section
number or a name.
else:
self._emitline('debug dump not yet supported for "%s"' % dump_what)
- def _format_hex(self, addr, fieldsize=None, fullhex=False, lead0x=True):
+ def _format_hex(self, addr, fieldsize=None, fullhex=False, lead0x=True,
+ alternate=False):
""" Format an address into a hexadecimal string.
fieldsize:
lead0x:
If True, leading 0x is added
+
+ alternate:
+ If True, override lead0x to emulate the alternate
+ hexadecimal form specified in format string with the #
+ character: only non-zero values are prefixed with 0x.
+ This form is used by readelf.
"""
+ if alternate:
+ if addr == 0:
+ lead0x = False
+ else:
+ lead0x = True
+ fieldsize -= 2
+
s = '0x' if lead0x else ''
if fullhex:
fieldsize = 8 if self.elffile.elfclass == 32 else 16
field = '%' + '0%sx' % fieldsize
return s + field % addr
+
+ def _print_version_section_header(self, version_section, name, lead0x=True, indent=1):
+ """ Print a section header of one version related section (versym, verneed or verdef)
+ with some options to accomodate readelf little differences between each header
+ (e.g. indentation and 0x prefixing).
+ """
+ if hasattr(version_section, 'num_versions'):
+ num_entries = version_section.num_versions()
+ else:
+ num_entries = version_section.num_symbols()
+
+ self._emitline("\n%s section '%s' contains %s entries:" %
+ (name, bytes2str(version_section.name), num_entries))
+ self._emitline('%sAddr: %s Offset: %s Link: %i (%s)' %
+ (' ' * indent,
+ self._format_hex(version_section['sh_addr'], fieldsize=16, lead0x=lead0x),
+ self._format_hex(version_section['sh_offset'], fieldsize=6, lead0x=True),
+ version_section['sh_link'],
+ bytes2str(self.elffile.get_section(version_section['sh_link']).name)))
+
+
+
+ def _init_versioninfo(self):
+ """ Search and initialize informations about version related sections
+ and the kind of versioning used (GNU or Solaris).
+ """
+ if self._versioninfo is not None:
+ return
+
+ self._versioninfo = { 'versym': None, 'verdef': None,
+ 'verneed': None, 'type': None }
+
+ for section in self.elffile.iter_sections():
+ if isinstance(section, VersymTableSection):
+ self._versioninfo['versym'] = section
+ elif isinstance(section, VerdefTableSection):
+ self._versioninfo['verdef'] = section
+ elif isinstance(section, VerneedTableSection):
+ self._versioninfo['verneed'] = section
+ elif isinstance(section, DynamicSection):
+ for tag in section.iter_tags():
+ if tag['d_tag'] == 'DT_VERSYM':
+ self._versioninfo['type'] = 'GNU'
+ break
+
+ if not self._versioninfo['type'] and (
+ self._versioninfo['verneed'] or self._versioninfo['verdef']):
+ self._versioninfo['type'] = 'Solaris'
+
+
+ def _symbol_version(self, nsym):
+ """ Return a dict containing information on the
+ or None if no version information is available
+ """
+ self._init_versioninfo()
+
+ symbol_version = dict.fromkeys(('index', 'name', 'filename', 'hidden'))
+
+ if (not self._versioninfo['versym'] or
+ nsym >= self._versioninfo['versym'].num_symbols()):
+ return None
+
+ symbol = self._versioninfo['versym'].get_symbol(nsym)
+ index = symbol.entry['ndx']
+ if not index in ('VER_NDX_LOCAL', 'VER_NDX_GLOBAL'):
+ index = int(index)
+
+ if self._versioninfo['type'] == 'GNU':
+ # In GNU versioning mode, the highest bit is used to
+ # store wether the symbol is hidden or not
+ if index & 0x8000:
+ index &= ~0x8000;
+ symbol_version['hidden'] = True
+
+ if (self._versioninfo['verdef'] and
+ index <= self._versioninfo['verdef'].num_versions()):
+ _, verdaux_iter = \
+ self._versioninfo['verdef'].get_version(index)
+ symbol_version['name'] = bytes2str(next(verdaux_iter).name)
+ else:
+ verneed, vernaux = \
+ self._versioninfo['verneed'].get_version(index)
+ symbol_version['name'] = bytes2str(vernaux.name)
+ symbol_version['filename'] = bytes2str(verneed.name)
+
+ symbol_version['index'] = index
+ return symbol_version
+
+
def _section_from_spec(self, spec):
""" Retrieve a section given a "spec" (either number or name).
Return None if no such section exists in the file.
optparser.add_option('-p', '--string-dump',
action='store', dest='show_string_dump', metavar='<number|name>',
help='Dump the contents of section <number|name> as strings')
+ optparser.add_option('-V', '--version-info',
+ action='store_true', dest='show_version_info',
+ help='Display the version sections (if present)')
optparser.add_option('--debug-dump',
action='store', dest='debug_dump_what', metavar='<what>',
help=(
readelf.display_symbol_tables()
if options.show_relocs:
readelf.display_relocations()
+ if options.show_version_info:
+ readelf.display_version_info()
if options.show_hex_dump:
readelf.display_hex_dump(options.show_hex_dump)
if options.show_string_dump:
for option in [
'-e', '-d', '-s', '-r', '-x.text', '-p.shstrtab',
'--debug-dump=info', '--debug-dump=decodedline',
- '--debug-dump=frames', '--debug-dump=frames-interp']:
+ '--debug-dump=frames', '--debug-dump=frames-interp',
+ '-V']:
if verbose: testlog.info("..option='%s'" % option)
# stdouts will be a 2-element list: output of readelf and output
# of scripts/readelf.py