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
12 from itertools
import ifilter
16 # If elftools is not installed, maybe we're running from the root or scripts
17 # dir of the source distribution
22 sys
.path
.extend(['.', '..'])
24 from elftools
import __version__
25 from elftools
.common
.exceptions
import ELFError
26 from elftools
.elf
.elffile
import ELFFile
27 from elftools
.elf
.segments
import InterpSegment
28 from elftools
.elf
.sections
import SymbolTableSection
29 from elftools
.elf
.relocation
import RelocationSection
30 from elftools
.elf
.descriptions
import (
31 describe_ei_class
, describe_ei_data
, describe_ei_version
,
32 describe_ei_osabi
, describe_e_type
, describe_e_machine
,
33 describe_e_version_numeric
, describe_p_type
, describe_p_flags
,
34 describe_sh_type
, describe_sh_flags
,
35 describe_symbol_type
, describe_symbol_bind
, describe_symbol_visibility
,
36 describe_symbol_shndx
, describe_reloc_type
,
38 from elftools
.dwarf
.dwarfinfo
import DWARFInfo
39 from elftools
.dwarf
.descriptions
import (
40 describe_reg_name
, describe_attr_value
, set_global_machine_arch
,
41 describe_CFI_instructions
, describe_CFI_register_rule
,
42 describe_CFI_CFA_rule
,
44 from elftools
.dwarf
.constants
import (
45 DW_LNS_copy
, DW_LNS_set_file
, DW_LNE_define_file
)
46 from elftools
.dwarf
.callframe
import CIE
, FDE
49 class ReadElf(object):
50 """ display_* methods are used to emit output into the output stream
52 def __init__(self
, file, output
):
54 stream object with the ELF file to read
57 output stream to write to
59 self
.elffile
= ELFFile(file)
62 # Lazily initialized if a debug dump is requested
63 self
._dwarfinfo
= None
65 def display_file_header(self
):
66 """ Display the ELF file header
68 self
._emitline
('ELF Header:')
69 self
._emit
(' Magic: ')
70 self
._emitline
(' '.join('%2.2x' % ord(b
)
71 for b
in self
.elffile
.e_ident_raw
))
72 header
= self
.elffile
.header
73 e_ident
= header
['e_ident']
74 self
._emitline
(' Class: %s' %
75 describe_ei_class(e_ident
['EI_CLASS']))
76 self
._emitline
(' Data: %s' %
77 describe_ei_data(e_ident
['EI_DATA']))
78 self
._emitline
(' Version: %s' %
79 describe_ei_version(e_ident
['EI_VERSION']))
80 self
._emitline
(' OS/ABI: %s' %
81 describe_ei_osabi(e_ident
['EI_OSABI']))
82 self
._emitline
(' ABI Version: %d' %
83 e_ident
['EI_ABIVERSION'])
84 self
._emitline
(' Type: %s' %
85 describe_e_type(header
['e_type']))
86 self
._emitline
(' Machine: %s' %
87 describe_e_machine(header
['e_machine']))
88 self
._emitline
(' Version: %s' %
89 describe_e_version_numeric(header
['e_version']))
90 self
._emitline
(' Entry point address: %s' %
91 self
._format
_hex
(header
['e_entry']))
92 self
._emit
(' Start of program headers: %s' %
94 self
._emitline
(' (bytes into file)')
95 self
._emit
(' Start of section headers: %s' %
97 self
._emitline
(' (bytes into file)')
98 self
._emitline
(' Flags: %s' %
99 self
._format
_hex
(header
['e_flags']))
100 self
._emitline
(' Size of this header: %s (bytes)' %
102 self
._emitline
(' Size of program headers: %s (bytes)' %
103 header
['e_phentsize'])
104 self
._emitline
(' Number of program headers: %s' %
106 self
._emitline
(' Size of section headers: %s (bytes)' %
107 header
['e_shentsize'])
108 self
._emitline
(' Number of section headers: %s' %
110 self
._emitline
(' Section header string table index: %s' %
111 header
['e_shstrndx'])
113 def display_program_headers(self
, show_heading
=True):
114 """ Display the ELF program headers.
115 If show_heading is True, displays the heading for this information
116 (Elf file type is...)
119 if self
.elffile
.num_segments() == 0:
120 self
._emitline
('There are no program headers in this file.')
123 elfheader
= self
.elffile
.header
125 self
._emitline
('Elf file type is %s' %
126 describe_e_type(elfheader
['e_type']))
127 self
._emitline
('Entry point is %s' %
128 self
._format
_hex
(elfheader
['e_entry']))
129 # readelf weirness - why isn't e_phoff printed as hex? (for section
131 self
._emitline
('There are %s program headers, starting at offset %s' % (
132 elfheader
['e_phnum'], elfheader
['e_phoff']))
135 self
._emitline
('Program Headers:')
137 # Now comes the table of program headers with their attributes. Note
138 # that due to different formatting constraints of 32-bit and 64-bit
139 # addresses, there are some conditions on elfclass here.
141 # First comes the table heading
143 if self
.elffile
.elfclass
== 32:
144 self
._emitline
(' Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align')
146 self
._emitline
(' Type Offset VirtAddr PhysAddr')
147 self
._emitline
(' FileSiz MemSiz Flags Align')
151 for segment
in self
.elffile
.iter_segments():
152 self
._emit
(' %-14s ' % describe_p_type(segment
['p_type']))
154 if self
.elffile
.elfclass
== 32:
155 self
._emitline
('%s %s %s %s %s %-3s %s' % (
156 self
._format
_hex
(segment
['p_offset'], fieldsize
=6),
157 self
._format
_hex
(segment
['p_vaddr'], fullhex
=True),
158 self
._format
_hex
(segment
['p_paddr'], fullhex
=True),
159 self
._format
_hex
(segment
['p_filesz'], fieldsize
=5),
160 self
._format
_hex
(segment
['p_memsz'], fieldsize
=5),
161 describe_p_flags(segment
['p_flags']),
162 self
._format
_hex
(segment
['p_align'])))
164 self
._emitline
('%s %s %s' % (
165 self
._format
_hex
(segment
['p_offset'], fullhex
=True),
166 self
._format
_hex
(segment
['p_vaddr'], fullhex
=True),
167 self
._format
_hex
(segment
['p_paddr'], fullhex
=True)))
168 self
._emitline
(' %s %s %-3s %s' % (
169 self
._format
_hex
(segment
['p_filesz'], fullhex
=True),
170 self
._format
_hex
(segment
['p_memsz'], fullhex
=True),
171 describe_p_flags(segment
['p_flags']),
172 # lead0x set to False for p_align, to mimic readelf.
173 # No idea why the difference from 32-bit mode :-|
174 self
._format
_hex
(segment
['p_align'], lead0x
=False)))
176 if isinstance(segment
, InterpSegment
):
177 self
._emitline
(' [Requesting program interpreter: %s]' %
178 segment
.get_interp_name())
180 # Sections to segments mapping
182 if self
.elffile
.num_sections() == 0:
183 # No sections? We're done
186 self
._emitline
('\n Section to Segment mapping:')
187 self
._emitline
(' Segment Sections...')
189 for nseg
, segment
in enumerate(self
.elffile
.iter_segments()):
190 self
._emit
(' %2.2d ' % nseg
)
192 for section
in self
.elffile
.iter_sections():
193 if ( not section
.is_null() and
194 segment
.section_in_segment(section
)):
195 self
._emit
('%s ' % section
.name
)
199 def display_section_headers(self
, show_heading
=True):
200 """ Display the ELF section headers
202 elfheader
= self
.elffile
.header
204 self
._emitline
('There are %s section headers, starting at offset %s' % (
205 elfheader
['e_shnum'], self
._format
_hex
(elfheader
['e_shoff'])))
207 self
._emitline
('\nSection Header%s:' % (
208 's' if elfheader
['e_shnum'] > 1 else ''))
210 # Different formatting constraints of 32-bit and 64-bit addresses
212 if self
.elffile
.elfclass
== 32:
213 self
._emitline
(' [Nr] Name Type Addr Off Size ES Flg Lk Inf Al')
215 self
._emitline
(' [Nr] Name Type Address Offset')
216 self
._emitline
(' Size EntSize Flags Link Info Align')
220 for nsec
, section
in enumerate(self
.elffile
.iter_sections()):
221 self
._emit
(' [%2u] %-17.17s %-15.15s ' % (
222 nsec
, section
.name
, describe_sh_type(section
['sh_type'])))
224 if self
.elffile
.elfclass
== 32:
225 self
._emitline
('%s %s %s %s %3s %2s %3s %2s' % (
226 self
._format
_hex
(section
['sh_addr'], fieldsize
=8, lead0x
=False),
227 self
._format
_hex
(section
['sh_offset'], fieldsize
=6, lead0x
=False),
228 self
._format
_hex
(section
['sh_size'], fieldsize
=6, lead0x
=False),
229 self
._format
_hex
(section
['sh_entsize'], fieldsize
=2, lead0x
=False),
230 describe_sh_flags(section
['sh_flags']),
231 section
['sh_link'], section
['sh_info'],
232 section
['sh_addralign']))
234 self
._emitline
(' %s %s' % (
235 self
._format
_hex
(section
['sh_addr'], fullhex
=True, lead0x
=False),
236 self
._format
_hex
(section
['sh_offset'],
237 fieldsize
=16 if section
['sh_offset'] > 0xffffffff else 8,
239 self
._emitline
(' %s %s %3s %2s %3s %s' % (
240 self
._format
_hex
(section
['sh_size'], fullhex
=True, lead0x
=False),
241 self
._format
_hex
(section
['sh_entsize'], fullhex
=True, lead0x
=False),
242 describe_sh_flags(section
['sh_flags']),
243 section
['sh_link'], section
['sh_info'],
244 section
['sh_addralign']))
246 self
._emitline
('Key to Flags:')
247 self
._emit
(' W (write), A (alloc), X (execute), M (merge), S (strings)')
248 if self
.elffile
['e_machine'] in ('EM_X86_64', 'EM_L10M'):
249 self
._emitline
(', l (large)')
252 self
._emitline
(' I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)')
253 self
._emitline
(' O (extra OS processing required) o (OS specific), p (processor specific)')
255 def display_symbol_tables(self
):
256 """ Display the symbol tables contained in the file
258 for section
in self
.elffile
.iter_sections():
259 if not isinstance(section
, SymbolTableSection
):
262 if section
['sh_entsize'] == 0:
263 self
._emitline
("\nSymbol table '%s' has a sh_entsize of zero!" % (
267 self
._emitline
("\nSymbol table '%s' contains %s entries:" % (
268 section
.name
, section
.num_symbols()))
270 if self
.elffile
.elfclass
== 32:
271 self
._emitline
(' Num: Value Size Type Bind Vis Ndx Name')
273 self
._emitline
(' Num: Value Size Type Bind Vis Ndx Name')
275 for nsym
, symbol
in enumerate(section
.iter_symbols()):
276 # symbol names are truncated to 25 chars, similarly to readelf
277 self
._emitline
('%6d: %s %5d %-7s %-6s %-7s %4s %.25s' % (
279 self
._format
_hex
(symbol
['st_value'], fullhex
=True, lead0x
=False),
281 describe_symbol_type(symbol
['st_info']['type']),
282 describe_symbol_bind(symbol
['st_info']['bind']),
283 describe_symbol_visibility(symbol
['st_other']['visibility']),
284 describe_symbol_shndx(symbol
['st_shndx']),
287 def display_relocations(self
):
288 """ Display the relocations contained in the file
290 has_relocation_sections
= False
291 for section
in self
.elffile
.iter_sections():
292 if not isinstance(section
, RelocationSection
):
295 has_relocation_sections
= True
296 self
._emitline
("\nRelocation section '%s' at offset %s contains %s entries:" % (
298 self
._format
_hex
(section
['sh_offset']),
299 section
.num_relocations()))
300 if section
.is_RELA():
301 self
._emitline
(" Offset Info Type Sym. Value Sym. Name + Addend")
303 self
._emitline
(" Offset Info Type Sym.Value Sym. Name")
305 # The symbol table section pointed to in sh_link
306 symtable
= self
.elffile
.get_section(section
['sh_link'])
308 for rel
in section
.iter_relocations():
309 hexwidth
= 8 if self
.elffile
.elfclass
== 32 else 12
310 self
._emit
('%s %s %-17.17s' % (
311 self
._format
_hex
(rel
['r_offset'],
312 fieldsize
=hexwidth
, lead0x
=False),
313 self
._format
_hex
(rel
['r_info'],
314 fieldsize
=hexwidth
, lead0x
=False),
316 rel
['r_info_type'], self
.elffile
)))
318 if rel
['r_info_sym'] == 0:
322 symbol
= symtable
.get_symbol(rel
['r_info_sym'])
323 # Some symbols have zero 'st_name', so instead what's used is
324 # the name of the section they point at
325 if symbol
['st_name'] == 0:
326 symsec
= self
.elffile
.get_section(symbol
['st_shndx'])
327 symbol_name
= symsec
.name
329 symbol_name
= symbol
.name
330 self
._emit
(' %s %s%22.22s' % (
333 fullhex
=True, lead0x
=False),
334 ' ' if self
.elffile
.elfclass
== 32 else '',
336 if section
.is_RELA():
337 self
._emit
(' %s %x' % (
338 '+' if rel
['r_addend'] >= 0 else '-',
339 abs(rel
['r_addend'])))
342 if not has_relocation_sections
:
343 self
._emitline
('\nThere are no relocations in this file.')
345 def display_hex_dump(self
, section_spec
):
346 """ Display a hex dump of a section. section_spec is either a section
349 section
= self
._section
_from
_spec
(section_spec
)
351 self
._emitline
("Section '%s' does not exist in the file!" % (
355 self
._emitline
("\nHex dump of section '%s':" % section
.name
)
356 self
._note
_relocs
_for
_section
(section
)
357 addr
= section
['sh_addr']
358 data
= section
.data()
361 while dataptr
< len(data
):
362 bytesleft
= len(data
) - dataptr
363 # chunks of 16 bytes per line
364 linebytes
= 16 if bytesleft
> 16 else bytesleft
366 self
._emit
(' %s ' % self
._format
_hex
(addr
, fieldsize
=8))
369 self
._emit
('%2.2x' % ord(data
[dataptr
+ i
]))
375 for i
in range(linebytes
):
376 c
= data
[dataptr
+ i
]
377 if c
>= ' ' and ord(c
) < 0x7f:
388 def display_string_dump(self
, section_spec
):
389 """ Display a strings dump of a section. section_spec is either a
390 section number or a name.
392 section
= self
._section
_from
_spec
(section_spec
)
394 self
._emitline
("Section '%s' does not exist in the file!" % (
398 printables
= set(string
.printable
)
399 self
._emitline
("\nString dump of section '%s':" % section
.name
)
402 data
= section
.data()
405 while dataptr
< len(data
):
406 while dataptr
< len(data
) and data
[dataptr
] not in printables
:
409 if dataptr
>= len(data
):
413 while endptr
< len(data
) and data
[endptr
] != '\x00':
417 self
._emitline
(' [%6x] %s' % (
418 dataptr
, data
[dataptr
:endptr
]))
423 self
._emitline
(' No strings found in this section.')
427 def display_debug_dump(self
, dump_what
):
428 """ Dump a DWARF section
430 self
._init
_dwarfinfo
()
431 if self
._dwarfinfo
is None:
434 set_global_machine_arch(self
.elffile
.get_machine_arch())
436 if dump_what
== 'info':
437 self
._dump
_debug
_info
()
438 elif dump_what
== 'decodedline':
439 self
._dump
_debug
_line
_programs
()
440 elif dump_what
== 'frames':
441 self
._dump
_debug
_frames
()
442 elif dump_what
== 'frames-interp':
443 self
._dump
_debug
_frames
_interp
()
445 self
._emitline
('debug dump not yet supported for "%s"' % dump_what
)
447 def _format_hex(self
, addr
, fieldsize
=None, fullhex
=False, lead0x
=True):
448 """ Format an address into a hexadecimal string.
451 Size of the hexadecimal field (with leading zeros to fit the
452 address into. For example with fieldsize=8, the format will
454 If None, the minimal required field size will be used.
457 If True, override fieldsize to set it to the maximal size
458 needed for the elfclass
461 If True, leading 0x is added
463 s
= '0x' if lead0x
else ''
465 fieldsize
= 8 if self
.elffile
.elfclass
== 32 else 16
466 if fieldsize
is None:
469 field
= '%' + '0%sx' % fieldsize
470 return s
+ field
% addr
472 def _section_from_spec(self
, spec
):
473 """ Retrieve a section given a "spec" (either number or name).
474 Return None if no such section exists in the file.
478 if num
< self
.elffile
.num_sections():
479 return self
.elffile
.get_section(num
)
483 # Not a number. Must be a name then
484 return self
.elffile
.get_section_by_name(spec
)
486 def _note_relocs_for_section(self
, section
):
487 """ If there are relocation sections pointing to the givne section,
488 emit a note about it.
490 for relsec
in self
.elffile
.iter_sections():
491 if isinstance(relsec
, RelocationSection
):
492 info_idx
= relsec
['sh_info']
493 if self
.elffile
.get_section(info_idx
) == section
:
494 self
._emitline
(' Note: This section has relocations against it, but these have NOT been applied to this dump.')
497 def _init_dwarfinfo(self
):
498 """ Initialize the DWARF info contained in the file and assign it to
500 Leave self._dwarfinfo at None if no DWARF info was found in the file
502 if self
._dwarfinfo
is not None:
505 if self
.elffile
.has_dwarf_info():
506 self
._dwarfinfo
= self
.elffile
.get_dwarf_info()
508 self
._dwarfinfo
= None
510 def _dump_debug_info(self
):
511 """ Dump the debugging info section.
513 self
._emitline
('Contents of the .debug_info section:\n')
515 # Offset of the .debug_info section in the stream
516 section_offset
= self
._dwarfinfo
.debug_info_sec
.global_offset
518 for cu
in self
._dwarfinfo
.iter_CUs():
519 self
._emitline
(' Compilation Unit @ offset %s:' %
520 self
._format
_hex
(cu
.cu_offset
))
521 self
._emitline
(' Length: %s (%s)' % (
522 self
._format
_hex
(cu
['unit_length']),
523 '%s-bit' % cu
.dwarf_format()))
524 self
._emitline
(' Version: %s' % cu
['version']),
525 self
._emitline
(' Abbrev Offset: %s' % cu
['debug_abbrev_offset']),
526 self
._emitline
(' Pointer Size: %s' % cu
['address_size'])
528 # The nesting depth of each DIE within the tree of DIEs must be
529 # displayed. To implement this, a counter is incremented each time
530 # the current DIE has children, and decremented when a null die is
531 # encountered. Due to the way the DIE tree is serialized, this will
532 # correctly reflect the nesting depth
535 for die
in cu
.iter_DIEs():
539 self
._emitline
(' <%s><%x>: Abbrev Number: %s (%s)' % (
545 for attr
in die
.attributes
.itervalues():
546 self
._emitline
(' <%2x> %-18s: %s' % (
550 attr
, die
, section_offset
)))
557 def _dump_debug_line_programs(self
):
558 """ Dump the (decoded) line programs from .debug_line
559 The programs are dumped in the order of the CUs they belong to.
561 self
._emitline
('Decoded dump of debug contents of section .debug_line:\n')
563 for cu
in self
._dwarfinfo
.iter_CUs():
564 lineprogram
= self
._dwarfinfo
.line_program_for_CU(cu
)
567 if len(lineprogram
['include_directory']) > 0:
568 cu_filename
= '%s/%s' % (
569 lineprogram
['include_directory'][0],
570 lineprogram
['file_entry'][0].name
)
572 cu_filename
= lineprogram
['file_entry'][0].name
574 self
._emitline
('CU: %s:' % cu_filename
)
575 self
._emitline
('File name Line number Starting address')
577 # Print each state's file, line and address information. For some
578 # instructions other output is needed to be compatible with
580 for entry
in lineprogram
.get_entries():
583 # Special handling for commands that don't set a new state
584 if entry
.command
== DW_LNS_set_file
:
585 file_entry
= lineprogram
['file_entry'][entry
.args
[0] - 1]
586 if file_entry
.dir_index
== 0:
588 self
._emitline
('\n./%s:[++]' % (
591 self
._emitline
('\n%s/%s:' % (
592 lineprogram
['include_directory'][file_entry
.dir_index
- 1],
594 elif entry
.command
== DW_LNE_define_file
:
595 self
._emitline
('%s:' % (
596 lineprogram
['include_directory'][entry
.args
[0].dir_index
]))
597 elif not state
.end_sequence
:
598 # readelf doesn't print the state after end_sequence
599 # instructions. I think it's a bug but to be compatible
600 # I don't print them too.
601 self
._emitline
('%-35s %11d %18s' % (
602 lineprogram
['file_entry'][state
.file - 1].name
,
604 '0' if state
.address
== 0 else
605 self
._format
_hex
(state
.address
)))
606 if entry
.command
== DW_LNS_copy
:
607 # Another readelf oddity...
610 def _dump_debug_frames(self
):
611 """ Dump the raw frame information from .debug_frame
613 if not self
._dwarfinfo
.has_CFI():
615 self
._emitline
('Contents of the .debug_frame section:')
617 for entry
in self
._dwarfinfo
.CFI_entries():
618 if isinstance(entry
, CIE
):
619 self
._emitline
('\n%08x %08x %08x CIE' % (
620 entry
.offset
, entry
['length'], entry
['CIE_id']))
621 self
._emitline
(' Version: %d' % entry
['version'])
622 self
._emitline
(' Augmentation: "%s"' % entry
['augmentation'])
623 self
._emitline
(' Code alignment factor: %u' % entry
['code_alignment_factor'])
624 self
._emitline
(' Data alignment factor: %d' % entry
['data_alignment_factor'])
625 self
._emitline
(' Return address column: %d' % entry
['return_address_register'])
628 self
._emitline
('\n%08x %08x %08x FDE cie=%08x pc=%08x..%08x' % (
631 entry
['CIE_pointer'],
633 entry
['initial_location'],
634 entry
['initial_location'] + entry
['address_range']))
636 self
._emit
(describe_CFI_instructions(entry
))
639 def _dump_debug_frames_interp(self
):
640 """ Dump the interpreted (decoded) frame information from .debug_frame
642 if not self
._dwarfinfo
.has_CFI():
645 self
._emitline
('Contents of the .debug_frame section:')
647 for entry
in self
._dwarfinfo
.CFI_entries():
648 if isinstance(entry
, CIE
):
649 self
._emitline
('\n%08x %08x %08x CIE "%s" cf=%d df=%d ra=%d' % (
653 entry
['augmentation'],
654 entry
['code_alignment_factor'],
655 entry
['data_alignment_factor'],
656 entry
['return_address_register']))
657 ra_regnum
= entry
['return_address_register']
659 self
._emitline
('\n%08x %08x %08x FDE cie=%08x pc=%08x..%08x' % (
662 entry
['CIE_pointer'],
664 entry
['initial_location'],
665 entry
['initial_location'] + entry
['address_range']))
666 ra_regnum
= entry
.cie
['return_address_register']
668 # Print the heading row for the decoded table
670 self
._emit
(' ' if entry
.structs
.address_size
== 4 else ' ')
673 # Decode the table nad look at the registers it describes.
674 # We build reg_order here to match readelf's order. In particular,
675 # registers are sorted by their number, and the register matching
676 # ra_regnum is always listed last with a special heading.
677 decoded_table
= entry
.get_decoded()
678 reg_order
= sorted(ifilter(
679 lambda r
: r
!= ra_regnum
,
680 decoded_table
.reg_order
))
682 # Headings for the registers
683 for regnum
in reg_order
:
684 self
._emit
('%-6s' % describe_reg_name(regnum
))
685 self
._emitline
('ra ')
687 # Now include ra_regnum in reg_order to print its values similarly
688 # to the other registers.
689 reg_order
.append(ra_regnum
)
690 for line
in decoded_table
.table
:
691 self
._emit
(self
._format
_hex
(
692 line
['pc'], fullhex
=True, lead0x
=False))
693 self
._emit
(' %-9s' % describe_CFI_CFA_rule(line
['cfa']))
695 for regnum
in reg_order
:
697 s
= describe_CFI_register_rule(line
[regnum
])
700 self
._emit
('%-6s' % s
)
704 def _emit(self
, s
=''):
705 """ Emit an object to output
707 self
.output
.write(str(s
))
709 def _emitline(self
, s
=''):
710 """ Emit an object to output, followed by a newline
712 self
.output
.write(str(s
) + '\n')
715 SCRIPT_DESCRIPTION
= 'Display information about the contents of ELF format files'
716 VERSION_STRING
= '%%prog: based on pyelftools %s' % __version__
719 def main(stream
=None):
720 # parse the command-line arguments and invoke ReadElf
721 optparser
= OptionParser(
722 usage
='usage: %prog [options] <elf-file>',
723 description
=SCRIPT_DESCRIPTION
,
724 add_help_option
=False, # -h is a real option of readelf
726 version
=VERSION_STRING
)
727 optparser
.add_option('-H', '--help',
728 action
='store_true', dest
='help',
729 help='Display this information')
730 optparser
.add_option('-h', '--file-header',
731 action
='store_true', dest
='show_file_header',
732 help='Display the ELF file header')
733 optparser
.add_option('-l', '--program-headers', '--segments',
734 action
='store_true', dest
='show_program_header',
735 help='Display the program headers')
736 optparser
.add_option('-S', '--section-headers', '--sections',
737 action
='store_true', dest
='show_section_header',
738 help="Display the sections' headers")
739 optparser
.add_option('-e', '--headers',
740 action
='store_true', dest
='show_all_headers',
741 help='Equivalent to: -h -l -S')
742 optparser
.add_option('-s', '--symbols', '--syms',
743 action
='store_true', dest
='show_symbols',
744 help='Display the symbol table')
745 optparser
.add_option('-r', '--relocs',
746 action
='store_true', dest
='show_relocs',
747 help='Display the relocations (if present)')
748 optparser
.add_option('-x', '--hex-dump',
749 action
='store', dest
='show_hex_dump', metavar
='<number|name>',
750 help='Dump the contents of section <number|name> as bytes')
751 optparser
.add_option('-p', '--string-dump',
752 action
='store', dest
='show_string_dump', metavar
='<number|name>',
753 help='Dump the contents of section <number|name> as strings')
754 optparser
.add_option('--debug-dump',
755 action
='store', dest
='debug_dump_what', metavar
='<section>',
756 help='Display the contents of DWARF debug sections')
758 options
, args
= optparser
.parse_args()
760 if options
.help or len(args
) == 0:
761 optparser
.print_help()
764 if options
.show_all_headers
:
765 do_file_header
= do_section_header
= do_program_header
= True
767 do_file_header
= options
.show_file_header
768 do_section_header
= options
.show_section_header
769 do_program_header
= options
.show_program_header
771 with
open(args
[0], 'rb') as file:
773 readelf
= ReadElf(file, stream
or sys
.stdout
)
775 readelf
.display_file_header()
776 if do_section_header
:
777 readelf
.display_section_headers(
778 show_heading
=not do_file_header
)
779 if do_program_header
:
780 readelf
.display_program_headers(
781 show_heading
=not do_file_header
)
782 if options
.show_symbols
:
783 readelf
.display_symbol_tables()
784 if options
.show_relocs
:
785 readelf
.display_relocations()
786 if options
.show_hex_dump
:
787 readelf
.display_hex_dump(options
.show_hex_dump
)
788 if options
.show_string_dump
:
789 readelf
.display_string_dump(options
.show_string_dump
)
790 if options
.debug_dump_what
:
791 readelf
.display_debug_dump(options
.debug_dump_what
)
792 except ELFError
as ex
:
793 sys
.stderr
.write('ELF error: %s\n' % ex
)
798 # Run 'main' redirecting its output to readelfout.txt
799 # Saves profiling information in readelf.profile
800 PROFFILE
= 'readelf.profile'
802 cProfile
.run('main(open("readelfout.txt", "w"))', PROFFILE
)
804 # Dig in some profiling stats
806 p
= pstats
.Stats(PROFFILE
)
807 p
.sort_stats('cumulative').print_stats(25)
810 #-------------------------------------------------------------------------------
811 if __name__
== '__main__':