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
15 # If elftools is not installed, maybe we're running from the root or scripts
16 # dir of the source distribution
20 sys
.path
.extend(['.', '..'])
22 from elftools
import __version__
23 from elftools
.common
.exceptions
import ELFError
24 from elftools
.elf
.elffile
import ELFFile
25 from elftools
.elf
.segments
import InterpSegment
26 from elftools
.elf
.sections
import SymbolTableSection
27 from elftools
.elf
.relocation
import RelocationSection
28 from elftools
.elf
.descriptions
import (
29 describe_ei_class
, describe_ei_data
, describe_ei_version
,
30 describe_ei_osabi
, describe_e_type
, describe_e_machine
,
31 describe_e_version_numeric
, describe_p_type
, describe_p_flags
,
32 describe_sh_type
, describe_sh_flags
,
33 describe_symbol_type
, describe_symbol_bind
, describe_symbol_visibility
,
34 describe_symbol_shndx
, describe_reloc_type
,
36 from elftools
.dwarf
.dwarfinfo
import DWARFInfo
37 from elftools
.dwarf
.descriptions
import (
38 describe_reg_name
, describe_attr_value
, set_global_machine_arch
,
39 describe_CFI_instructions
, describe_CFI_register_rule
,
40 describe_CFI_CFA_rule
,
42 from elftools
.dwarf
.constants
import (
43 DW_LNS_copy
, DW_LNS_set_file
, DW_LNE_define_file
)
44 from elftools
.dwarf
.callframe
import CIE
, FDE
47 class ReadElf(object):
48 """ display_* methods are used to emit output into the output stream
50 def __init__(self
, file, output
):
52 stream object with the ELF file to read
55 output stream to write to
57 self
.elffile
= ELFFile(file)
60 # Lazily initialized if a debug dump is requested
61 self
._dwarfinfo
= None
63 def display_file_header(self
):
64 """ Display the ELF file header
66 self
._emitline
('ELF Header:')
67 self
._emit
(' Magic: ')
68 self
._emitline
(' '.join('%2.2x' % ord(b
)
69 for b
in self
.elffile
.e_ident_raw
))
70 header
= self
.elffile
.header
71 e_ident
= header
['e_ident']
72 self
._emitline
(' Class: %s' %
73 describe_ei_class(e_ident
['EI_CLASS']))
74 self
._emitline
(' Data: %s' %
75 describe_ei_data(e_ident
['EI_DATA']))
76 self
._emitline
(' Version: %s' %
77 describe_ei_version(e_ident
['EI_VERSION']))
78 self
._emitline
(' OS/ABI: %s' %
79 describe_ei_osabi(e_ident
['EI_OSABI']))
80 self
._emitline
(' ABI Version: %d' %
81 e_ident
['EI_ABIVERSION'])
82 self
._emitline
(' Type: %s' %
83 describe_e_type(header
['e_type']))
84 self
._emitline
(' Machine: %s' %
85 describe_e_machine(header
['e_machine']))
86 self
._emitline
(' Version: %s' %
87 describe_e_version_numeric(header
['e_version']))
88 self
._emitline
(' Entry point address: %s' %
89 self
._format
_hex
(header
['e_entry']))
90 self
._emit
(' Start of program headers: %s' %
92 self
._emitline
(' (bytes into file)')
93 self
._emit
(' Start of section headers: %s' %
95 self
._emitline
(' (bytes into file)')
96 self
._emitline
(' Flags: %s' %
97 self
._format
_hex
(header
['e_flags']))
98 self
._emitline
(' Size of this header: %s (bytes)' %
100 self
._emitline
(' Size of program headers: %s (bytes)' %
101 header
['e_phentsize'])
102 self
._emitline
(' Number of program headers: %s' %
104 self
._emitline
(' Size of section headers: %s (bytes)' %
105 header
['e_shentsize'])
106 self
._emitline
(' Number of section headers: %s' %
108 self
._emitline
(' Section header string table index: %s' %
109 header
['e_shstrndx'])
111 def display_program_headers(self
, show_heading
=True):
112 """ Display the ELF program headers.
113 If show_heading is True, displays the heading for this information
114 (Elf file type is...)
117 if self
.elffile
.num_segments() == 0:
118 self
._emitline
('There are no program headers in this file.')
121 elfheader
= self
.elffile
.header
123 self
._emitline
('Elf file type is %s' %
124 describe_e_type(elfheader
['e_type']))
125 self
._emitline
('Entry point is %s' %
126 self
._format
_hex
(elfheader
['e_entry']))
127 # readelf weirness - why isn't e_phoff printed as hex? (for section
129 self
._emitline
('There are %s program headers, starting at offset %s' % (
130 elfheader
['e_phnum'], elfheader
['e_phoff']))
133 self
._emitline
('Program Headers:')
135 # Now comes the table of program headers with their attributes. Note
136 # that due to different formatting constraints of 32-bit and 64-bit
137 # addresses, there are some conditions on elfclass here.
139 # First comes the table heading
141 if self
.elffile
.elfclass
== 32:
142 self
._emitline
(' Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align')
144 self
._emitline
(' Type Offset VirtAddr PhysAddr')
145 self
._emitline
(' FileSiz MemSiz Flags Align')
149 for segment
in self
.elffile
.iter_segments():
150 self
._emit
(' %-14s ' % describe_p_type(segment
['p_type']))
152 if self
.elffile
.elfclass
== 32:
153 self
._emitline
('%s %s %s %s %s %-3s %s' % (
154 self
._format
_hex
(segment
['p_offset'], fieldsize
=6),
155 self
._format
_hex
(segment
['p_vaddr'], fullhex
=True),
156 self
._format
_hex
(segment
['p_paddr'], fullhex
=True),
157 self
._format
_hex
(segment
['p_filesz'], fieldsize
=5),
158 self
._format
_hex
(segment
['p_memsz'], fieldsize
=5),
159 describe_p_flags(segment
['p_flags']),
160 self
._format
_hex
(segment
['p_align'])))
162 self
._emitline
('%s %s %s' % (
163 self
._format
_hex
(segment
['p_offset'], fullhex
=True),
164 self
._format
_hex
(segment
['p_vaddr'], fullhex
=True),
165 self
._format
_hex
(segment
['p_paddr'], fullhex
=True)))
166 self
._emitline
(' %s %s %-3s %s' % (
167 self
._format
_hex
(segment
['p_filesz'], fullhex
=True),
168 self
._format
_hex
(segment
['p_memsz'], fullhex
=True),
169 describe_p_flags(segment
['p_flags']),
170 # lead0x set to False for p_align, to mimic readelf.
171 # No idea why the difference from 32-bit mode :-|
172 self
._format
_hex
(segment
['p_align'], lead0x
=False)))
174 if isinstance(segment
, InterpSegment
):
175 self
._emitline
(' [Requesting program interpreter: %s]' %
176 segment
.get_interp_name())
178 # Sections to segments mapping
180 if self
.elffile
.num_sections() == 0:
181 # No sections? We're done
184 self
._emitline
('\n Section to Segment mapping:')
185 self
._emitline
(' Segment Sections...')
187 for nseg
, segment
in enumerate(self
.elffile
.iter_segments()):
188 self
._emit
(' %2.2d ' % nseg
)
190 for section
in self
.elffile
.iter_sections():
191 if ( not section
.is_null() and
192 segment
.section_in_segment(section
)):
193 self
._emit
('%s ' % section
.name
)
197 def display_section_headers(self
, show_heading
=True):
198 """ Display the ELF section headers
200 elfheader
= self
.elffile
.header
202 self
._emitline
('There are %s section headers, starting at offset %s' % (
203 elfheader
['e_shnum'], self
._format
_hex
(elfheader
['e_shoff'])))
205 self
._emitline
('\nSection Header%s:' % (
206 's' if elfheader
['e_shnum'] > 1 else ''))
208 # Different formatting constraints of 32-bit and 64-bit addresses
210 if self
.elffile
.elfclass
== 32:
211 self
._emitline
(' [Nr] Name Type Addr Off Size ES Flg Lk Inf Al')
213 self
._emitline
(' [Nr] Name Type Address Offset')
214 self
._emitline
(' Size EntSize Flags Link Info Align')
218 for nsec
, section
in enumerate(self
.elffile
.iter_sections()):
219 self
._emit
(' [%2u] %-17.17s %-15.15s ' % (
220 nsec
, section
.name
, describe_sh_type(section
['sh_type'])))
222 if self
.elffile
.elfclass
== 32:
223 self
._emitline
('%s %s %s %s %3s %2s %3s %2s' % (
224 self
._format
_hex
(section
['sh_addr'], fieldsize
=8, lead0x
=False),
225 self
._format
_hex
(section
['sh_offset'], fieldsize
=6, lead0x
=False),
226 self
._format
_hex
(section
['sh_size'], fieldsize
=6, lead0x
=False),
227 self
._format
_hex
(section
['sh_entsize'], fieldsize
=2, lead0x
=False),
228 describe_sh_flags(section
['sh_flags']),
229 section
['sh_link'], section
['sh_info'],
230 section
['sh_addralign']))
232 self
._emitline
(' %s %s' % (
233 self
._format
_hex
(section
['sh_addr'], fullhex
=True, lead0x
=False),
234 self
._format
_hex
(section
['sh_offset'],
235 fieldsize
=16 if section
['sh_offset'] > 0xffffffff else 8,
237 self
._emitline
(' %s %s %3s %2s %3s %s' % (
238 self
._format
_hex
(section
['sh_size'], fullhex
=True, lead0x
=False),
239 self
._format
_hex
(section
['sh_entsize'], fullhex
=True, lead0x
=False),
240 describe_sh_flags(section
['sh_flags']),
241 section
['sh_link'], section
['sh_info'],
242 section
['sh_addralign']))
244 self
._emitline
('Key to Flags:')
245 self
._emit
(' W (write), A (alloc), X (execute), M (merge), S (strings)')
246 if self
.elffile
['e_machine'] in ('EM_X86_64', 'EM_L10M'):
247 self
._emitline
(', l (large)')
250 self
._emitline
(' I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)')
251 self
._emitline
(' O (extra OS processing required) o (OS specific), p (processor specific)')
253 def display_symbol_tables(self
):
254 """ Display the symbol tables contained in the file
256 for section
in self
.elffile
.iter_sections():
257 if not isinstance(section
, SymbolTableSection
):
260 if section
['sh_entsize'] == 0:
261 self
._emitline
("\nSymbol table '%s' has a sh_entsize of zero!" % (
265 self
._emitline
("\nSymbol table '%s' contains %s entries:" % (
266 section
.name
, section
.num_symbols()))
268 if self
.elffile
.elfclass
== 32:
269 self
._emitline
(' Num: Value Size Type Bind Vis Ndx Name')
271 self
._emitline
(' Num: Value Size Type Bind Vis Ndx Name')
273 for nsym
, symbol
in enumerate(section
.iter_symbols()):
274 # symbol names are truncated to 25 chars, similarly to readelf
275 self
._emitline
('%6d: %s %5d %-7s %-6s %-7s %4s %.25s' % (
277 self
._format
_hex
(symbol
['st_value'], fullhex
=True, lead0x
=False),
279 describe_symbol_type(symbol
['st_info']['type']),
280 describe_symbol_bind(symbol
['st_info']['bind']),
281 describe_symbol_visibility(symbol
['st_other']['visibility']),
282 describe_symbol_shndx(symbol
['st_shndx']),
285 def display_relocations(self
):
286 """ Display the relocations contained in the file
288 has_relocation_sections
= False
289 for section
in self
.elffile
.iter_sections():
290 if not isinstance(section
, RelocationSection
):
293 has_relocation_sections
= True
294 self
._emitline
("\nRelocation section '%s' at offset %s contains %s entries:" % (
296 self
._format
_hex
(section
['sh_offset']),
297 section
.num_relocations()))
298 if section
.is_RELA():
299 self
._emitline
(" Offset Info Type Sym. Value Sym. Name + Addend")
301 self
._emitline
(" Offset Info Type Sym.Value Sym. Name")
303 # The symbol table section pointed to in sh_link
304 symtable
= self
.elffile
.get_section(section
['sh_link'])
306 for rel
in section
.iter_relocations():
307 hexwidth
= 8 if self
.elffile
.elfclass
== 32 else 12
308 self
._emit
('%s %s %-17.17s' % (
309 self
._format
_hex
(rel
['r_offset'],
310 fieldsize
=hexwidth
, lead0x
=False),
311 self
._format
_hex
(rel
['r_info'],
312 fieldsize
=hexwidth
, lead0x
=False),
314 rel
['r_info_type'], self
.elffile
)))
316 if rel
['r_info_sym'] == 0:
320 symbol
= symtable
.get_symbol(rel
['r_info_sym'])
321 # Some symbols have zero 'st_name', so instead what's used is
322 # the name of the section they point at
323 if symbol
['st_name'] == 0:
324 symsec
= self
.elffile
.get_section(symbol
['st_shndx'])
325 symbol_name
= symsec
.name
327 symbol_name
= symbol
.name
328 self
._emit
(' %s %s%22.22s' % (
331 fullhex
=True, lead0x
=False),
332 ' ' if self
.elffile
.elfclass
== 32 else '',
334 if section
.is_RELA():
335 self
._emit
(' %s %x' % (
336 '+' if rel
['r_addend'] >= 0 else '-',
337 abs(rel
['r_addend'])))
340 if not has_relocation_sections
:
341 self
._emitline
('\nThere are no relocations in this file.')
343 def display_hex_dump(self
, section_spec
):
344 """ Display a hex dump of a section. section_spec is either a section
347 section
= self
._section
_from
_spec
(section_spec
)
349 self
._emitline
("Section '%s' does not exist in the file!" % (
353 self
._emitline
("\nHex dump of section '%s':" % section
.name
)
354 self
._note
_relocs
_for
_section
(section
)
355 addr
= section
['sh_addr']
356 data
= section
.data()
359 while dataptr
< len(data
):
360 bytesleft
= len(data
) - dataptr
361 # chunks of 16 bytes per line
362 linebytes
= 16 if bytesleft
> 16 else bytesleft
364 self
._emit
(' %s ' % self
._format
_hex
(addr
, fieldsize
=8))
367 self
._emit
('%2.2x' % ord(data
[dataptr
+ i
]))
373 for i
in range(linebytes
):
374 c
= data
[dataptr
+ i
]
375 if c
>= ' ' and ord(c
) < 0x7f:
386 def display_string_dump(self
, section_spec
):
387 """ Display a strings dump of a section. section_spec is either a
388 section number or a name.
390 section
= self
._section
_from
_spec
(section_spec
)
392 self
._emitline
("Section '%s' does not exist in the file!" % (
396 printables
= set(string
.printable
)
397 self
._emitline
("\nString dump of section '%s':" % section
.name
)
400 data
= section
.data()
403 while dataptr
< len(data
):
404 while dataptr
< len(data
) and data
[dataptr
] not in printables
:
407 if dataptr
>= len(data
):
411 while endptr
< len(data
) and data
[endptr
] != '\x00':
415 self
._emitline
(' [%6x] %s' % (
416 dataptr
, data
[dataptr
:endptr
]))
421 self
._emitline
(' No strings found in this section.')
425 def display_debug_dump(self
, dump_what
):
426 """ Dump a DWARF section
428 self
._init
_dwarfinfo
()
429 if self
._dwarfinfo
is None:
432 set_global_machine_arch(self
.elffile
.get_machine_arch())
434 if dump_what
== 'info':
435 self
._dump
_debug
_info
()
436 elif dump_what
== 'decodedline':
437 self
._dump
_debug
_line
_programs
()
438 elif dump_what
== 'frames':
439 self
._dump
_debug
_frames
()
440 elif dump_what
== 'frames-interp':
441 self
._dump
_debug
_frames
_interp
()
443 self
._emitline
('debug dump not yet supported for "%s"' % dump_what
)
445 def _format_hex(self
, addr
, fieldsize
=None, fullhex
=False, lead0x
=True):
446 """ Format an address into a hexadecimal string.
449 Size of the hexadecimal field (with leading zeros to fit the
450 address into. For example with fieldsize=8, the format will
452 If None, the minimal required field size will be used.
455 If True, override fieldsize to set it to the maximal size
456 needed for the elfclass
459 If True, leading 0x is added
461 s
= '0x' if lead0x
else ''
463 fieldsize
= 8 if self
.elffile
.elfclass
== 32 else 16
464 if fieldsize
is None:
467 field
= '%' + '0%sx' % fieldsize
468 return s
+ field
% addr
470 def _section_from_spec(self
, spec
):
471 """ Retrieve a section given a "spec" (either number or name).
472 Return None if no such section exists in the file.
476 if num
< self
.elffile
.num_sections():
477 return self
.elffile
.get_section(num
)
481 # Not a number. Must be a name then
482 return self
.elffile
.get_section_by_name(spec
)
484 def _note_relocs_for_section(self
, section
):
485 """ If there are relocation sections pointing to the givne section,
486 emit a note about it.
488 for relsec
in self
.elffile
.iter_sections():
489 if isinstance(relsec
, RelocationSection
):
490 info_idx
= relsec
['sh_info']
491 if self
.elffile
.get_section(info_idx
) == section
:
492 self
._emitline
(' Note: This section has relocations against it, but these have NOT been applied to this dump.')
495 def _init_dwarfinfo(self
):
496 """ Initialize the DWARF info contained in the file and assign it to
498 Leave self._dwarfinfo at None if no DWARF info was found in the file
500 if self
._dwarfinfo
is not None:
503 if self
.elffile
.has_dwarf_info():
504 self
._dwarfinfo
= self
.elffile
.get_dwarf_info()
506 self
._dwarfinfo
= None
508 def _dump_debug_info(self
):
509 """ Dump the debugging info section.
511 self
._emitline
('Contents of the .debug_info section:\n')
513 # Offset of the .debug_info section in the stream
514 section_offset
= self
._dwarfinfo
.debug_info_sec
.global_offset
516 for cu
in self
._dwarfinfo
.iter_CUs():
517 self
._emitline
(' Compilation Unit @ offset %s:' %
518 self
._format
_hex
(cu
.cu_offset
))
519 self
._emitline
(' Length: %s (%s)' % (
520 self
._format
_hex
(cu
['unit_length']),
521 '%s-bit' % cu
.dwarf_format()))
522 self
._emitline
(' Version: %s' % cu
['version']),
523 self
._emitline
(' Abbrev Offset: %s' % cu
['debug_abbrev_offset']),
524 self
._emitline
(' Pointer Size: %s' % cu
['address_size'])
526 # The nesting depth of each DIE within the tree of DIEs must be
527 # displayed. To implement this, a counter is incremented each time
528 # the current DIE has children, and decremented when a null die is
529 # encountered. Due to the way the DIE tree is serialized, this will
530 # correctly reflect the nesting depth
533 for die
in cu
.iter_DIEs():
537 self
._emitline
(' <%s><%x>: Abbrev Number: %s (%s)' % (
543 for attr
in die
.attributes
.itervalues():
545 # Unknown attribute values are passed-through as integers
546 if isinstance(name
, int):
547 name
= 'Unknown AT value: %x' % name
548 self
._emitline
(' <%2x> %-18s: %s' % (
552 attr
, die
, section_offset
)))
559 def _dump_debug_line_programs(self
):
560 """ Dump the (decoded) line programs from .debug_line
561 The programs are dumped in the order of the CUs they belong to.
563 self
._emitline
('Decoded dump of debug contents of section .debug_line:\n')
565 for cu
in self
._dwarfinfo
.iter_CUs():
566 lineprogram
= self
._dwarfinfo
.line_program_for_CU(cu
)
569 if len(lineprogram
['include_directory']) > 0:
570 cu_filename
= '%s/%s' % (
571 lineprogram
['include_directory'][0],
572 lineprogram
['file_entry'][0].name
)
574 cu_filename
= lineprogram
['file_entry'][0].name
576 self
._emitline
('CU: %s:' % cu_filename
)
577 self
._emitline
('File name Line number Starting address')
579 # Print each state's file, line and address information. For some
580 # instructions other output is needed to be compatible with
582 for entry
in lineprogram
.get_entries():
585 # Special handling for commands that don't set a new state
586 if entry
.command
== DW_LNS_set_file
:
587 file_entry
= lineprogram
['file_entry'][entry
.args
[0] - 1]
588 if file_entry
.dir_index
== 0:
590 self
._emitline
('\n./%s:[++]' % (
593 self
._emitline
('\n%s/%s:' % (
594 lineprogram
['include_directory'][file_entry
.dir_index
- 1],
596 elif entry
.command
== DW_LNE_define_file
:
597 self
._emitline
('%s:' % (
598 lineprogram
['include_directory'][entry
.args
[0].dir_index
]))
599 elif not state
.end_sequence
:
600 # readelf doesn't print the state after end_sequence
601 # instructions. I think it's a bug but to be compatible
602 # I don't print them too.
603 self
._emitline
('%-35s %11d %18s' % (
604 lineprogram
['file_entry'][state
.file - 1].name
,
606 '0' if state
.address
== 0 else
607 self
._format
_hex
(state
.address
)))
608 if entry
.command
== DW_LNS_copy
:
609 # Another readelf oddity...
612 def _dump_debug_frames(self
):
613 """ Dump the raw frame information from .debug_frame
615 if not self
._dwarfinfo
.has_CFI():
617 self
._emitline
('Contents of the .debug_frame section:')
619 for entry
in self
._dwarfinfo
.CFI_entries():
620 if isinstance(entry
, CIE
):
621 self
._emitline
('\n%08x %08x %08x CIE' % (
622 entry
.offset
, entry
['length'], entry
['CIE_id']))
623 self
._emitline
(' Version: %d' % entry
['version'])
624 self
._emitline
(' Augmentation: "%s"' % entry
['augmentation'])
625 self
._emitline
(' Code alignment factor: %u' % entry
['code_alignment_factor'])
626 self
._emitline
(' Data alignment factor: %d' % entry
['data_alignment_factor'])
627 self
._emitline
(' Return address column: %d' % entry
['return_address_register'])
630 self
._emitline
('\n%08x %08x %08x FDE cie=%08x pc=%08x..%08x' % (
633 entry
['CIE_pointer'],
635 entry
['initial_location'],
636 entry
['initial_location'] + entry
['address_range']))
638 self
._emit
(describe_CFI_instructions(entry
))
641 def _dump_debug_frames_interp(self
):
642 """ Dump the interpreted (decoded) frame information from .debug_frame
644 if not self
._dwarfinfo
.has_CFI():
647 self
._emitline
('Contents of the .debug_frame section:')
649 for entry
in self
._dwarfinfo
.CFI_entries():
650 if isinstance(entry
, CIE
):
651 self
._emitline
('\n%08x %08x %08x CIE "%s" cf=%d df=%d ra=%d' % (
655 entry
['augmentation'],
656 entry
['code_alignment_factor'],
657 entry
['data_alignment_factor'],
658 entry
['return_address_register']))
659 ra_regnum
= entry
['return_address_register']
661 self
._emitline
('\n%08x %08x %08x FDE cie=%08x pc=%08x..%08x' % (
664 entry
['CIE_pointer'],
666 entry
['initial_location'],
667 entry
['initial_location'] + entry
['address_range']))
668 ra_regnum
= entry
.cie
['return_address_register']
670 # Print the heading row for the decoded table
672 self
._emit
(' ' if entry
.structs
.address_size
== 4 else ' ')
675 # Decode the table nad look at the registers it describes.
676 # We build reg_order here to match readelf's order. In particular,
677 # registers are sorted by their number, and the register matching
678 # ra_regnum is always listed last with a special heading.
679 decoded_table
= entry
.get_decoded()
680 reg_order
= sorted(ifilter(
681 lambda r
: r
!= ra_regnum
,
682 decoded_table
.reg_order
))
684 # Headings for the registers
685 for regnum
in reg_order
:
686 self
._emit
('%-6s' % describe_reg_name(regnum
))
687 self
._emitline
('ra ')
689 # Now include ra_regnum in reg_order to print its values similarly
690 # to the other registers.
691 reg_order
.append(ra_regnum
)
692 for line
in decoded_table
.table
:
693 self
._emit
(self
._format
_hex
(
694 line
['pc'], fullhex
=True, lead0x
=False))
695 self
._emit
(' %-9s' % describe_CFI_CFA_rule(line
['cfa']))
697 for regnum
in reg_order
:
699 s
= describe_CFI_register_rule(line
[regnum
])
702 self
._emit
('%-6s' % s
)
706 def _emit(self
, s
=''):
707 """ Emit an object to output
709 self
.output
.write(str(s
))
711 def _emitline(self
, s
=''):
712 """ Emit an object to output, followed by a newline
714 self
.output
.write(str(s
) + '\n')
717 SCRIPT_DESCRIPTION
= 'Display information about the contents of ELF format files'
718 VERSION_STRING
= '%%prog: based on pyelftools %s' % __version__
721 def main(stream
=None):
722 # parse the command-line arguments and invoke ReadElf
723 optparser
= OptionParser(
724 usage
='usage: %prog [options] <elf-file>',
725 description
=SCRIPT_DESCRIPTION
,
726 add_help_option
=False, # -h is a real option of readelf
728 version
=VERSION_STRING
)
729 optparser
.add_option('-H', '--help',
730 action
='store_true', dest
='help',
731 help='Display this information')
732 optparser
.add_option('-h', '--file-header',
733 action
='store_true', dest
='show_file_header',
734 help='Display the ELF file header')
735 optparser
.add_option('-l', '--program-headers', '--segments',
736 action
='store_true', dest
='show_program_header',
737 help='Display the program headers')
738 optparser
.add_option('-S', '--section-headers', '--sections',
739 action
='store_true', dest
='show_section_header',
740 help="Display the sections' headers")
741 optparser
.add_option('-e', '--headers',
742 action
='store_true', dest
='show_all_headers',
743 help='Equivalent to: -h -l -S')
744 optparser
.add_option('-s', '--symbols', '--syms',
745 action
='store_true', dest
='show_symbols',
746 help='Display the symbol table')
747 optparser
.add_option('-r', '--relocs',
748 action
='store_true', dest
='show_relocs',
749 help='Display the relocations (if present)')
750 optparser
.add_option('-x', '--hex-dump',
751 action
='store', dest
='show_hex_dump', metavar
='<number|name>',
752 help='Dump the contents of section <number|name> as bytes')
753 optparser
.add_option('-p', '--string-dump',
754 action
='store', dest
='show_string_dump', metavar
='<number|name>',
755 help='Dump the contents of section <number|name> as strings')
756 optparser
.add_option('--debug-dump',
757 action
='store', dest
='debug_dump_what', metavar
='<what>',
759 'Display the contents of DWARF debug sections. <what> can ' +
760 'one of {info,decodedline,frames,frames-interp}'))
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__':