+++ /dev/null
-#!/opt/csw/bin/python
-#-------------------------------------------------------------------------------
-# scripts/elfdump.py
-#
-# A clone of 'elfdump' in Python, based on the pyelftools library
-#
-# Eli Bendersky (eliben@gmail.com)
-# Yann Rouillard (yann@pleiades.fr.eu.org)
-# This code is in the public domain
-#-------------------------------------------------------------------------------
-import os, sys
-from optparse import OptionParser
-import string
-
-# For running from development directory. It should take precedence over the
-# installed pyelftools.
-sys.path.insert(0, '.')
-
-
-from elftools import __version__
-from elftools.common.exceptions import ELFError
-from elftools.common.py3compat import (
- ifilter, byte2int, bytes2str, itervalues, str2bytes)
-from elftools.elf.elffile import ELFFile
-from elftools.elf.dynamic import DynamicSection, DynamicSegment
-from elftools.elf.enums import ENUM_D_TAG
-from elftools.elf.constants import SYMINFO_FLAGS
-from elftools.elf.segments import InterpSegment
-from elftools.elf.sections import SUNWSyminfoTableSection
-from elftools.elf.relocation import RelocationSection
-from elftools.elf.descriptions import (
- describe_ei_class, describe_ei_data, describe_ei_version,
- describe_ei_osabi, describe_e_type, describe_e_machine,
- describe_e_version_numeric, describe_p_type, describe_p_flags,
- 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_syminfo_flags, describe_symbol_boundto,
- )
-from elftools.dwarf.dwarfinfo import DWARFInfo
-from elftools.dwarf.descriptions import (
- describe_reg_name, describe_attr_value, set_global_machine_arch,
- describe_CFI_instructions, describe_CFI_register_rule,
- describe_CFI_CFA_rule,
- )
-from elftools.dwarf.constants import (
- DW_LNS_copy, DW_LNS_set_file, DW_LNE_define_file)
-from elftools.dwarf.callframe import CIE, FDE
-
-
-class Elfdump(object):
- """ display_* methods are used to emit output into the output stream
- """
- def __init__(self, file, output):
- """ file:
- stream object with the ELF file to read
-
- output:
- output stream to write to
- """
- self.elffile = ELFFile(file)
- self.output = output
-
- def display_syminfo_table(self):
- """ Display the SUNW syminfo tables contained in the file
- """
- syminfo_section = None
- for section in self.elffile.iter_sections():
- if isinstance(section, SUNWSyminfoTableSection):
- syminfo_section = section
- break
-
- if syminfo_section:
- # We need to dyntable to do get the soname names
- dyntable = self.elffile.get_section_by_name('.dynamic')
-
- if section['sh_entsize'] == 0:
- self._emitline("\nSymbol table '%s' has a sh_entsize of zero!"
- % (bytes2str(section.name)))
- return
-
- # The symbol table section pointed to in sh_link
- symtable = self.elffile.get_section(section['sh_link'])
-
- self._emitline("\nSyminfo Section: %s" % bytes2str(section.name))
- self._emitline('%10s %-5s %10s %-24s %s'
- % ('index', 'flags', '', 'bound to', 'symbol'))
-
- for nsym, syminfo in enumerate(section.iter_symbols(), start=1):
-
- # elfdump doesn't display anything for this kind of symbols
- if not (syminfo['si_flags'] or syminfo['si_boundto']):
- continue
-
- index = ''
- if syminfo['si_flags'] & SYMINFO_FLAGS.SYMINFO_FLG_CAP:
- boundto = '<symbol capabilities>'
- elif not isinstance(syminfo['si_boundto'], int):
- boundto = describe_symbol_boundto(syminfo['si_boundto'])
- else:
- dyn_tag = dyntable.get_tag(syminfo['si_boundto'])
- if syminfo['si_flags'] & SYMINFO_FLAGS.SYMINFO_FLG_FILTER:
- boundto = bytes2str(dyn_tag.sunw_filter)
- else:
- boundto = bytes2str(dyn_tag.needed)
- index = '[%d]' % syminfo['si_boundto']
-
- # syminfo names are truncated to 24 chars, similarly to elfdump
- self._emitline('%10s %-5s %10s %-24s %s' % (
- '[%d]' % (int(nsym)),
- describe_syminfo_flags(syminfo['si_flags']),
- index,
- boundto,
- bytes2str(syminfo.name)))
-
- def _emit(self, s=''):
- """ Emit an object to output
- """
- self.output.write(str(s))
-
- def _emitline(self, s=''):
- """ Emit an object to output, followed by a newline
- """
- self.output.write(str(s) + '\n')
-
-
-SCRIPT_DESCRIPTION = 'Dumps selected parts of an object file'
-VERSION_STRING = '%%prog: based on pyelftools %s' % __version__
-
-
-def main(stream=None):
- # parse the command-line arguments and invoke ReadElf
- optparser = OptionParser(
- usage='usage: %prog [options] <elf-file>',
- description=SCRIPT_DESCRIPTION,
- add_help_option=False, # -h is a real option of readelf
- prog='elfdump.py',
- version=VERSION_STRING)
- optparser.add_option('--help',
- action='store_true', dest='help',
- help='Display this information')
- optparser.add_option('-y',
- action='store_true', dest='show_syminfo',
- help='dump the contents of the .SUNW_syminfo section')
-
- options, args = optparser.parse_args()
-
- if options.help or len(args) == 0:
- optparser.print_help()
- sys.exit(0)
-
- with open(args[0], 'rb') as file:
- try:
- readelf = Elfdump(file, stream or sys.stdout)
- if options.show_syminfo:
- readelf.display_syminfo_table()
- except ELFError as ex:
- sys.stderr.write('ELF error: %s\n' % ex)
- sys.exit(1)
-
-
-def profile_main():
- # Run 'main' redirecting its output to readelfout.txt
- # Saves profiling information in readelf.profile
- PROFFILE = 'elfdump.profile'
- import cProfile
- cProfile.run('main(open("elfdumpout.txt", "w"))', PROFFILE)
-
- # Dig in some profiling stats
- import pstats
- p = pstats.Stats(PROFFILE)
- p.sort_stats('cumulative').print_stats(25)
-
-
-#-------------------------------------------------------------------------------
-if __name__ == '__main__':
- main()
- #profile_main()
+++ /dev/null
-#!/usr/bin/env python
-#-------------------------------------------------------------------------------
-# test/run_elfdump_tests.py
-#
-# Automatic test runner for elftools & elfdump
-#
-# Eli Bendersky (eliben@gmail.com)
-# Yann Rouillard (yann@pleiades.fr.eu.org)
-# This code is in the public domain
-#-------------------------------------------------------------------------------
-import os, sys
-import re
-from difflib import SequenceMatcher
-from optparse import OptionParser
-import logging
-import platform
-from utils import setup_syspath; setup_syspath()
-from utils import run_exe, is_in_rootdir, dump_output_to_temp_files
-
-
-# Create a global logger object
-#
-testlog = logging.getLogger('run_tests')
-testlog.setLevel(logging.DEBUG)
-testlog.addHandler(logging.StreamHandler(sys.stdout))
-
-ELFDUMP_PATH = '/usr/ccs/bin/elfdump'
-
-def discover_testfiles(rootdir):
- """ Discover test files in the given directory. Yield them one by one.
- """
- for filename in os.listdir(rootdir):
- name, ext = os.path.splitext(filename)
- if ext == '.elf' and 'solaris' in name:
- yield os.path.join(rootdir, filename)
-
-
-def run_test_on_file(filename, verbose=False):
- """ Runs a test on the given input filename. Return True if all test
- runs succeeded.
- """
- success = True
- testlog.info("Test file '%s'" % filename)
- for option in [
- '-y']:
- if verbose: testlog.info("..option='%s'" % option)
- # stdouts will be a 2-element list: output of elfdump and output
- # of scripts/elfdump.py
- stdouts = []
- for exe_path in [ELFDUMP_PATH, 'scripts/elfdump.py']:
- args = [option, filename]
- if verbose: testlog.info("....executing: '%s %s'" % (
- exe_path, ' '.join(args)))
- rc, stdout = run_exe(exe_path, args)
- if rc != 0:
- testlog.error("@@ aborting - '%s' returned '%s'" % (exe_path, rc))
- return False
- stdouts.append(stdout)
- if verbose: testlog.info('....comparing output...')
- rc, errmsg = compare_output(*stdouts)
- if rc:
- if verbose: testlog.info('.......................SUCCESS')
- else:
- success = False
- testlog.info('.......................FAIL')
- testlog.info('....for option "%s"' % option)
- testlog.info('....Output #1 is elfdump, Output #2 is pyelftools')
- testlog.info('@@ ' + errmsg)
- dump_output_to_temp_files(testlog, *stdouts)
- return success
-
-
-def compare_output(s1, s2):
- """ Compare stdout strings s1 and s2.
- s1 is from elfdump, s2 from elftools elfdump.py
- Return pair success, errmsg. If comparison succeeds, success is True
- and errmsg is empty. Otherwise success is False and errmsg holds a
- description of the mismatch.
-
- Note: this function contains some rather horrible hacks to ignore
- differences which are not important for the verification of pyelftools.
- This is due to some intricacies of binutils's elfdump which pyelftools
- doesn't currently implement, or silly inconsistencies in the output of
- elfdump, which I was reluctant to replicate.
- Read the documentation for more details.
- """
- def prepare_lines(s):
- return [line for line in s.lower().splitlines() if line.strip() != '']
- def filter_elfdump_lines(lines):
- filter_out = False
- for line in lines:
- if not filter_out:
- yield line
-
- lines1 = prepare_lines(s1)
- lines2 = prepare_lines(s2)
-
- lines1 = list(filter_elfdump_lines(lines1))
-
- flag_after_symtable = False
-
- if len(lines1) != len(lines2):
- return False, 'Number of lines different: %s vs %s' % (
- len(lines1), len(lines2))
-
- for i in range(len(lines1)):
- if 'symbol table' in lines1[i]:
- flag_after_symtable = True
-
- # Compare ignoring whitespace
- lines1_parts = lines1[i].split()
- lines2_parts = lines2[i].split()
- if ''.join(lines1_parts) != ''.join(lines2_parts):
- ok = False
- if not ok:
- errmsg = 'Mismatch on line #%s:\n>>%s<<\n>>%s<<\n' % (
- i, lines1[i], lines2[i])
- return False, errmsg
- return True, ''
-
-
-def main():
- if not is_in_rootdir():
- testlog.error('Error: Please run me from the root dir of pyelftools!')
- return 1
-
- optparser = OptionParser(
- usage='usage: %prog [options] [file] [file] ...',
- prog='run_elfdump_tests.py')
- optparser.add_option('-V', '--verbose',
- action='store_true', dest='verbose',
- help='Verbose output')
- options, args = optparser.parse_args()
-
- if options.verbose:
- testlog.info('Running in verbose mode')
- testlog.info('Python executable = %s' % sys.executable)
- testlog.info('elfdump path = %s' % READELF_PATH)
- testlog.info('Given list of files: %s' % args)
-
- # If file names are given as command-line arguments, only these files
- # are taken as inputs. Otherwise, autodiscovery is performed.
- #
- if len(args) > 0:
- filenames = args
- else:
- filenames = list(discover_testfiles('test/testfiles'))
-
- success = True
- for filename in filenames:
- if success:
- success = success and run_test_on_file(
- filename,
- verbose=options.verbose)
-
- if success:
- testlog.info('\nConclusion: SUCCESS')
- return 0
- else:
- testlog.info('\nConclusion: FAIL')
- return 1
-
-
-if __name__ == '__main__':
- sys.exit(main())
-