blob: 7b3cc963ad64ea4f575c0ec01e5430d1ad6fa328 [file] [log] [blame]
Eli Bendersky3edefab2011-09-16 14:52:54 +03001#!/usr/bin/env python
Eli Bendersky933f6992011-09-09 08:11:06 +03002#-------------------------------------------------------------------------------
3# readelf.py
4#
5# A clone of 'readelf' in Python, based on the pyelftools library
6#
7# Eli Bendersky (eliben@gmail.com)
8# This code is in the public domain
9#-------------------------------------------------------------------------------
10import sys
11from optparse import OptionParser
12
13# If elftools is not installed, maybe we're running from the root or scripts
14# dir of the source distribution
15#
16try:
17 import elftools
18except ImportError:
19 sys.path.extend(['.', '..'])
20
Eli Bendersky0b27ba42011-09-17 06:44:02 +030021from elftools import __version__
Eli Bendersky933f6992011-09-09 08:11:06 +030022from elftools.common.exceptions import ELFError
23from elftools.elf.elffile import ELFFile
Eli Bendersky3f4de3e2011-09-14 05:58:06 +030024from elftools.elf.segments import InterpSegment
Eli Bendersky3edefab2011-09-16 14:52:54 +030025from elftools.elf.sections import SymbolTableSection
Eli Bendersky933f6992011-09-09 08:11:06 +030026from elftools.elf.descriptions import (
27 describe_ei_class, describe_ei_data, describe_ei_version,
Eli Benderskyde8d71e2011-09-09 08:22:35 +030028 describe_ei_osabi, describe_e_type, describe_e_machine,
Eli Bendersky26de2ac2011-09-13 06:50:28 +030029 describe_e_version_numeric, describe_p_type, describe_p_flags,
Eli Bendersky377bd862011-09-16 11:10:44 +030030 describe_sh_type, describe_sh_flags,
Eli Bendersky3edefab2011-09-16 14:52:54 +030031 describe_symbol_type, describe_symbol_bind, describe_symbol_visibility,
32 describe_symbol_shndx,
Eli Bendersky933f6992011-09-09 08:11:06 +030033 )
34
35
36class ReadElf(object):
37 """ display_* methods are used to emit output into the output stream
38 """
39 def __init__(self, file, output):
40 """ file:
41 stream object with the ELF file to read
42
43 output:
44 output stream to write to
45 """
46 self.elffile = ELFFile(file)
47 self.output = output
48
49 def display_file_header(self):
50 """ Display the ELF file header
51 """
52 self._emitline('ELF Header:')
53 self._emit(' Magic: ')
54 self._emitline(' '.join('%2.2x' % ord(b)
55 for b in self.elffile.e_ident_raw))
56 header = self.elffile.header
57 e_ident = header['e_ident']
58 self._emitline(' Class: %s' %
59 describe_ei_class(e_ident['EI_CLASS']))
60 self._emitline(' Data: %s' %
61 describe_ei_data(e_ident['EI_DATA']))
62 self._emitline(' Version: %s' %
63 describe_ei_version(e_ident['EI_VERSION']))
64 self._emitline(' OS/ABI: %s' %
65 describe_ei_osabi(e_ident['EI_OSABI']))
66 self._emitline(' ABI Version: %d' %
67 e_ident['EI_ABIVERSION'])
68 self._emitline(' Type: %s' %
69 describe_e_type(header['e_type']))
Eli Benderskyde8d71e2011-09-09 08:22:35 +030070 self._emitline(' Machine: %s' %
71 describe_e_machine(header['e_machine']))
72 self._emitline(' Version: %s' %
73 describe_e_version_numeric(header['e_version']))
Eli Benderskyd62928d2011-09-09 10:05:57 +030074 self._emitline(' Entry point address: %s' %
Eli Bendersky26de2ac2011-09-13 06:50:28 +030075 self._format_hex(header['e_entry']))
Eli Benderskyd62928d2011-09-09 10:05:57 +030076 self._emit(' Start of program headers %s' %
77 header['e_phoff'])
78 self._emitline(' (bytes into file)')
79 self._emit(' Start of section headers %s' %
80 header['e_shoff'])
81 self._emitline(' (bytes into file)')
82 self._emitline(' Flags: %s' %
Eli Bendersky26de2ac2011-09-13 06:50:28 +030083 self._format_hex(header['e_flags']))
Eli Benderskyd62928d2011-09-09 10:05:57 +030084 self._emitline(' Size of this header: %s (bytes)' %
85 header['e_ehsize'])
86 self._emitline(' Size of program headers: %s (bytes)' %
87 header['e_phentsize'])
88 self._emitline(' Number of program headers: %s' %
89 header['e_phnum'])
90 self._emitline(' Size of section headers: %s (bytes)' %
91 header['e_shentsize'])
92 self._emitline(' Number of section headers: %s' %
93 header['e_shnum'])
94 self._emitline(' Section header string table index: %s' %
95 header['e_shstrndx'])
Eli Bendersky933f6992011-09-09 08:11:06 +030096
Eli Bendersky0b27ba42011-09-17 06:44:02 +030097 def display_program_headers(self, show_heading=True):
98 """ Display the ELF program headers.
99 If show_heading is True, displays the heading for this information
100 (Elf file type is...)
Eli Bendersky26de2ac2011-09-13 06:50:28 +0300101 """
102 self._emitline()
103 elfheader = self.elffile.header
Eli Bendersky0b27ba42011-09-17 06:44:02 +0300104 if show_heading:
105 self._emitline('Elf file type is %s' %
106 describe_e_type(elfheader['e_type']))
107 self._emitline('Entry point is %s' %
108 self._format_hex(elfheader['e_entry']))
109 # readelf weirness - why isn't e_phoff printed as hex? (for section
110 # headers, it is...)
111 self._emitline('There are %s program headers, starting at offset %s' % (
112 elfheader['e_phnum'], elfheader['e_phoff']))
113 self._emitline()
Eli Bendersky26de2ac2011-09-13 06:50:28 +0300114
Eli Bendersky0b27ba42011-09-17 06:44:02 +0300115 self._emitline('Program headers:')
Eli Bendersky26de2ac2011-09-13 06:50:28 +0300116
117 # Now comes the table of program headers with their attributes. Note
118 # that due to different formatting constraints of 32-bit and 64-bit
119 # addresses, there are some conditions on elfclass here.
120 #
121 # First comes the table heading
122 #
123 if self.elffile.elfclass == 32:
124 self._emitline(' Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align')
125 else:
126 self._emitline(' Type Offset VirtAddr PhysAddr')
127 self._emitline(' FileSiz MemSiz Flags Align')
128
129 # Now the entries
130 #
131 for segment in self.elffile.iter_segments():
132 self._emit(' %-14s ' % describe_p_type(segment['p_type']))
133
134 if self.elffile.elfclass == 32:
135 self._emitline('%s %s %s %s %s %-3s %s' % (
136 self._format_hex(segment['p_offset'], fieldsize=6),
137 self._format_hex(segment['p_vaddr'], fullhex=True),
138 self._format_hex(segment['p_paddr'], fullhex=True),
139 self._format_hex(segment['p_filesz'], fieldsize=5),
140 self._format_hex(segment['p_memsz'], fieldsize=5),
141 describe_p_flags(segment['p_flags']),
142 self._format_hex(segment['p_align'])))
Eli Benderskya41c3c02011-09-14 06:18:28 +0300143 else: # 64
144 self._emitline('%s %s %s' % (
145 self._format_hex(segment['p_offset'], fullhex=True),
146 self._format_hex(segment['p_vaddr'], fullhex=True),
147 self._format_hex(segment['p_paddr'], fullhex=True)))
148 self._emitline(' %s %s %-3s %s' % (
149 self._format_hex(segment['p_filesz'], fullhex=True),
150 self._format_hex(segment['p_memsz'], fullhex=True),
151 describe_p_flags(segment['p_flags']),
152 # lead0x set to False for p_align, to mimic readelf.
153 # No idea why the difference from 32-bit mode :-|
154 self._format_hex(segment['p_align'], lead0x=False)))
Eli Bendersky26de2ac2011-09-13 06:50:28 +0300155
Eli Bendersky3f4de3e2011-09-14 05:58:06 +0300156 if isinstance(segment, InterpSegment):
157 self._emitline(' [Requesting program interpreter: %s]' %
158 segment.get_interp_name())
159
Eli Bendersky58585b02011-09-15 07:07:54 +0300160 # Sections to segments mapping
161 #
162 if self.elffile.num_sections() == 0:
163 # No sections? We're done
164 return
165
166 self._emitline('\n Section to Segment mapping:')
167 self._emitline(' Segment Sections...\n')
168
169 for nseg, segment in enumerate(self.elffile.iter_segments()):
170 self._emit(' %2.2d ' % nseg)
171
172 for section in self.elffile.iter_sections():
173 if ( not section.is_null() and
174 segment.section_in_segment(section)):
175 self._emit('%s ' % section.name)
176
177 self._emitline('')
178
Eli Bendersky0b27ba42011-09-17 06:44:02 +0300179 def display_section_headers(self, show_heading=True):
Eli Bendersky377bd862011-09-16 11:10:44 +0300180 """ Display the ELF section headers
181 """
182 elfheader = self.elffile.header
Eli Bendersky0b27ba42011-09-17 06:44:02 +0300183 if show_heading:
184 self._emitline('There are %s section headers, starting at offset %s' % (
185 elfheader['e_shnum'], self._format_hex(elfheader['e_shoff'])))
Eli Bendersky26de2ac2011-09-13 06:50:28 +0300186
Eli Bendersky377bd862011-09-16 11:10:44 +0300187 self._emitline('\nSection header%s:' % (
188 's' if elfheader['e_shnum'] > 1 else ''))
Eli Bendersky26de2ac2011-09-13 06:50:28 +0300189
Eli Bendersky377bd862011-09-16 11:10:44 +0300190 # Different formatting constraints of 32-bit and 64-bit addresses
191 #
192 if self.elffile.elfclass == 32:
193 self._emitline(' [Nr] Name Type Addr Off Size ES Flg Lk Inf Al')
194 else:
195 self._emitline(' [Nr] Name Type Address Offset')
196 self._emitline(' Size EntSize Flags Link Info Align')
197
198 # Now the entries
199 #
200 for nsec, section in enumerate(self.elffile.iter_sections()):
201 self._emit(' [%2u] %-17.17s %-15.15s ' % (
202 nsec, section.name, describe_sh_type(section['sh_type'])))
203
204 if self.elffile.elfclass == 32:
205 self._emitline('%s %s %s %s %3s %2s %3s %2s' % (
206 self._format_hex(section['sh_addr'], fieldsize=8, lead0x=False),
207 self._format_hex(section['sh_offset'], fieldsize=6, lead0x=False),
208 self._format_hex(section['sh_size'], fieldsize=6, lead0x=False),
209 self._format_hex(section['sh_entsize'], fieldsize=2, lead0x=False),
210 describe_sh_flags(section['sh_flags']),
211 section['sh_link'], section['sh_info'],
212 section['sh_addralign']))
213 else: # 64
214 self._emitline(' %s %s' % (
215 self._format_hex(section['sh_addr'], fullhex=True, lead0x=False),
216 self._format_hex(section['sh_offset'],
217 fieldsize=16 if section['sh_offset'] > 0xffffffff else 8,
218 lead0x=False)))
219 self._emitline(' %s %s %3s %2s %3s %s' % (
220 self._format_hex(section['sh_size'], fullhex=True, lead0x=False),
221 self._format_hex(section['sh_entsize'], fullhex=True, lead0x=False),
222 describe_sh_flags(section['sh_flags']),
223 section['sh_link'], section['sh_info'],
224 section['sh_addralign']))
225
226 self._emitline('Key to Flags:')
227 self._emitline(' W (write), A (alloc), X (execute), M (merge), S (strings)')
228 self._emitline(' I (info), L (link order), G (group), x (unknown)')
229 self._emitline(' O (extra OS processing required) o (OS specific), p (processor specific)')
230
Eli Bendersky3edefab2011-09-16 14:52:54 +0300231 def display_symbol_tables(self):
232 """ Display the symbol tables contained in the file
233 """
234 for section in self.elffile.iter_sections():
235 if not isinstance(section, SymbolTableSection):
236 continue
237
238 if section['sh_entsize'] == 0:
239 self._emitline("\nSymbol table '%s' has a sh_entsize of zero!" % (
240 section.name))
241 continue
242
243 self._emitline("\nSymbol table '%s' contains %s entries:" % (
244 section.name, section.num_symbols()))
245
246 if self.elffile.elfclass == 32:
247 self._emitline(' Num: Value Size Type Bind Vis Ndx Name')
248 else: # 64
249 self._emitline(' Num: Value Size Type Bind Vis Ndx Name')
250
251 for nsym, symbol in enumerate(section.iter_symbols()):
Eli Benderskyb6fa3652011-09-16 15:20:20 +0300252 # symbol names are truncated to 25 chars, similarly to readelf
253 self._emitline('%6d: %s %5d %-7s %-6s %-7s %4s %.25s' % (
Eli Bendersky3edefab2011-09-16 14:52:54 +0300254 nsym,
255 self._format_hex(symbol['st_value'], fullhex=True, lead0x=False),
256 symbol['st_size'],
257 describe_symbol_type(symbol['st_info']['type']),
258 describe_symbol_bind(symbol['st_info']['bind']),
259 describe_symbol_visibility(symbol['st_other']['visibility']),
260 describe_symbol_shndx(symbol['st_shndx']),
261 symbol.name))
262
Eli Bendersky26de2ac2011-09-13 06:50:28 +0300263 def _format_hex(self, addr, fieldsize=None, fullhex=False, lead0x=True):
Eli Bendersky6a12cde2011-09-09 10:23:16 +0300264 """ Format an address into a hexadecimal string.
Eli Benderskyd62928d2011-09-09 10:05:57 +0300265
Eli Bendersky26de2ac2011-09-13 06:50:28 +0300266 fieldsize:
267 Size of the hexadecimal field (with leading zeros to fit the
268 address into. For example with fieldsize=8, the format will
269 be %08x
270 If None, the minimal required field size will be used.
271
Eli Bendersky6a12cde2011-09-09 10:23:16 +0300272 fullhex:
Eli Bendersky26de2ac2011-09-13 06:50:28 +0300273 If True, override fieldsize to set it to the maximal size
274 needed for the elfclass
Eli Bendersky6a12cde2011-09-09 10:23:16 +0300275
276 lead0x:
277 If True, leading 0x is added
Eli Benderskyd62928d2011-09-09 10:05:57 +0300278 """
Eli Bendersky6a12cde2011-09-09 10:23:16 +0300279 s = '0x' if lead0x else ''
280 if fullhex:
Eli Bendersky26de2ac2011-09-13 06:50:28 +0300281 fieldsize = 8 if self.elffile.elfclass == 32 else 16
282 if fieldsize is None:
283 field = '%x'
Eli Bendersky6a12cde2011-09-09 10:23:16 +0300284 else:
Eli Bendersky26de2ac2011-09-13 06:50:28 +0300285 field = '%' + '0%sx' % fieldsize
286 return s + field % addr
Eli Benderskyd62928d2011-09-09 10:05:57 +0300287
Eli Bendersky26de2ac2011-09-13 06:50:28 +0300288 def _emit(self, s=''):
Eli Bendersky933f6992011-09-09 08:11:06 +0300289 """ Emit an object to output
290 """
291 self.output.write(str(s))
Eli Benderskyd62928d2011-09-09 10:05:57 +0300292
Eli Bendersky26de2ac2011-09-13 06:50:28 +0300293 def _emitline(self, s=''):
Eli Bendersky933f6992011-09-09 08:11:06 +0300294 """ Emit an object to output, followed by a newline
295 """
296 self.output.write(str(s) + '\n')
297
298
Eli Bendersky0b27ba42011-09-17 06:44:02 +0300299SCRIPT_DESCRIPTION = 'Display information about the contents of ELF format files'
300VERSION_STRING = '%%prog: based on pyelftools %s' % __version__
301
302
Eli Bendersky933f6992011-09-09 08:11:06 +0300303def main():
Eli Bendersky0b27ba42011-09-17 06:44:02 +0300304 # parse the command-line arguments and invoke ReadElf
Eli Bendersky40eb1702011-09-16 16:59:52 +0300305 optparser = OptionParser(
Eli Benderskyecde41b2011-09-16 17:16:20 +0300306 usage='usage: %prog [options] <elf-file>',
Eli Bendersky0b27ba42011-09-17 06:44:02 +0300307 description=SCRIPT_DESCRIPTION,
Eli Bendersky40eb1702011-09-16 16:59:52 +0300308 add_help_option=False, # -h is a real option of readelf
Eli Bendersky0b27ba42011-09-17 06:44:02 +0300309 prog='readelf.py',
310 version=VERSION_STRING)
Eli Bendersky40eb1702011-09-16 16:59:52 +0300311 optparser.add_option('-H', '--help',
312 action='store_true', dest='help',
313 help='Display this information')
314 optparser.add_option('-h', '--file-header',
Eli Benderskyecde41b2011-09-16 17:16:20 +0300315 action='store_true', dest='show_file_header',
316 help='Display the ELF file header')
Eli Bendersky40eb1702011-09-16 16:59:52 +0300317 optparser.add_option('-l', '--program-headers', '--segments',
Eli Bendersky0b27ba42011-09-17 06:44:02 +0300318 action='store_true', dest='show_program_header',
Eli Benderskyecde41b2011-09-16 17:16:20 +0300319 help='Display the program headers')
Eli Bendersky40eb1702011-09-16 16:59:52 +0300320 optparser.add_option('-S', '--section-headers', '--sections',
Eli Bendersky0b27ba42011-09-17 06:44:02 +0300321 action='store_true', dest='show_section_header',
Eli Benderskyecde41b2011-09-16 17:16:20 +0300322 help="Display the sections' headers")
Eli Bendersky40eb1702011-09-16 16:59:52 +0300323 optparser.add_option('-e', '--headers',
Eli Benderskyecde41b2011-09-16 17:16:20 +0300324 action='store_true', dest='show_all_headers',
325 help='Equivalent to: -h -l -S')
Eli Bendersky40eb1702011-09-16 16:59:52 +0300326 optparser.add_option('-s', '--symbols', '--syms',
Eli Benderskyecde41b2011-09-16 17:16:20 +0300327 action='store_true', dest='show_symbols',
328 help='Display the symbol table')
Eli Bendersky933f6992011-09-09 08:11:06 +0300329 options, args = optparser.parse_args()
330
Eli Bendersky40eb1702011-09-16 16:59:52 +0300331 if options.help or len(args) == 0:
332 optparser.print_help()
333 sys.exit(0)
334
Eli Bendersky0b27ba42011-09-17 06:44:02 +0300335 if options.show_all_headers:
336 do_file_header = do_section_header = do_program_header = True
337 else:
338 do_file_header = options.show_file_header
339 do_section_header = options.show_section_header
340 do_program_header = options.show_program_header
341
Eli Bendersky933f6992011-09-09 08:11:06 +0300342 with open(args[0], 'rb') as file:
343 try:
344 readelf = ReadElf(file, sys.stdout)
Eli Bendersky0b27ba42011-09-17 06:44:02 +0300345 if do_file_header:
346 readelf.display_file_header()
347 if do_program_header:
348 readelf.display_program_headers(
349 show_heading=not do_file_header)
350 if do_section_header:
351 readelf.display_section_headers(
352 show_heading=not do_file_header)
353 if options.show_symbols:
354 readelf.display_symbol_tables()
Eli Bendersky933f6992011-09-09 08:11:06 +0300355 except ELFError as ex:
Eli Bendersky0b27ba42011-09-17 06:44:02 +0300356 sys.stderr.write('ELF error: %s\n' % ex)
Eli Bendersky933f6992011-09-09 08:11:06 +0300357 sys.exit(1)
358
359
360#-------------------------------------------------------------------------------
361if __name__ == '__main__':
362 main()
363