1 #-------------------------------------------------------------------------------
4 # A clone of 'readelf' in Python, based on the pyelftools library
6 # Eli Bendersky (eliben@gmail.com)
7 # This code is in the public domain
8 #-------------------------------------------------------------------------------
10 from optparse
import OptionParser
12 # If elftools is not installed, maybe we're running from the root or scripts
13 # dir of the source distribution
18 sys
.path
.extend(['.', '..'])
20 from elftools
.common
.exceptions
import ELFError
21 from elftools
.elf
.elffile
import ELFFile
22 from elftools
.elf
.descriptions
import (
23 describe_ei_class
, describe_ei_data
, describe_ei_version
,
24 describe_ei_osabi
, describe_e_type
, describe_e_machine
,
25 describe_e_version_numeric
, describe_p_type
, describe_p_flags
,
30 class ReadElf(object):
31 """ display_* methods are used to emit output into the output stream
33 def __init__(self
, file, output
):
35 stream object with the ELF file to read
38 output stream to write to
40 self
.elffile
= ELFFile(file)
43 def display_file_header(self
):
44 """ Display the ELF file header
46 self
._emitline
('ELF Header:')
47 self
._emit
(' Magic: ')
48 self
._emitline
(' '.join('%2.2x' % ord(b
)
49 for b
in self
.elffile
.e_ident_raw
))
50 header
= self
.elffile
.header
51 e_ident
= header
['e_ident']
52 self
._emitline
(' Class: %s' %
53 describe_ei_class(e_ident
['EI_CLASS']))
54 self
._emitline
(' Data: %s' %
55 describe_ei_data(e_ident
['EI_DATA']))
56 self
._emitline
(' Version: %s' %
57 describe_ei_version(e_ident
['EI_VERSION']))
58 self
._emitline
(' OS/ABI: %s' %
59 describe_ei_osabi(e_ident
['EI_OSABI']))
60 self
._emitline
(' ABI Version: %d' %
61 e_ident
['EI_ABIVERSION'])
62 self
._emitline
(' Type: %s' %
63 describe_e_type(header
['e_type']))
64 self
._emitline
(' Machine: %s' %
65 describe_e_machine(header
['e_machine']))
66 self
._emitline
(' Version: %s' %
67 describe_e_version_numeric(header
['e_version']))
68 self
._emitline
(' Entry point address: %s' %
69 self
._format
_hex
(header
['e_entry']))
70 self
._emit
(' Start of program headers %s' %
72 self
._emitline
(' (bytes into file)')
73 self
._emit
(' Start of section headers %s' %
75 self
._emitline
(' (bytes into file)')
76 self
._emitline
(' Flags: %s' %
77 self
._format
_hex
(header
['e_flags']))
78 self
._emitline
(' Size of this header: %s (bytes)' %
80 self
._emitline
(' Size of program headers: %s (bytes)' %
81 header
['e_phentsize'])
82 self
._emitline
(' Number of program headers: %s' %
84 self
._emitline
(' Size of section headers: %s (bytes)' %
85 header
['e_shentsize'])
86 self
._emitline
(' Number of section headers: %s' %
88 self
._emitline
(' Section header string table index: %s' %
91 def display_program_headers(self
):
92 """ Display the ELF program headers
95 elfheader
= self
.elffile
.header
96 self
._emitline
('Elf file type is %s' %
97 describe_e_type(elfheader
['e_type']))
98 self
._emitline
('Entry point is %s' %
99 self
._format
_hex
(elfheader
['e_entry']))
100 self
._emitline
('There are %s program headers, starting at offset %s' % (
101 elfheader
['e_phnum'], elfheader
['e_phoff']))
103 self
._emitline
('\nProgram headers:')
105 # Now comes the table of program headers with their attributes. Note
106 # that due to different formatting constraints of 32-bit and 64-bit
107 # addresses, there are some conditions on elfclass here.
109 # First comes the table heading
111 if self
.elffile
.elfclass
== 32:
112 self
._emitline
(' Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align')
114 self
._emitline
(' Type Offset VirtAddr PhysAddr')
115 self
._emitline
(' FileSiz MemSiz Flags Align')
119 for segment
in self
.elffile
.iter_segments():
120 self
._emit
(' %-14s ' % describe_p_type(segment
['p_type']))
122 if self
.elffile
.elfclass
== 32:
123 self
._emitline
('%s %s %s %s %s %-3s %s' % (
124 self
._format
_hex
(segment
['p_offset'], fieldsize
=6),
125 self
._format
_hex
(segment
['p_vaddr'], fullhex
=True),
126 self
._format
_hex
(segment
['p_paddr'], fullhex
=True),
127 self
._format
_hex
(segment
['p_filesz'], fieldsize
=5),
128 self
._format
_hex
(segment
['p_memsz'], fieldsize
=5),
129 describe_p_flags(segment
['p_flags']),
130 self
._format
_hex
(segment
['p_align'])))
135 def _format_hex(self
, addr
, fieldsize
=None, fullhex
=False, lead0x
=True):
136 """ Format an address into a hexadecimal string.
139 Size of the hexadecimal field (with leading zeros to fit the
140 address into. For example with fieldsize=8, the format will
142 If None, the minimal required field size will be used.
145 If True, override fieldsize to set it to the maximal size
146 needed for the elfclass
149 If True, leading 0x is added
151 s
= '0x' if lead0x
else ''
153 fieldsize
= 8 if self
.elffile
.elfclass
== 32 else 16
154 if fieldsize
is None:
157 field
= '%' + '0%sx' % fieldsize
158 return s
+ field
% addr
160 def _emit(self
, s
=''):
161 """ Emit an object to output
163 self
.output
.write(str(s
))
165 def _emitline(self
, s
=''):
166 """ Emit an object to output, followed by a newline
168 self
.output
.write(str(s
) + '\n')
172 optparser
= OptionParser()
173 options
, args
= optparser
.parse_args()
175 with
open(args
[0], 'rb') as file:
177 readelf
= ReadElf(file, sys
.stdout
)
178 readelf
.display_file_header()
180 readelf
.display_program_headers()
181 except ELFError
as ex
:
182 sys
.stderr
.write('ELF read error: %s\n' % ex
)
186 #-------------------------------------------------------------------------------
187 if __name__
== '__main__':