implemented some of program header display
[pyelftools.git] / scripts / readelf.py
1 #-------------------------------------------------------------------------------
2 # readelf.py
3 #
4 # A clone of 'readelf' in Python, based on the pyelftools library
5 #
6 # Eli Bendersky (eliben@gmail.com)
7 # This code is in the public domain
8 #-------------------------------------------------------------------------------
9 import sys
10 from optparse import OptionParser
11
12 # If elftools is not installed, maybe we're running from the root or scripts
13 # dir of the source distribution
14 #
15 try:
16 import elftools
17 except ImportError:
18 sys.path.extend(['.', '..'])
19
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,
26
27 )
28
29
30 class ReadElf(object):
31 """ display_* methods are used to emit output into the output stream
32 """
33 def __init__(self, file, output):
34 """ file:
35 stream object with the ELF file to read
36
37 output:
38 output stream to write to
39 """
40 self.elffile = ELFFile(file)
41 self.output = output
42
43 def display_file_header(self):
44 """ Display the ELF file header
45 """
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' %
71 header['e_phoff'])
72 self._emitline(' (bytes into file)')
73 self._emit(' Start of section headers %s' %
74 header['e_shoff'])
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)' %
79 header['e_ehsize'])
80 self._emitline(' Size of program headers: %s (bytes)' %
81 header['e_phentsize'])
82 self._emitline(' Number of program headers: %s' %
83 header['e_phnum'])
84 self._emitline(' Size of section headers: %s (bytes)' %
85 header['e_shentsize'])
86 self._emitline(' Number of section headers: %s' %
87 header['e_shnum'])
88 self._emitline(' Section header string table index: %s' %
89 header['e_shstrndx'])
90
91 def display_program_headers(self):
92 """ Display the ELF program headers
93 """
94 self._emitline()
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']))
102
103 self._emitline('\nProgram headers:')
104
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.
108 #
109 # First comes the table heading
110 #
111 if self.elffile.elfclass == 32:
112 self._emitline(' Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align')
113 else:
114 self._emitline(' Type Offset VirtAddr PhysAddr')
115 self._emitline(' FileSiz MemSiz Flags Align')
116
117 # Now the entries
118 #
119 for segment in self.elffile.iter_segments():
120 self._emit(' %-14s ' % describe_p_type(segment['p_type']))
121
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'])))
131
132
133
134
135 def _format_hex(self, addr, fieldsize=None, fullhex=False, lead0x=True):
136 """ Format an address into a hexadecimal string.
137
138 fieldsize:
139 Size of the hexadecimal field (with leading zeros to fit the
140 address into. For example with fieldsize=8, the format will
141 be %08x
142 If None, the minimal required field size will be used.
143
144 fullhex:
145 If True, override fieldsize to set it to the maximal size
146 needed for the elfclass
147
148 lead0x:
149 If True, leading 0x is added
150 """
151 s = '0x' if lead0x else ''
152 if fullhex:
153 fieldsize = 8 if self.elffile.elfclass == 32 else 16
154 if fieldsize is None:
155 field = '%x'
156 else:
157 field = '%' + '0%sx' % fieldsize
158 return s + field % addr
159
160 def _emit(self, s=''):
161 """ Emit an object to output
162 """
163 self.output.write(str(s))
164
165 def _emitline(self, s=''):
166 """ Emit an object to output, followed by a newline
167 """
168 self.output.write(str(s) + '\n')
169
170
171 def main():
172 optparser = OptionParser()
173 options, args = optparser.parse_args()
174
175 with open(args[0], 'rb') as file:
176 try:
177 readelf = ReadElf(file, sys.stdout)
178 readelf.display_file_header()
179 print '----'
180 readelf.display_program_headers()
181 except ELFError as ex:
182 sys.stderr.write('ELF read error: %s\n' % ex)
183 sys.exit(1)
184
185
186 #-------------------------------------------------------------------------------
187 if __name__ == '__main__':
188 main()
189