2 #-------------------------------------------------------------------------------
5 # A clone of 'readelf' in Python, based on the pyelftools library
7 # Eli Bendersky (eliben@gmail.com)
8 # This code is in the public domain
9 #-------------------------------------------------------------------------------
11 from optparse
import OptionParser
14 # If elftools is not installed, maybe we're running from the root or scripts
15 # dir of the source distribution
19 sys
.path
.extend(['.', '..'])
21 from elftools
import __version__
22 from elftools
.common
.exceptions
import ELFError
23 from elftools
.common
.py3compat
import (
24 ifilter
, byte2int
, bytes2str
, itervalues
, str2bytes
)
25 from elftools
.elf
.elffile
import ELFFile
26 from elftools
.elf
.segments
import InterpSegment
27 from elftools
.elf
.sections
import SymbolTableSection
28 from elftools
.elf
.relocation
import RelocationSection
29 from elftools
.elf
.descriptions
import (
30 describe_ei_class
, describe_ei_data
, describe_ei_version
,
31 describe_ei_osabi
, describe_e_type
, describe_e_machine
,
32 describe_e_version_numeric
, describe_p_type
, describe_p_flags
,
33 describe_sh_type
, describe_sh_flags
,
34 describe_symbol_type
, describe_symbol_bind
, describe_symbol_visibility
,
35 describe_symbol_shndx
, describe_reloc_type
,
37 from elftools
.dwarf
.dwarfinfo
import DWARFInfo
38 from elftools
.dwarf
.descriptions
import (
39 describe_reg_name
, describe_attr_value
, set_global_machine_arch
,
40 describe_CFI_instructions
, describe_CFI_register_rule
,
41 describe_CFI_CFA_rule
,
43 from elftools
.dwarf
.constants
import (
44 DW_LNS_copy
, DW_LNS_set_file
, DW_LNE_define_file
)
45 from elftools
.dwarf
.callframe
import CIE
, FDE
48 class ReadElf(object):
49 """ display_* methods are used to emit output into the output stream
51 def __init__(self
, file, output
):
53 stream object with the ELF file to read
56 output stream to write to
58 self
.elffile
= ELFFile(file)
61 # Lazily initialized if a debug dump is requested
62 self
._dwarfinfo
= None
64 def display_file_header(self
):
65 """ Display the ELF file header
67 self
._emitline
('ELF Header:')
68 self
._emit
(' Magic: ')
69 self
._emitline
(' '.join('%2.2x' % byte2int(b
)
70 for b
in self
.elffile
.e_ident_raw
))
71 header
= self
.elffile
.header
72 e_ident
= header
['e_ident']
73 self
._emitline
(' Class: %s' %
74 describe_ei_class(e_ident
['EI_CLASS']))
75 self
._emitline
(' Data: %s' %
76 describe_ei_data(e_ident
['EI_DATA']))
77 self
._emitline
(' Version: %s' %
78 describe_ei_version(e_ident
['EI_VERSION']))
79 self
._emitline
(' OS/ABI: %s' %
80 describe_ei_osabi(e_ident
['EI_OSABI']))
81 self
._emitline
(' ABI Version: %d' %
82 e_ident
['EI_ABIVERSION'])
83 self
._emitline
(' Type: %s' %
84 describe_e_type(header
['e_type']))
85 self
._emitline
(' Machine: %s' %
86 describe_e_machine(header
['e_machine']))
87 self
._emitline
(' Version: %s' %
88 describe_e_version_numeric(header
['e_version']))
89 self
._emitline
(' Entry point address: %s' %
90 self
._format
_hex
(header
['e_entry']))
91 self
._emit
(' Start of program headers: %s' %
93 self
._emitline
(' (bytes into file)')
94 self
._emit
(' Start of section headers: %s' %
96 self
._emitline
(' (bytes into file)')
97 self
._emitline
(' Flags: %s' %
98 self
._format
_hex
(header
['e_flags']))
99 self
._emitline
(' Size of this header: %s (bytes)' %
101 self
._emitline
(' Size of program headers: %s (bytes)' %
102 header
['e_phentsize'])
103 self
._emitline
(' Number of program headers: %s' %
105 self
._emitline
(' Size of section headers: %s (bytes)' %
106 header
['e_shentsize'])
107 self
._emitline
(' Number of section headers: %s' %
109 self
._emitline
(' Section header string table index: %s' %
110 header
['e_shstrndx'])
112 def display_program_headers(self
, show_heading
=True):
113 """ Display the ELF program headers.
114 If show_heading is True, displays the heading for this information
115 (Elf file type is...)
118 if self
.elffile
.num_segments() == 0:
119 self
._emitline
('There are no program headers in this file.')
122 elfheader
= self
.elffile
.header
124 self
._emitline
('Elf file type is %s' %
125 describe_e_type(elfheader
['e_type']))
126 self
._emitline
('Entry point is %s' %
127 self
._format
_hex
(elfheader
['e_entry']))
128 # readelf weirness - why isn't e_phoff printed as hex? (for section
130 self
._emitline
('There are %s program headers, starting at offset %s' % (
131 elfheader
['e_phnum'], elfheader
['e_phoff']))
134 self
._emitline
('Program Headers:')
136 # Now comes the table of program headers with their attributes. Note
137 # that due to different formatting constraints of 32-bit and 64-bit
138 # addresses, there are some conditions on elfclass here.
140 # First comes the table heading
142 if self
.elffile
.elfclass
== 32:
143 self
._emitline
(' Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align')
145 self
._emitline
(' Type Offset VirtAddr PhysAddr')
146 self
._emitline
(' FileSiz MemSiz Flags Align')
150 for segment
in self
.elffile
.iter_segments():
151 self
._emit
(' %-14s ' % describe_p_type(segment
['p_type']))
153 if self
.elffile
.elfclass
== 32:
154 self
._emitline
('%s %s %s %s %s %-3s %s' % (
155 self
._format
_hex
(segment
['p_offset'], fieldsize
=6),
156 self
._format
_hex
(segment
['p_vaddr'], fullhex
=True),
157 self
._format
_hex
(segment
['p_paddr'], fullhex
=True),
158 self
._format
_hex
(segment
['p_filesz'], fieldsize
=5),
159 self
._format
_hex
(segment
['p_memsz'], fieldsize
=5),
160 describe_p_flags(segment
['p_flags']),
161 self
._format
_hex
(segment
['p_align'])))
163 self
._emitline
('%s %s %s' % (
164 self
._format
_hex
(segment
['p_offset'], fullhex
=True),
165 self
._format
_hex
(segment
['p_vaddr'], fullhex
=True),
166 self
._format
_hex
(segment
['p_paddr'], fullhex
=True)))
167 self
._emitline
(' %s %s %-3s %s' % (
168 self
._format
_hex
(segment
['p_filesz'], fullhex
=True),
169 self
._format
_hex
(segment
['p_memsz'], fullhex
=True),
170 describe_p_flags(segment
['p_flags']),
171 # lead0x set to False for p_align, to mimic readelf.
172 # No idea why the difference from 32-bit mode :-|
173 self
._format
_hex
(segment
['p_align'], lead0x
=False)))
175 if isinstance(segment
, InterpSegment
):
176 self
._emitline
(' [Requesting program interpreter: %s]' %
177 bytes2str(segment
.get_interp_name()))
179 # Sections to segments mapping
181 if self
.elffile
.num_sections() == 0:
182 # No sections? We're done
185 self
._emitline
('\n Section to Segment mapping:')
186 self
._emitline
(' Segment Sections...')
188 for nseg
, segment
in enumerate(self
.elffile
.iter_segments()):
189 self
._emit
(' %2.2d ' % nseg
)
191 for section
in self
.elffile
.iter_sections():
192 if ( not section
.is_null() and
193 segment
.section_in_segment(section
)):
194 self
._emit
('%s ' % bytes2str(section
.name
))
198 def display_section_headers(self
, show_heading
=True):
199 """ Display the ELF section headers
201 elfheader
= self
.elffile
.header
203 self
._emitline
('There are %s section headers, starting at offset %s' % (
204 elfheader
['e_shnum'], self
._format
_hex
(elfheader
['e_shoff'])))
206 self
._emitline
('\nSection Header%s:' % (
207 's' if elfheader
['e_shnum'] > 1 else ''))
209 # Different formatting constraints of 32-bit and 64-bit addresses
211 if self
.elffile
.elfclass
== 32:
212 self
._emitline
(' [Nr] Name Type Addr Off Size ES Flg Lk Inf Al')
214 self
._emitline
(' [Nr] Name Type Address Offset')
215 self
._emitline
(' Size EntSize Flags Link Info Align')
219 for nsec
, section
in enumerate(self
.elffile
.iter_sections()):
220 self
._emit
(' [%2u] %-17.17s %-15.15s ' % (
221 nsec
, bytes2str(section
.name
), describe_sh_type(section
['sh_type'])))
223 if self
.elffile
.elfclass
== 32:
224 self
._emitline
('%s %s %s %s %3s %2s %3s %2s' % (
225 self
._format
_hex
(section
['sh_addr'], fieldsize
=8, lead0x
=False),
226 self
._format
_hex
(section
['sh_offset'], fieldsize
=6, lead0x
=False),
227 self
._format
_hex
(section
['sh_size'], fieldsize
=6, lead0x
=False),
228 self
._format
_hex
(section
['sh_entsize'], fieldsize
=2, lead0x
=False),
229 describe_sh_flags(section
['sh_flags']),
230 section
['sh_link'], section
['sh_info'],
231 section
['sh_addralign']))
233 self
._emitline
(' %s %s' % (
234 self
._format
_hex
(section
['sh_addr'], fullhex
=True, lead0x
=False),
235 self
._format
_hex
(section
['sh_offset'],
236 fieldsize
=16 if section
['sh_offset'] > 0xffffffff else 8,
238 self
._emitline
(' %s %s %3s %2s %3s %s' % (
239 self
._format
_hex
(section
['sh_size'], fullhex
=True, lead0x
=False),
240 self
._format
_hex
(section
['sh_entsize'], fullhex
=True, lead0x
=False),
241 describe_sh_flags(section
['sh_flags']),
242 section
['sh_link'], section
['sh_info'],
243 section
['sh_addralign']))
245 self
._emitline
('Key to Flags:')
246 self
._emit
(' W (write), A (alloc), X (execute), M (merge), S (strings)')
247 if self
.elffile
['e_machine'] in ('EM_X86_64', 'EM_L10M'):
248 self
._emitline
(', l (large)')
251 self
._emitline
(' I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)')
252 self
._emitline
(' O (extra OS processing required) o (OS specific), p (processor specific)')
254 def display_symbol_tables(self
):
255 """ Display the symbol tables contained in the file
257 for section
in self
.elffile
.iter_sections():
258 if not isinstance(section
, SymbolTableSection
):
261 if section
['sh_entsize'] == 0:
262 self
._emitline
("\nSymbol table '%s' has a sh_entsize of zero!" % (
263 bytes2str(section
.name
)))
266 self
._emitline
("\nSymbol table '%s' contains %s entries:" % (
267 bytes2str(section
.name
), section
.num_symbols()))
269 if self
.elffile
.elfclass
== 32:
270 self
._emitline
(' Num: Value Size Type Bind Vis Ndx Name')
272 self
._emitline
(' Num: Value Size Type Bind Vis Ndx Name')
274 for nsym
, symbol
in enumerate(section
.iter_symbols()):
275 # symbol names are truncated to 25 chars, similarly to readelf
276 self
._emitline
('%6d: %s %5d %-7s %-6s %-7s %4s %.25s' % (
278 self
._format
_hex
(symbol
['st_value'], fullhex
=True, lead0x
=False),
280 describe_symbol_type(symbol
['st_info']['type']),
281 describe_symbol_bind(symbol
['st_info']['bind']),
282 describe_symbol_visibility(symbol
['st_other']['visibility']),
283 describe_symbol_shndx(symbol
['st_shndx']),
284 bytes2str(symbol
.name
)))
286 def display_relocations(self
):
287 """ Display the relocations contained in the file
289 has_relocation_sections
= False
290 for section
in self
.elffile
.iter_sections():
291 if not isinstance(section
, RelocationSection
):
294 has_relocation_sections
= True
295 self
._emitline
("\nRelocation section '%s' at offset %s contains %s entries:" % (
296 bytes2str(section
.name
),
297 self
._format
_hex
(section
['sh_offset']),
298 section
.num_relocations()))
299 if section
.is_RELA():
300 self
._emitline
(" Offset Info Type Sym. Value Sym. Name + Addend")
302 self
._emitline
(" Offset Info Type Sym.Value Sym. Name")
304 # The symbol table section pointed to in sh_link
305 symtable
= self
.elffile
.get_section(section
['sh_link'])
307 for rel
in section
.iter_relocations():
308 hexwidth
= 8 if self
.elffile
.elfclass
== 32 else 12
309 self
._emit
('%s %s %-17.17s' % (
310 self
._format
_hex
(rel
['r_offset'],
311 fieldsize
=hexwidth
, lead0x
=False),
312 self
._format
_hex
(rel
['r_info'],
313 fieldsize
=hexwidth
, lead0x
=False),
315 rel
['r_info_type'], self
.elffile
)))
317 if rel
['r_info_sym'] == 0:
321 symbol
= symtable
.get_symbol(rel
['r_info_sym'])
322 # Some symbols have zero 'st_name', so instead what's used is
323 # the name of the section they point at
324 if symbol
['st_name'] == 0:
325 symsec
= self
.elffile
.get_section(symbol
['st_shndx'])
326 symbol_name
= symsec
.name
328 symbol_name
= symbol
.name
329 self
._emit
(' %s %s%22.22s' % (
332 fullhex
=True, lead0x
=False),
333 ' ' if self
.elffile
.elfclass
== 32 else '',
334 bytes2str(symbol_name
)))
335 if section
.is_RELA():
336 self
._emit
(' %s %x' % (
337 '+' if rel
['r_addend'] >= 0 else '-',
338 abs(rel
['r_addend'])))
341 if not has_relocation_sections
:
342 self
._emitline
('\nThere are no relocations in this file.')
344 def display_hex_dump(self
, section_spec
):
345 """ Display a hex dump of a section. section_spec is either a section
348 section
= self
._section
_from
_spec
(section_spec
)
350 self
._emitline
("Section '%s' does not exist in the file!" % (
354 self
._emitline
("\nHex dump of section '%s':" % bytes2str(section
.name
))
355 self
._note
_relocs
_for
_section
(section
)
356 addr
= section
['sh_addr']
357 data
= section
.data()
360 while dataptr
< len(data
):
361 bytesleft
= len(data
) - dataptr
362 # chunks of 16 bytes per line
363 linebytes
= 16 if bytesleft
> 16 else bytesleft
365 self
._emit
(' %s ' % self
._format
_hex
(addr
, fieldsize
=8))
368 self
._emit
('%2.2x' % byte2int(data
[dataptr
+ i
]))
374 for i
in range(linebytes
):
375 c
= data
[dataptr
+ i
: dataptr
+ i
+ 1]
376 if byte2int(c
[0]) >= 32 and byte2int(c
[0]) < 0x7f:
377 self
._emit
(bytes2str(c
))
379 self
._emit
(bytes2str(b
'.'))
387 def display_string_dump(self
, section_spec
):
388 """ Display a strings dump of a section. section_spec is either a
389 section number or a name.
391 section
= self
._section
_from
_spec
(section_spec
)
393 self
._emitline
("Section '%s' does not exist in the file!" % (
397 self
._emitline
("\nString dump of section '%s':" % bytes2str(section
.name
))
400 data
= section
.data()
403 while dataptr
< len(data
):
404 while ( dataptr
< len(data
) and
405 not (32 <= byte2int(data
[dataptr
]) <= 127)):
408 if dataptr
>= len(data
):
412 while endptr
< len(data
) and byte2int(data
[endptr
]) != 0:
416 self
._emitline
(' [%6x] %s' % (
417 dataptr
, bytes2str(data
[dataptr
:endptr
])))
422 self
._emitline
(' No strings found in this section.')
426 def display_debug_dump(self
, dump_what
):
427 """ Dump a DWARF section
429 self
._init
_dwarfinfo
()
430 if self
._dwarfinfo
is None:
433 set_global_machine_arch(self
.elffile
.get_machine_arch())
435 if dump_what
== 'info':
436 self
._dump
_debug
_info
()
437 elif dump_what
== 'decodedline':
438 self
._dump
_debug
_line
_programs
()
439 elif dump_what
== 'frames':
440 self
._dump
_debug
_frames
()
441 elif dump_what
== 'frames-interp':
442 self
._dump
_debug
_frames
_interp
()
444 self
._emitline
('debug dump not yet supported for "%s"' % dump_what
)
446 def _format_hex(self
, addr
, fieldsize
=None, fullhex
=False, lead0x
=True):
447 """ Format an address into a hexadecimal string.
450 Size of the hexadecimal field (with leading zeros to fit the
451 address into. For example with fieldsize=8, the format will
453 If None, the minimal required field size will be used.
456 If True, override fieldsize to set it to the maximal size
457 needed for the elfclass
460 If True, leading 0x is added
462 s
= '0x' if lead0x
else ''
464 fieldsize
= 8 if self
.elffile
.elfclass
== 32 else 16
465 if fieldsize
is None:
468 field
= '%' + '0%sx' % fieldsize
469 return s
+ field
% addr
471 def _section_from_spec(self
, spec
):
472 """ Retrieve a section given a "spec" (either number or name).
473 Return None if no such section exists in the file.
477 if num
< self
.elffile
.num_sections():
478 return self
.elffile
.get_section(num
)
482 # Not a number. Must be a name then
483 return self
.elffile
.get_section_by_name(str2bytes(spec
))
485 def _note_relocs_for_section(self
, section
):
486 """ If there are relocation sections pointing to the givne section,
487 emit a note about it.
489 for relsec
in self
.elffile
.iter_sections():
490 if isinstance(relsec
, RelocationSection
):
491 info_idx
= relsec
['sh_info']
492 if self
.elffile
.get_section(info_idx
) == section
:
493 self
._emitline
(' Note: This section has relocations against it, but these have NOT been applied to this dump.')
496 def _init_dwarfinfo(self
):
497 """ Initialize the DWARF info contained in the file and assign it to
499 Leave self._dwarfinfo at None if no DWARF info was found in the file
501 if self
._dwarfinfo
is not None:
504 if self
.elffile
.has_dwarf_info():
505 self
._dwarfinfo
= self
.elffile
.get_dwarf_info()
507 self
._dwarfinfo
= None
509 def _dump_debug_info(self
):
510 """ Dump the debugging info section.
512 self
._emitline
('Contents of the .debug_info section:\n')
514 # Offset of the .debug_info section in the stream
515 section_offset
= self
._dwarfinfo
.debug_info_sec
.global_offset
517 for cu
in self
._dwarfinfo
.iter_CUs():
518 self
._emitline
(' Compilation Unit @ offset %s:' %
519 self
._format
_hex
(cu
.cu_offset
))
520 self
._emitline
(' Length: %s (%s)' % (
521 self
._format
_hex
(cu
['unit_length']),
522 '%s-bit' % cu
.dwarf_format()))
523 self
._emitline
(' Version: %s' % cu
['version']),
524 self
._emitline
(' Abbrev Offset: %s' % cu
['debug_abbrev_offset']),
525 self
._emitline
(' Pointer Size: %s' % cu
['address_size'])
527 # The nesting depth of each DIE within the tree of DIEs must be
528 # displayed. To implement this, a counter is incremented each time
529 # the current DIE has children, and decremented when a null die is
530 # encountered. Due to the way the DIE tree is serialized, this will
531 # correctly reflect the nesting depth
534 for die
in cu
.iter_DIEs():
538 self
._emitline
(' <%s><%x>: Abbrev Number: %s (%s)' % (
544 for attr
in itervalues(die
.attributes
):
546 # Unknown attribute values are passed-through as integers
547 if isinstance(name
, int):
548 name
= 'Unknown AT value: %x' % name
549 self
._emitline
(' <%2x> %-18s: %s' % (
553 attr
, die
, section_offset
)))
560 def _dump_debug_line_programs(self
):
561 """ Dump the (decoded) line programs from .debug_line
562 The programs are dumped in the order of the CUs they belong to.
564 self
._emitline
('Decoded dump of debug contents of section .debug_line:\n')
566 for cu
in self
._dwarfinfo
.iter_CUs():
567 lineprogram
= self
._dwarfinfo
.line_program_for_CU(cu
)
570 if len(lineprogram
['include_directory']) > 0:
571 cu_filename
= '%s/%s' % (
572 bytes2str(lineprogram
['include_directory'][0]),
573 bytes2str(lineprogram
['file_entry'][0].name
))
575 cu_filename
= bytes2str(lineprogram
['file_entry'][0].name
)
577 self
._emitline
('CU: %s:' % cu_filename
)
578 self
._emitline
('File name Line number Starting address')
580 # Print each state's file, line and address information. For some
581 # instructions other output is needed to be compatible with
583 for entry
in lineprogram
.get_entries():
586 # Special handling for commands that don't set a new state
587 if entry
.command
== DW_LNS_set_file
:
588 file_entry
= lineprogram
['file_entry'][entry
.args
[0] - 1]
589 if file_entry
.dir_index
== 0:
591 self
._emitline
('\n./%s:[++]' % (
592 bytes2str(file_entry
.name
)))
594 self
._emitline
('\n%s/%s:' % (
595 bytes2str(lineprogram
['include_directory'][file_entry
.dir_index
- 1]),
596 bytes2str(file_entry
.name
)))
597 elif entry
.command
== DW_LNE_define_file
:
598 self
._emitline
('%s:' % (
599 bytes2str(lineprogram
['include_directory'][entry
.args
[0].dir_index
])))
600 elif not state
.end_sequence
:
601 # readelf doesn't print the state after end_sequence
602 # instructions. I think it's a bug but to be compatible
603 # I don't print them too.
604 self
._emitline
('%-35s %11d %18s' % (
605 bytes2str(lineprogram
['file_entry'][state
.file - 1].name
),
607 '0' if state
.address
== 0 else
608 self
._format
_hex
(state
.address
)))
609 if entry
.command
== DW_LNS_copy
:
610 # Another readelf oddity...
613 def _dump_debug_frames(self
):
614 """ Dump the raw frame information from .debug_frame
616 if not self
._dwarfinfo
.has_CFI():
618 self
._emitline
('Contents of the .debug_frame section:')
620 for entry
in self
._dwarfinfo
.CFI_entries():
621 if isinstance(entry
, CIE
):
622 self
._emitline
('\n%08x %08x %08x CIE' % (
623 entry
.offset
, entry
['length'], entry
['CIE_id']))
624 self
._emitline
(' Version: %d' % entry
['version'])
625 self
._emitline
(' Augmentation: "%s"' % bytes2str(entry
['augmentation']))
626 self
._emitline
(' Code alignment factor: %u' % entry
['code_alignment_factor'])
627 self
._emitline
(' Data alignment factor: %d' % entry
['data_alignment_factor'])
628 self
._emitline
(' Return address column: %d' % entry
['return_address_register'])
631 self
._emitline
('\n%08x %08x %08x FDE cie=%08x pc=%08x..%08x' % (
634 entry
['CIE_pointer'],
636 entry
['initial_location'],
637 entry
['initial_location'] + entry
['address_range']))
639 self
._emit
(describe_CFI_instructions(entry
))
642 def _dump_debug_frames_interp(self
):
643 """ Dump the interpreted (decoded) frame information from .debug_frame
645 if not self
._dwarfinfo
.has_CFI():
648 self
._emitline
('Contents of the .debug_frame section:')
650 for entry
in self
._dwarfinfo
.CFI_entries():
651 if isinstance(entry
, CIE
):
652 self
._emitline
('\n%08x %08x %08x CIE "%s" cf=%d df=%d ra=%d' % (
656 bytes2str(entry
['augmentation']),
657 entry
['code_alignment_factor'],
658 entry
['data_alignment_factor'],
659 entry
['return_address_register']))
660 ra_regnum
= entry
['return_address_register']
662 self
._emitline
('\n%08x %08x %08x FDE cie=%08x pc=%08x..%08x' % (
665 entry
['CIE_pointer'],
667 entry
['initial_location'],
668 entry
['initial_location'] + entry
['address_range']))
669 ra_regnum
= entry
.cie
['return_address_register']
671 # Print the heading row for the decoded table
673 self
._emit
(' ' if entry
.structs
.address_size
== 4 else ' ')
676 # Decode the table nad look at the registers it describes.
677 # We build reg_order here to match readelf's order. In particular,
678 # registers are sorted by their number, and the register matching
679 # ra_regnum is always listed last with a special heading.
680 decoded_table
= entry
.get_decoded()
681 reg_order
= sorted(ifilter(
682 lambda r
: r
!= ra_regnum
,
683 decoded_table
.reg_order
))
685 # Headings for the registers
686 for regnum
in reg_order
:
687 self
._emit
('%-6s' % describe_reg_name(regnum
))
688 self
._emitline
('ra ')
690 # Now include ra_regnum in reg_order to print its values similarly
691 # to the other registers.
692 reg_order
.append(ra_regnum
)
693 for line
in decoded_table
.table
:
694 self
._emit
(self
._format
_hex
(
695 line
['pc'], fullhex
=True, lead0x
=False))
696 self
._emit
(' %-9s' % describe_CFI_CFA_rule(line
['cfa']))
698 for regnum
in reg_order
:
700 s
= describe_CFI_register_rule(line
[regnum
])
703 self
._emit
('%-6s' % s
)
707 def _emit(self
, s
=''):
708 """ Emit an object to output
710 self
.output
.write(str(s
))
712 def _emitline(self
, s
=''):
713 """ Emit an object to output, followed by a newline
715 self
.output
.write(str(s
) + '\n')
718 SCRIPT_DESCRIPTION
= 'Display information about the contents of ELF format files'
719 VERSION_STRING
= '%%prog: based on pyelftools %s' % __version__
722 def main(stream
=None):
723 # parse the command-line arguments and invoke ReadElf
724 optparser
= OptionParser(
725 usage
='usage: %prog [options] <elf-file>',
726 description
=SCRIPT_DESCRIPTION
,
727 add_help_option
=False, # -h is a real option of readelf
729 version
=VERSION_STRING
)
730 optparser
.add_option('-H', '--help',
731 action
='store_true', dest
='help',
732 help='Display this information')
733 optparser
.add_option('-h', '--file-header',
734 action
='store_true', dest
='show_file_header',
735 help='Display the ELF file header')
736 optparser
.add_option('-l', '--program-headers', '--segments',
737 action
='store_true', dest
='show_program_header',
738 help='Display the program headers')
739 optparser
.add_option('-S', '--section-headers', '--sections',
740 action
='store_true', dest
='show_section_header',
741 help="Display the sections' headers")
742 optparser
.add_option('-e', '--headers',
743 action
='store_true', dest
='show_all_headers',
744 help='Equivalent to: -h -l -S')
745 optparser
.add_option('-s', '--symbols', '--syms',
746 action
='store_true', dest
='show_symbols',
747 help='Display the symbol table')
748 optparser
.add_option('-r', '--relocs',
749 action
='store_true', dest
='show_relocs',
750 help='Display the relocations (if present)')
751 optparser
.add_option('-x', '--hex-dump',
752 action
='store', dest
='show_hex_dump', metavar
='<number|name>',
753 help='Dump the contents of section <number|name> as bytes')
754 optparser
.add_option('-p', '--string-dump',
755 action
='store', dest
='show_string_dump', metavar
='<number|name>',
756 help='Dump the contents of section <number|name> as strings')
757 optparser
.add_option('--debug-dump',
758 action
='store', dest
='debug_dump_what', metavar
='<what>',
760 'Display the contents of DWARF debug sections. <what> can ' +
761 'one of {info,decodedline,frames,frames-interp}'))
763 options
, args
= optparser
.parse_args()
765 if options
.help or len(args
) == 0:
766 optparser
.print_help()
769 if options
.show_all_headers
:
770 do_file_header
= do_section_header
= do_program_header
= True
772 do_file_header
= options
.show_file_header
773 do_section_header
= options
.show_section_header
774 do_program_header
= options
.show_program_header
776 with
open(args
[0], 'rb') as file:
778 readelf
= ReadElf(file, stream
or sys
.stdout
)
780 readelf
.display_file_header()
781 if do_section_header
:
782 readelf
.display_section_headers(
783 show_heading
=not do_file_header
)
784 if do_program_header
:
785 readelf
.display_program_headers(
786 show_heading
=not do_file_header
)
787 if options
.show_symbols
:
788 readelf
.display_symbol_tables()
789 if options
.show_relocs
:
790 readelf
.display_relocations()
791 if options
.show_hex_dump
:
792 readelf
.display_hex_dump(options
.show_hex_dump
)
793 if options
.show_string_dump
:
794 readelf
.display_string_dump(options
.show_string_dump
)
795 if options
.debug_dump_what
:
796 readelf
.display_debug_dump(options
.debug_dump_what
)
797 except ELFError
as ex
:
798 sys
.stderr
.write('ELF error: %s\n' % ex
)
803 # Run 'main' redirecting its output to readelfout.txt
804 # Saves profiling information in readelf.profile
805 PROFFILE
= 'readelf.profile'
807 cProfile
.run('main(open("readelfout.txt", "w"))', PROFFILE
)
809 # Dig in some profiling stats
811 p
= pstats
.Stats(PROFFILE
)
812 p
.sort_stats('cumulative').print_stats(25)
815 #-------------------------------------------------------------------------------
816 if __name__
== '__main__':