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():
547 # Unknown attribute values are passed-through as integers
548 if isinstance(name
, int):
549 name
= 'Unknown AT value: %x' % name
550 self
._emitline
(' <%2x> %-18s: %s' % (
554 attr
, die
, section_offset
)))
561 def _dump_debug_line_programs(self
):
562 """ Dump the (decoded) line programs from .debug_line
563 The programs are dumped in the order of the CUs they belong to.
565 self
._emitline
('Decoded dump of debug contents of section .debug_line:\n')
567 for cu
in self
._dwarfinfo
.iter_CUs():
568 lineprogram
= self
._dwarfinfo
.line_program_for_CU(cu
)
571 if len(lineprogram
['include_directory']) > 0:
572 cu_filename
= '%s/%s' % (
573 lineprogram
['include_directory'][0],
574 lineprogram
['file_entry'][0].name
)
576 cu_filename
= lineprogram
['file_entry'][0].name
578 self
._emitline
('CU: %s:' % cu_filename
)
579 self
._emitline
('File name Line number Starting address')
581 # Print each state's file, line and address information. For some
582 # instructions other output is needed to be compatible with
584 for entry
in lineprogram
.get_entries():
587 # Special handling for commands that don't set a new state
588 if entry
.command
== DW_LNS_set_file
:
589 file_entry
= lineprogram
['file_entry'][entry
.args
[0] - 1]
590 if file_entry
.dir_index
== 0:
592 self
._emitline
('\n./%s:[++]' % (
595 self
._emitline
('\n%s/%s:' % (
596 lineprogram
['include_directory'][file_entry
.dir_index
- 1],
598 elif entry
.command
== DW_LNE_define_file
:
599 self
._emitline
('%s:' % (
600 lineprogram
['include_directory'][entry
.args
[0].dir_index
]))
601 elif not state
.end_sequence
:
602 # readelf doesn't print the state after end_sequence
603 # instructions. I think it's a bug but to be compatible
604 # I don't print them too.
605 self
._emitline
('%-35s %11d %18s' % (
606 lineprogram
['file_entry'][state
.file - 1].name
,
608 '0' if state
.address
== 0 else
609 self
._format
_hex
(state
.address
)))
610 if entry
.command
== DW_LNS_copy
:
611 # Another readelf oddity...
614 def _dump_debug_frames(self
):
615 """ Dump the raw frame information from .debug_frame
617 if not self
._dwarfinfo
.has_CFI():
619 self
._emitline
('Contents of the .debug_frame section:')
621 for entry
in self
._dwarfinfo
.CFI_entries():
622 if isinstance(entry
, CIE
):
623 self
._emitline
('\n%08x %08x %08x CIE' % (
624 entry
.offset
, entry
['length'], entry
['CIE_id']))
625 self
._emitline
(' Version: %d' % entry
['version'])
626 self
._emitline
(' Augmentation: "%s"' % entry
['augmentation'])
627 self
._emitline
(' Code alignment factor: %u' % entry
['code_alignment_factor'])
628 self
._emitline
(' Data alignment factor: %d' % entry
['data_alignment_factor'])
629 self
._emitline
(' Return address column: %d' % entry
['return_address_register'])
632 self
._emitline
('\n%08x %08x %08x FDE cie=%08x pc=%08x..%08x' % (
635 entry
['CIE_pointer'],
637 entry
['initial_location'],
638 entry
['initial_location'] + entry
['address_range']))
640 self
._emit
(describe_CFI_instructions(entry
))
643 def _dump_debug_frames_interp(self
):
644 """ Dump the interpreted (decoded) frame information from .debug_frame
646 if not self
._dwarfinfo
.has_CFI():
649 self
._emitline
('Contents of the .debug_frame section:')
651 for entry
in self
._dwarfinfo
.CFI_entries():
652 if isinstance(entry
, CIE
):
653 self
._emitline
('\n%08x %08x %08x CIE "%s" cf=%d df=%d ra=%d' % (
657 entry
['augmentation'],
658 entry
['code_alignment_factor'],
659 entry
['data_alignment_factor'],
660 entry
['return_address_register']))
661 ra_regnum
= entry
['return_address_register']
663 self
._emitline
('\n%08x %08x %08x FDE cie=%08x pc=%08x..%08x' % (
666 entry
['CIE_pointer'],
668 entry
['initial_location'],
669 entry
['initial_location'] + entry
['address_range']))
670 ra_regnum
= entry
.cie
['return_address_register']
672 # Print the heading row for the decoded table
674 self
._emit
(' ' if entry
.structs
.address_size
== 4 else ' ')
677 # Decode the table nad look at the registers it describes.
678 # We build reg_order here to match readelf's order. In particular,
679 # registers are sorted by their number, and the register matching
680 # ra_regnum is always listed last with a special heading.
681 decoded_table
= entry
.get_decoded()
682 reg_order
= sorted(ifilter(
683 lambda r
: r
!= ra_regnum
,
684 decoded_table
.reg_order
))
686 # Headings for the registers
687 for regnum
in reg_order
:
688 self
._emit
('%-6s' % describe_reg_name(regnum
))
689 self
._emitline
('ra ')
691 # Now include ra_regnum in reg_order to print its values similarly
692 # to the other registers.
693 reg_order
.append(ra_regnum
)
694 for line
in decoded_table
.table
:
695 self
._emit
(self
._format
_hex
(
696 line
['pc'], fullhex
=True, lead0x
=False))
697 self
._emit
(' %-9s' % describe_CFI_CFA_rule(line
['cfa']))
699 for regnum
in reg_order
:
701 s
= describe_CFI_register_rule(line
[regnum
])
704 self
._emit
('%-6s' % s
)
708 def _emit(self
, s
=''):
709 """ Emit an object to output
711 self
.output
.write(str(s
))
713 def _emitline(self
, s
=''):
714 """ Emit an object to output, followed by a newline
716 self
.output
.write(str(s
) + '\n')
719 SCRIPT_DESCRIPTION
= 'Display information about the contents of ELF format files'
720 VERSION_STRING
= '%%prog: based on pyelftools %s' % __version__
723 def main(stream
=None):
724 # parse the command-line arguments and invoke ReadElf
725 optparser
= OptionParser(
726 usage
='usage: %prog [options] <elf-file>',
727 description
=SCRIPT_DESCRIPTION
,
728 add_help_option
=False, # -h is a real option of readelf
730 version
=VERSION_STRING
)
731 optparser
.add_option('-H', '--help',
732 action
='store_true', dest
='help',
733 help='Display this information')
734 optparser
.add_option('-h', '--file-header',
735 action
='store_true', dest
='show_file_header',
736 help='Display the ELF file header')
737 optparser
.add_option('-l', '--program-headers', '--segments',
738 action
='store_true', dest
='show_program_header',
739 help='Display the program headers')
740 optparser
.add_option('-S', '--section-headers', '--sections',
741 action
='store_true', dest
='show_section_header',
742 help="Display the sections' headers")
743 optparser
.add_option('-e', '--headers',
744 action
='store_true', dest
='show_all_headers',
745 help='Equivalent to: -h -l -S')
746 optparser
.add_option('-s', '--symbols', '--syms',
747 action
='store_true', dest
='show_symbols',
748 help='Display the symbol table')
749 optparser
.add_option('-r', '--relocs',
750 action
='store_true', dest
='show_relocs',
751 help='Display the relocations (if present)')
752 optparser
.add_option('-x', '--hex-dump',
753 action
='store', dest
='show_hex_dump', metavar
='<number|name>',
754 help='Dump the contents of section <number|name> as bytes')
755 optparser
.add_option('-p', '--string-dump',
756 action
='store', dest
='show_string_dump', metavar
='<number|name>',
757 help='Dump the contents of section <number|name> as strings')
758 optparser
.add_option('--debug-dump',
759 action
='store', dest
='debug_dump_what', metavar
='<section>',
760 help='Display the contents of DWARF debug sections')
762 options
, args
= optparser
.parse_args()
764 if options
.help or len(args
) == 0:
765 optparser
.print_help()
768 if options
.show_all_headers
:
769 do_file_header
= do_section_header
= do_program_header
= True
771 do_file_header
= options
.show_file_header
772 do_section_header
= options
.show_section_header
773 do_program_header
= options
.show_program_header
775 with
open(args
[0], 'rb') as file:
777 readelf
= ReadElf(file, stream
or sys
.stdout
)
779 readelf
.display_file_header()
780 if do_section_header
:
781 readelf
.display_section_headers(
782 show_heading
=not do_file_header
)
783 if do_program_header
:
784 readelf
.display_program_headers(
785 show_heading
=not do_file_header
)
786 if options
.show_symbols
:
787 readelf
.display_symbol_tables()
788 if options
.show_relocs
:
789 readelf
.display_relocations()
790 if options
.show_hex_dump
:
791 readelf
.display_hex_dump(options
.show_hex_dump
)
792 if options
.show_string_dump
:
793 readelf
.display_string_dump(options
.show_string_dump
)
794 if options
.debug_dump_what
:
795 readelf
.display_debug_dump(options
.debug_dump_what
)
796 except ELFError
as ex
:
797 sys
.stderr
.write('ELF error: %s\n' % ex
)
802 # Run 'main' redirecting its output to readelfout.txt
803 # Saves profiling information in readelf.profile
804 PROFFILE
= 'readelf.profile'
806 cProfile
.run('main(open("readelfout.txt", "w"))', PROFFILE
)
808 # Dig in some profiling stats
810 p
= pstats
.Stats(PROFFILE
)
811 p
.sort_stats('cumulative').print_stats(25)
814 #-------------------------------------------------------------------------------
815 if __name__
== '__main__':