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 we're running from the root of the development directory, elftools should
15 # be loaded from there.
16 sys
.path
.insert(0, '.')
18 from elftools
import __version__
19 from elftools
.common
.exceptions
import ELFError
20 from elftools
.common
.py3compat
import (
21 ifilter
, byte2int
, bytes2str
, itervalues
, str2bytes
)
22 from elftools
.elf
.elffile
import ELFFile
23 from elftools
.elf
.dynamic
import DynamicSection
, DynamicSegment
24 from elftools
.elf
.enums
import ENUM_D_TAG
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
, describe_dyn_tag
,
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' % byte2int(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 bytes2str(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 ' % bytes2str(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
, bytes2str(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!" % (
262 bytes2str(section
.name
)))
265 self
._emitline
("\nSymbol table '%s' contains %s entries:" % (
266 bytes2str(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']),
283 bytes2str(symbol
.name
)))
285 def display_dynamic_tags(self
):
286 """ Display the dynamic tags contained in the file
288 for section
in self
.elffile
.iter_sections():
289 if not isinstance(section
, DynamicSection
):
292 self
._emitline
("\nDynamic section at offset %s contains %s entries:" % (
293 self
._format
_hex
(section
['sh_offset']),
295 self
._emitline
(" Tag Type Name/Value")
297 padding
= 20 + (8 if self
.elffile
.elfclass
== 32 else 0)
298 for tag
in section
.iter_tags():
299 if tag
.entry
.d_tag
== 'DT_NEEDED':
300 parsed
= 'Shared library: [%s]' % bytes2str(tag
.needed
)
301 elif tag
.entry
.d_tag
== 'DT_RPATH':
302 parsed
= 'Library rpath: [%s]' % bytes2str(tag
.rpath
)
303 elif tag
.entry
.d_tag
== 'DT_RUNPATH':
304 parsed
= 'Library runpath: [%s]' % bytes2str(tag
.runpath
)
305 elif tag
.entry
.d_tag
== 'DT_SONAME':
306 parsed
= 'Library soname: [%s]' % bytes2str(tag
.soname
)
307 elif (tag
.entry
.d_tag
.endswith('SZ') or
308 tag
.entry
.d_tag
.endswith('ENT')):
309 parsed
= '%i (bytes)' % tag
['d_val']
310 elif (tag
.entry
.d_tag
.endswith('NUM') or
311 tag
.entry
.d_tag
.endswith('COUNT')):
312 parsed
= '%i' % tag
['d_val']
313 elif tag
.entry
.d_tag
== 'DT_PLTREL':
314 s
= describe_dyn_tag(tag
.entry
.d_val
)
315 if s
.startswith('DT_'):
319 parsed
= '%#x' % tag
['d_val']
321 self
._emitline
(" %s %-*s %s" % (
322 self
._format
_hex
(ENUM_D_TAG
.get(tag
.entry
.d_tag
, tag
.entry
.d_tag
),
323 fullhex
=True, lead0x
=True),
325 '(%s)' % (tag
.entry
.d_tag
[3:],),
328 def display_relocations(self
):
329 """ Display the relocations contained in the file
331 has_relocation_sections
= False
332 for section
in self
.elffile
.iter_sections():
333 if not isinstance(section
, RelocationSection
):
336 has_relocation_sections
= True
337 self
._emitline
("\nRelocation section '%s' at offset %s contains %s entries:" % (
338 bytes2str(section
.name
),
339 self
._format
_hex
(section
['sh_offset']),
340 section
.num_relocations()))
341 if section
.is_RELA():
342 self
._emitline
(" Offset Info Type Sym. Value Sym. Name + Addend")
344 self
._emitline
(" Offset Info Type Sym.Value Sym. Name")
346 # The symbol table section pointed to in sh_link
347 symtable
= self
.elffile
.get_section(section
['sh_link'])
349 for rel
in section
.iter_relocations():
350 hexwidth
= 8 if self
.elffile
.elfclass
== 32 else 12
351 self
._emit
('%s %s %-17.17s' % (
352 self
._format
_hex
(rel
['r_offset'],
353 fieldsize
=hexwidth
, lead0x
=False),
354 self
._format
_hex
(rel
['r_info'],
355 fieldsize
=hexwidth
, lead0x
=False),
357 rel
['r_info_type'], self
.elffile
)))
359 if rel
['r_info_sym'] == 0:
363 symbol
= symtable
.get_symbol(rel
['r_info_sym'])
364 # Some symbols have zero 'st_name', so instead what's used is
365 # the name of the section they point at
366 if symbol
['st_name'] == 0:
367 symsec
= self
.elffile
.get_section(symbol
['st_shndx'])
368 symbol_name
= symsec
.name
370 symbol_name
= symbol
.name
371 self
._emit
(' %s %s%22.22s' % (
374 fullhex
=True, lead0x
=False),
375 ' ' if self
.elffile
.elfclass
== 32 else '',
376 bytes2str(symbol_name
)))
377 if section
.is_RELA():
378 self
._emit
(' %s %x' % (
379 '+' if rel
['r_addend'] >= 0 else '-',
380 abs(rel
['r_addend'])))
383 if not has_relocation_sections
:
384 self
._emitline
('\nThere are no relocations in this file.')
386 def display_hex_dump(self
, section_spec
):
387 """ Display a hex dump of a section. section_spec is either a section
390 section
= self
._section
_from
_spec
(section_spec
)
392 self
._emitline
("Section '%s' does not exist in the file!" % (
396 self
._emitline
("\nHex dump of section '%s':" % bytes2str(section
.name
))
397 self
._note
_relocs
_for
_section
(section
)
398 addr
= section
['sh_addr']
399 data
= section
.data()
402 while dataptr
< len(data
):
403 bytesleft
= len(data
) - dataptr
404 # chunks of 16 bytes per line
405 linebytes
= 16 if bytesleft
> 16 else bytesleft
407 self
._emit
(' %s ' % self
._format
_hex
(addr
, fieldsize
=8))
410 self
._emit
('%2.2x' % byte2int(data
[dataptr
+ i
]))
416 for i
in range(linebytes
):
417 c
= data
[dataptr
+ i
: dataptr
+ i
+ 1]
418 if byte2int(c
[0]) >= 32 and byte2int(c
[0]) < 0x7f:
419 self
._emit
(bytes2str(c
))
421 self
._emit
(bytes2str(b
'.'))
429 def display_string_dump(self
, section_spec
):
430 """ Display a strings dump of a section. section_spec is either a
431 section number or a name.
433 section
= self
._section
_from
_spec
(section_spec
)
435 self
._emitline
("Section '%s' does not exist in the file!" % (
439 self
._emitline
("\nString dump of section '%s':" % bytes2str(section
.name
))
442 data
= section
.data()
445 while dataptr
< len(data
):
446 while ( dataptr
< len(data
) and
447 not (32 <= byte2int(data
[dataptr
]) <= 127)):
450 if dataptr
>= len(data
):
454 while endptr
< len(data
) and byte2int(data
[endptr
]) != 0:
458 self
._emitline
(' [%6x] %s' % (
459 dataptr
, bytes2str(data
[dataptr
:endptr
])))
464 self
._emitline
(' No strings found in this section.')
468 def display_debug_dump(self
, dump_what
):
469 """ Dump a DWARF section
471 self
._init
_dwarfinfo
()
472 if self
._dwarfinfo
is None:
475 set_global_machine_arch(self
.elffile
.get_machine_arch())
477 if dump_what
== 'info':
478 self
._dump
_debug
_info
()
479 elif dump_what
== 'decodedline':
480 self
._dump
_debug
_line
_programs
()
481 elif dump_what
== 'frames':
482 self
._dump
_debug
_frames
()
483 elif dump_what
== 'frames-interp':
484 self
._dump
_debug
_frames
_interp
()
486 self
._emitline
('debug dump not yet supported for "%s"' % dump_what
)
488 def _format_hex(self
, addr
, fieldsize
=None, fullhex
=False, lead0x
=True):
489 """ Format an address into a hexadecimal string.
492 Size of the hexadecimal field (with leading zeros to fit the
493 address into. For example with fieldsize=8, the format will
495 If None, the minimal required field size will be used.
498 If True, override fieldsize to set it to the maximal size
499 needed for the elfclass
502 If True, leading 0x is added
504 s
= '0x' if lead0x
else ''
506 fieldsize
= 8 if self
.elffile
.elfclass
== 32 else 16
507 if fieldsize
is None:
510 field
= '%' + '0%sx' % fieldsize
511 return s
+ field
% addr
513 def _section_from_spec(self
, spec
):
514 """ Retrieve a section given a "spec" (either number or name).
515 Return None if no such section exists in the file.
519 if num
< self
.elffile
.num_sections():
520 return self
.elffile
.get_section(num
)
524 # Not a number. Must be a name then
525 return self
.elffile
.get_section_by_name(str2bytes(spec
))
527 def _note_relocs_for_section(self
, section
):
528 """ If there are relocation sections pointing to the givne section,
529 emit a note about it.
531 for relsec
in self
.elffile
.iter_sections():
532 if isinstance(relsec
, RelocationSection
):
533 info_idx
= relsec
['sh_info']
534 if self
.elffile
.get_section(info_idx
) == section
:
535 self
._emitline
(' Note: This section has relocations against it, but these have NOT been applied to this dump.')
538 def _init_dwarfinfo(self
):
539 """ Initialize the DWARF info contained in the file and assign it to
541 Leave self._dwarfinfo at None if no DWARF info was found in the file
543 if self
._dwarfinfo
is not None:
546 if self
.elffile
.has_dwarf_info():
547 self
._dwarfinfo
= self
.elffile
.get_dwarf_info()
549 self
._dwarfinfo
= None
551 def _dump_debug_info(self
):
552 """ Dump the debugging info section.
554 self
._emitline
('Contents of the .debug_info section:\n')
556 # Offset of the .debug_info section in the stream
557 section_offset
= self
._dwarfinfo
.debug_info_sec
.global_offset
559 for cu
in self
._dwarfinfo
.iter_CUs():
560 self
._emitline
(' Compilation Unit @ offset %s:' %
561 self
._format
_hex
(cu
.cu_offset
))
562 self
._emitline
(' Length: %s (%s)' % (
563 self
._format
_hex
(cu
['unit_length']),
564 '%s-bit' % cu
.dwarf_format()))
565 self
._emitline
(' Version: %s' % cu
['version']),
566 self
._emitline
(' Abbrev Offset: %s' % (
567 self
._format
_hex
(cu
['debug_abbrev_offset']))),
568 self
._emitline
(' Pointer Size: %s' % cu
['address_size'])
570 # The nesting depth of each DIE within the tree of DIEs must be
571 # displayed. To implement this, a counter is incremented each time
572 # the current DIE has children, and decremented when a null die is
573 # encountered. Due to the way the DIE tree is serialized, this will
574 # correctly reflect the nesting depth
577 for die
in cu
.iter_DIEs():
578 self
._emitline
(' <%s><%x>: Abbrev Number: %s%s' % (
582 (' (%s)' % die
.tag
) if not die
.is_null() else ''))
587 for attr
in itervalues(die
.attributes
):
589 # Unknown attribute values are passed-through as integers
590 if isinstance(name
, int):
591 name
= 'Unknown AT value: %x' % name
592 self
._emitline
(' <%2x> %-18s: %s' % (
596 attr
, die
, section_offset
)))
603 def _dump_debug_line_programs(self
):
604 """ Dump the (decoded) line programs from .debug_line
605 The programs are dumped in the order of the CUs they belong to.
607 self
._emitline
('Decoded dump of debug contents of section .debug_line:\n')
609 for cu
in self
._dwarfinfo
.iter_CUs():
610 lineprogram
= self
._dwarfinfo
.line_program_for_CU(cu
)
612 cu_filename
= bytes2str(lineprogram
['file_entry'][0].name
)
613 if len(lineprogram
['include_directory']) > 0:
614 dir_index
= lineprogram
['file_entry'][0].dir_index
616 dir = lineprogram
['include_directory'][dir_index
- 1]
619 cu_filename
= '%s/%s' % (bytes2str(dir), cu_filename
)
621 self
._emitline
('CU: %s:' % cu_filename
)
622 self
._emitline
('File name Line number Starting address')
624 # Print each state's file, line and address information. For some
625 # instructions other output is needed to be compatible with
627 for entry
in lineprogram
.get_entries():
630 # Special handling for commands that don't set a new state
631 if entry
.command
== DW_LNS_set_file
:
632 file_entry
= lineprogram
['file_entry'][entry
.args
[0] - 1]
633 if file_entry
.dir_index
== 0:
635 self
._emitline
('\n./%s:[++]' % (
636 bytes2str(file_entry
.name
)))
638 self
._emitline
('\n%s/%s:' % (
639 bytes2str(lineprogram
['include_directory'][file_entry
.dir_index
- 1]),
640 bytes2str(file_entry
.name
)))
641 elif entry
.command
== DW_LNE_define_file
:
642 self
._emitline
('%s:' % (
643 bytes2str(lineprogram
['include_directory'][entry
.args
[0].dir_index
])))
644 elif not state
.end_sequence
:
645 # readelf doesn't print the state after end_sequence
646 # instructions. I think it's a bug but to be compatible
647 # I don't print them too.
648 self
._emitline
('%-35s %11d %18s' % (
649 bytes2str(lineprogram
['file_entry'][state
.file - 1].name
),
651 '0' if state
.address
== 0 else
652 self
._format
_hex
(state
.address
)))
653 if entry
.command
== DW_LNS_copy
:
654 # Another readelf oddity...
657 def _dump_debug_frames(self
):
658 """ Dump the raw frame information from .debug_frame
660 if not self
._dwarfinfo
.has_CFI():
662 self
._emitline
('Contents of the .debug_frame section:')
664 for entry
in self
._dwarfinfo
.CFI_entries():
665 if isinstance(entry
, CIE
):
666 self
._emitline
('\n%08x %08x %08x CIE' % (
667 entry
.offset
, entry
['length'], entry
['CIE_id']))
668 self
._emitline
(' Version: %d' % entry
['version'])
669 self
._emitline
(' Augmentation: "%s"' % bytes2str(entry
['augmentation']))
670 self
._emitline
(' Code alignment factor: %u' % entry
['code_alignment_factor'])
671 self
._emitline
(' Data alignment factor: %d' % entry
['data_alignment_factor'])
672 self
._emitline
(' Return address column: %d' % entry
['return_address_register'])
675 self
._emitline
('\n%08x %08x %08x FDE cie=%08x pc=%08x..%08x' % (
678 entry
['CIE_pointer'],
680 entry
['initial_location'],
681 entry
['initial_location'] + entry
['address_range']))
683 self
._emit
(describe_CFI_instructions(entry
))
686 def _dump_debug_frames_interp(self
):
687 """ Dump the interpreted (decoded) frame information from .debug_frame
689 if not self
._dwarfinfo
.has_CFI():
692 self
._emitline
('Contents of the .debug_frame section:')
694 for entry
in self
._dwarfinfo
.CFI_entries():
695 if isinstance(entry
, CIE
):
696 self
._emitline
('\n%08x %08x %08x CIE "%s" cf=%d df=%d ra=%d' % (
700 bytes2str(entry
['augmentation']),
701 entry
['code_alignment_factor'],
702 entry
['data_alignment_factor'],
703 entry
['return_address_register']))
704 ra_regnum
= entry
['return_address_register']
706 self
._emitline
('\n%08x %08x %08x FDE cie=%08x pc=%08x..%08x' % (
709 entry
['CIE_pointer'],
711 entry
['initial_location'],
712 entry
['initial_location'] + entry
['address_range']))
713 ra_regnum
= entry
.cie
['return_address_register']
715 # Print the heading row for the decoded table
717 self
._emit
(' ' if entry
.structs
.address_size
== 4 else ' ')
720 # Decode the table nad look at the registers it describes.
721 # We build reg_order here to match readelf's order. In particular,
722 # registers are sorted by their number, and the register matching
723 # ra_regnum is always listed last with a special heading.
724 decoded_table
= entry
.get_decoded()
725 reg_order
= sorted(ifilter(
726 lambda r
: r
!= ra_regnum
,
727 decoded_table
.reg_order
))
729 # Headings for the registers
730 for regnum
in reg_order
:
731 self
._emit
('%-6s' % describe_reg_name(regnum
))
732 self
._emitline
('ra ')
734 # Now include ra_regnum in reg_order to print its values similarly
735 # to the other registers.
736 reg_order
.append(ra_regnum
)
737 for line
in decoded_table
.table
:
738 self
._emit
(self
._format
_hex
(
739 line
['pc'], fullhex
=True, lead0x
=False))
740 self
._emit
(' %-9s' % describe_CFI_CFA_rule(line
['cfa']))
742 for regnum
in reg_order
:
744 s
= describe_CFI_register_rule(line
[regnum
])
747 self
._emit
('%-6s' % s
)
751 def _emit(self
, s
=''):
752 """ Emit an object to output
754 self
.output
.write(str(s
))
756 def _emitline(self
, s
=''):
757 """ Emit an object to output, followed by a newline
759 self
.output
.write(str(s
) + '\n')
762 SCRIPT_DESCRIPTION
= 'Display information about the contents of ELF format files'
763 VERSION_STRING
= '%%prog: based on pyelftools %s' % __version__
766 def main(stream
=None):
767 # parse the command-line arguments and invoke ReadElf
768 optparser
= OptionParser(
769 usage
='usage: %prog [options] <elf-file>',
770 description
=SCRIPT_DESCRIPTION
,
771 add_help_option
=False, # -h is a real option of readelf
773 version
=VERSION_STRING
)
774 optparser
.add_option('-d', '--dynamic',
775 action
='store_true', dest
='show_dynamic_tags',
776 help='Display the dynamic section')
777 optparser
.add_option('-H', '--help',
778 action
='store_true', dest
='help',
779 help='Display this information')
780 optparser
.add_option('-h', '--file-header',
781 action
='store_true', dest
='show_file_header',
782 help='Display the ELF file header')
783 optparser
.add_option('-l', '--program-headers', '--segments',
784 action
='store_true', dest
='show_program_header',
785 help='Display the program headers')
786 optparser
.add_option('-S', '--section-headers', '--sections',
787 action
='store_true', dest
='show_section_header',
788 help="Display the sections' headers")
789 optparser
.add_option('-e', '--headers',
790 action
='store_true', dest
='show_all_headers',
791 help='Equivalent to: -h -l -S')
792 optparser
.add_option('-s', '--symbols', '--syms',
793 action
='store_true', dest
='show_symbols',
794 help='Display the symbol table')
795 optparser
.add_option('-r', '--relocs',
796 action
='store_true', dest
='show_relocs',
797 help='Display the relocations (if present)')
798 optparser
.add_option('-x', '--hex-dump',
799 action
='store', dest
='show_hex_dump', metavar
='<number|name>',
800 help='Dump the contents of section <number|name> as bytes')
801 optparser
.add_option('-p', '--string-dump',
802 action
='store', dest
='show_string_dump', metavar
='<number|name>',
803 help='Dump the contents of section <number|name> as strings')
804 optparser
.add_option('--debug-dump',
805 action
='store', dest
='debug_dump_what', metavar
='<what>',
807 'Display the contents of DWARF debug sections. <what> can ' +
808 'one of {info,decodedline,frames,frames-interp}'))
810 options
, args
= optparser
.parse_args()
812 if options
.help or len(args
) == 0:
813 optparser
.print_help()
816 if options
.show_all_headers
:
817 do_file_header
= do_section_header
= do_program_header
= True
819 do_file_header
= options
.show_file_header
820 do_section_header
= options
.show_section_header
821 do_program_header
= options
.show_program_header
823 with
open(args
[0], 'rb') as file:
825 readelf
= ReadElf(file, stream
or sys
.stdout
)
827 readelf
.display_file_header()
828 if do_section_header
:
829 readelf
.display_section_headers(
830 show_heading
=not do_file_header
)
831 if do_program_header
:
832 readelf
.display_program_headers(
833 show_heading
=not do_file_header
)
834 if options
.show_dynamic_tags
:
835 readelf
.display_dynamic_tags()
836 if options
.show_symbols
:
837 readelf
.display_symbol_tables()
838 if options
.show_relocs
:
839 readelf
.display_relocations()
840 if options
.show_hex_dump
:
841 readelf
.display_hex_dump(options
.show_hex_dump
)
842 if options
.show_string_dump
:
843 readelf
.display_string_dump(options
.show_string_dump
)
844 if options
.debug_dump_what
:
845 readelf
.display_debug_dump(options
.debug_dump_what
)
846 except ELFError
as ex
:
847 sys
.stderr
.write('ELF error: %s\n' % ex
)
852 # Run 'main' redirecting its output to readelfout.txt
853 # Saves profiling information in readelf.profile
854 PROFFILE
= 'readelf.profile'
856 cProfile
.run('main(open("readelfout.txt", "w"))', PROFFILE
)
858 # Dig in some profiling stats
860 p
= pstats
.Stats(PROFFILE
)
861 p
.sort_stats('cumulative').print_stats(25)
864 #-------------------------------------------------------------------------------
865 if __name__
== '__main__':