simpler check for syminfo entries that are not displayed by elfdump
[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 if not (syminfo['si_flags'] or syminfo['si_boundto']):
92 continue
93
94 index = ''
95 if syminfo['si_flags'] & SYMINFO_FLAGS.SYMINFO_FLG_CAP:
96 boundto = '<symbol capabilities>'
97 elif syminfo['si_boundto'] == 0xffff:
98 boundto = '<self>'
99 elif syminfo['si_boundto'] == 0xfffe:
100 boundto = '<parent>'
101 elif syminfo['si_boundto'] == 0xfffd:
102 boundto = ''
103 else:
104 dyn_tag = dyntable.get_tag(syminfo['si_boundto'])
105 boundto = bytes2str(dyn_tag.needed)
106 index = '[%d]' % syminfo['si_boundto']
107
108 # syminfo names are truncated to 25 chars, similarly to readelf
109 self._emitline('%10s %-5s %10s %-24s %s' % (
110 '[%d]' % (int(nsym)),
111 describe_syminfo_flags(syminfo['si_flags']),
112 index,
113 boundto,
114 bytes2str(syminfo.name)))
115
116 def _emit(self, s=''):
117 """ Emit an object to output
118 """
119 self.output.write(str(s))
120
121 def _emitline(self, s=''):
122 """ Emit an object to output, followed by a newline
123 """
124 self.output.write(str(s) + '\n')
125
126
127 SCRIPT_DESCRIPTION = 'Dumps selected parts of an object file'
128 VERSION_STRING = '%%prog: based on pyelftools %s' % __version__
129
130
131 def main(stream=None):
132 # parse the command-line arguments and invoke ReadElf
133 optparser = OptionParser(
134 usage='usage: %prog [options] <elf-file>',
135 description=SCRIPT_DESCRIPTION,
136 add_help_option=False, # -h is a real option of readelf
137 prog='elfdump.py',
138 version=VERSION_STRING)
139 optparser.add_option('--help',
140 action='store_true', dest='help',
141 help='Display this information')
142 optparser.add_option('-y',
143 action='store_true', dest='show_syminfo',
144 help='dump the contents of the .SUNW_syminfo section')
145
146 options, args = optparser.parse_args()
147
148 if options.help or len(args) == 0:
149 optparser.print_help()
150 sys.exit(0)
151
152 with open(args[0], 'rb') as file:
153 try:
154 readelf = Elfdump(file, stream or sys.stdout)
155 if options.show_syminfo:
156 readelf.display_syminfo_table()
157 except ELFError as ex:
158 sys.stderr.write('ELF error: %s\n' % ex)
159 sys.exit(1)
160
161
162 def profile_main():
163 # Run 'main' redirecting its output to readelfout.txt
164 # Saves profiling information in readelf.profile
165 PROFFILE = 'elfdump.profile'
166 import cProfile
167 cProfile.run('main(open("elfdumpout.txt", "w"))', PROFFILE)
168
169 # Dig in some profiling stats
170 import pstats
171 p = pstats.Stats(PROFFILE)
172 p.sort_stats('cumulative').print_stats(25)
173
174
175 #-------------------------------------------------------------------------------
176 if __name__ == '__main__':
177 main()
178 #profile_main()