some pep8 compliance fixes
[pyelftools.git] / scripts / elfdump.py
1 #!/opt/csw/bin/python
2 #-------------------------------------------------------------------------------
3 # scripts/elfdump.py
4 #
5 # A clone of 'elfdump' in Python, based on the pyelftools library
6 #
7 # Eli Bendersky (eliben@gmail.com)
8 # Yann Rouillard (yann@pleiades.fr.eu.org)
9 # This code is in the public domain
10 #-------------------------------------------------------------------------------
11 import os, sys
12 from optparse import OptionParser
13 import string
14
15 # For running from development directory. It should take precedence over the
16 # installed pyelftools.
17 sys.path.insert(0, '.')
18
19
20 from elftools import __version__
21 from elftools.common.exceptions import ELFError
22 from elftools.common.py3compat import (
23 ifilter, byte2int, bytes2str, itervalues, str2bytes)
24 from elftools.elf.elffile import ELFFile
25 from elftools.elf.dynamic import DynamicSection, DynamicSegment
26 from elftools.elf.enums import ENUM_D_TAG
27 from elftools.elf.constants import SYMINFO_FLAGS
28 from elftools.elf.segments import InterpSegment
29 from elftools.elf.sections import SUNWSyminfoTableSection
30 from elftools.elf.relocation import RelocationSection
31 from elftools.elf.descriptions import (
32 describe_ei_class, describe_ei_data, describe_ei_version,
33 describe_ei_osabi, describe_e_type, describe_e_machine,
34 describe_e_version_numeric, describe_p_type, describe_p_flags,
35 describe_sh_type, describe_sh_flags,
36 describe_symbol_type, describe_symbol_bind, describe_symbol_visibility,
37 describe_symbol_shndx, describe_reloc_type, describe_dyn_tag,
38 describe_syminfo_flags,
39 )
40 from elftools.dwarf.dwarfinfo import DWARFInfo
41 from elftools.dwarf.descriptions import (
42 describe_reg_name, describe_attr_value, set_global_machine_arch,
43 describe_CFI_instructions, describe_CFI_register_rule,
44 describe_CFI_CFA_rule,
45 )
46 from elftools.dwarf.constants import (
47 DW_LNS_copy, DW_LNS_set_file, DW_LNE_define_file)
48 from elftools.dwarf.callframe import CIE, FDE
49
50
51 class Elfdump(object):
52 """ display_* methods are used to emit output into the output stream
53 """
54 def __init__(self, file, output):
55 """ file:
56 stream object with the ELF file to read
57
58 output:
59 output stream to write to
60 """
61 self.elffile = ELFFile(file)
62 self.output = output
63
64 def display_syminfo_table(self):
65 """ Display the SUNW syminfo tables contained in the file
66 """
67 for section in self.elffile.iter_sections():
68 if isinstance(section, SUNWSyminfoTableSection):
69 syminfo_section = section
70 break
71
72 if syminfo_section:
73 # We need to dyntable to do get the soname names
74 dyntable = self.elffile.get_section_by_name('.dynamic')
75
76 if section['sh_entsize'] == 0:
77 self._emitline("\nSymbol table '%s' has a sh_entsize of zero!"
78 % (bytes2str(section.name)))
79 return
80
81 # The symbol table section pointed to in sh_link
82 symtable = self.elffile.get_section(section['sh_link'])
83
84 self._emitline("\nSyminfo Section: %s" % bytes2str(section.name))
85 self._emitline('%10s %-5s %10s %-24s %s'
86 % ('index', 'flags', '', 'bound to', 'symbol'))
87
88 for nsym, syminfo in enumerate(section.iter_symbols(), start=1):
89
90 # elfdump doesn't display anything for this kind of symbols
91 symbol = symtable.get_symbol(nsym)
92 if (symbol['st_info']['type'] == 'STT_NOTYPE' and
93 symbol['st_shndx'] == 'SHN_UNDEF'):
94 continue
95
96 index = ''
97 if syminfo['si_flags'] & SYMINFO_FLAGS.SYMINFO_FLG_CAP:
98 boundto = '<symbol capabilities>'
99 elif syminfo['si_boundto'] == 0xffff:
100 boundto = '<self>'
101 elif syminfo['si_boundto'] == 0xfffe:
102 boundto = '<parent>'
103 elif syminfo['si_boundto'] == 0xfffd:
104 boundto = ''
105 else:
106 dyn_tag = dyntable.get_tag(syminfo['si_boundto'])
107 boundto = bytes2str(dyn_tag.needed)
108 index = '[%d]' % syminfo['si_boundto']
109
110 # syminfo names are truncated to 25 chars, similarly to readelf
111 self._emitline('%10s %-5s %10s %-24s %s' % (
112 '[%d]' % (int(nsym)),
113 describe_syminfo_flags(syminfo['si_flags']),
114 index,
115 boundto,
116 bytes2str(syminfo.name)))
117
118 def _emit(self, s=''):
119 """ Emit an object to output
120 """
121 self.output.write(str(s))
122
123 def _emitline(self, s=''):
124 """ Emit an object to output, followed by a newline
125 """
126 self.output.write(str(s) + '\n')
127
128
129 SCRIPT_DESCRIPTION = 'Dumps selected parts of an object file'
130 VERSION_STRING = '%%prog: based on pyelftools %s' % __version__
131
132
133 def main(stream=None):
134 # parse the command-line arguments and invoke ReadElf
135 optparser = OptionParser(
136 usage='usage: %prog [options] <elf-file>',
137 description=SCRIPT_DESCRIPTION,
138 add_help_option=False, # -h is a real option of readelf
139 prog='elfdump.py',
140 version=VERSION_STRING)
141 optparser.add_option('--help',
142 action='store_true', dest='help',
143 help='Display this information')
144 optparser.add_option('-y',
145 action='store_true', dest='show_syminfo',
146 help='dump the contents of the .SUNW_syminfo section')
147
148 options, args = optparser.parse_args()
149
150 if options.help or len(args) == 0:
151 optparser.print_help()
152 sys.exit(0)
153
154 with open(args[0], 'rb') as file:
155 try:
156 readelf = Elfdump(file, stream or sys.stdout)
157 if options.show_syminfo:
158 readelf.display_syminfo_table()
159 except ELFError as ex:
160 sys.stderr.write('ELF error: %s\n' % ex)
161 sys.exit(1)
162
163
164 def profile_main():
165 # Run 'main' redirecting its output to readelfout.txt
166 # Saves profiling information in readelf.profile
167 PROFFILE = 'elfdump.profile'
168 import cProfile
169 cProfile.run('main(open("elfdumpout.txt", "w"))', PROFFILE)
170
171 # Dig in some profiling stats
172 import pstats
173 p = pstats.Stats(PROFFILE)
174 p.sort_stats('cumulative').print_stats(25)
175
176
177 #-------------------------------------------------------------------------------
178 if __name__ == '__main__':
179 main()
180 #profile_main()