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 #-------------------------------------------------------------------------------
15 # Note: zip has different behaviour between Python 2.x and 3.x.
16 # - Using izip ensures compatibility.
18 from itertools
import izip
22 # For running from development directory. It should take precedence over the
23 # installed pyelftools.
24 sys
.path
.insert(0, '.')
27 from elftools
import __version__
28 from elftools
.common
.exceptions
import ELFError
29 from elftools
.common
.py3compat
import (
30 ifilter
, byte2int
, bytes2str
, itervalues
, str2bytes
, iterbytes
)
31 from elftools
.elf
.elffile
import ELFFile
32 from elftools
.elf
.dynamic
import DynamicSection
, DynamicSegment
33 from elftools
.elf
.enums
import ENUM_D_TAG
34 from elftools
.elf
.segments
import InterpSegment
35 from elftools
.elf
.sections
import (
36 NoteSection
, SymbolTableSection
, SymbolTableIndexSection
38 from elftools
.elf
.gnuversions
import (
39 GNUVerSymSection
, GNUVerDefSection
,
42 from elftools
.elf
.relocation
import RelocationSection
43 from elftools
.elf
.descriptions
import (
44 describe_ei_class
, describe_ei_data
, describe_ei_version
,
45 describe_ei_osabi
, describe_e_type
, describe_e_machine
,
46 describe_e_version_numeric
, describe_p_type
, describe_p_flags
,
47 describe_rh_flags
, describe_sh_type
, describe_sh_flags
,
48 describe_symbol_type
, describe_symbol_bind
, describe_symbol_visibility
,
49 describe_symbol_shndx
, describe_reloc_type
, describe_dyn_tag
,
50 describe_dt_flags
, describe_dt_flags_1
, describe_ver_flags
, describe_note
,
53 from elftools
.elf
.constants
import E_FLAGS
54 from elftools
.elf
.constants
import E_FLAGS_MASKS
55 from elftools
.elf
.constants
import SH_FLAGS
56 from elftools
.elf
.constants
import SHN_INDICES
57 from elftools
.dwarf
.dwarfinfo
import DWARFInfo
58 from elftools
.dwarf
.descriptions
import (
59 describe_reg_name
, describe_attr_value
, set_global_machine_arch
,
60 describe_CFI_instructions
, describe_CFI_register_rule
,
61 describe_CFI_CFA_rule
, describe_DWARF_expr
63 from elftools
.dwarf
.constants
import (
64 DW_LNS_copy
, DW_LNS_set_file
, DW_LNE_define_file
)
65 from elftools
.dwarf
.locationlists
import LocationParser
, LocationEntry
66 from elftools
.dwarf
.callframe
import CIE
, FDE
, ZERO
67 from elftools
.ehabi
.ehabiinfo
import CorruptEHABIEntry
, CannotUnwindEHABIEntry
, GenericEHABIEntry
70 class ReadElf(object):
71 """ display_* methods are used to emit output into the output stream
73 def __init__(self
, file, output
):
75 stream object with the ELF file to read
78 output stream to write to
80 self
.elffile
= ELFFile(file)
83 # Lazily initialized if a debug dump is requested
84 self
._dwarfinfo
= None
86 self
._versioninfo
= None
88 self
._shndx
_sections
= None
90 def display_file_header(self
):
91 """ Display the ELF file header
93 self
._emitline
('ELF Header:')
94 self
._emit
(' Magic: ')
95 self
._emit
(' '.join('%2.2x' % byte2int(b
)
96 for b
in self
.elffile
.e_ident_raw
))
98 header
= self
.elffile
.header
99 e_ident
= header
['e_ident']
100 self
._emitline
(' Class: %s' %
101 describe_ei_class(e_ident
['EI_CLASS']))
102 self
._emitline
(' Data: %s' %
103 describe_ei_data(e_ident
['EI_DATA']))
104 self
._emitline
(' Version: %s' %
105 describe_ei_version(e_ident
['EI_VERSION']))
106 self
._emitline
(' OS/ABI: %s' %
107 describe_ei_osabi(e_ident
['EI_OSABI']))
108 self
._emitline
(' ABI Version: %d' %
109 e_ident
['EI_ABIVERSION'])
110 self
._emitline
(' Type: %s' %
111 describe_e_type(header
['e_type']))
112 self
._emitline
(' Machine: %s' %
113 describe_e_machine(header
['e_machine']))
114 self
._emitline
(' Version: %s' %
115 describe_e_version_numeric(header
['e_version']))
116 self
._emitline
(' Entry point address: %s' %
117 self
._format
_hex
(header
['e_entry']))
118 self
._emit
(' Start of program headers: %s' %
120 self
._emitline
(' (bytes into file)')
121 self
._emit
(' Start of section headers: %s' %
123 self
._emitline
(' (bytes into file)')
124 self
._emitline
(' Flags: %s%s' %
125 (self
._format
_hex
(header
['e_flags']),
126 self
.decode_flags(header
['e_flags'])))
127 self
._emitline
(' Size of this header: %s (bytes)' %
129 self
._emitline
(' Size of program headers: %s (bytes)' %
130 header
['e_phentsize'])
131 self
._emitline
(' Number of program headers: %s' %
133 self
._emitline
(' Size of section headers: %s (bytes)' %
134 header
['e_shentsize'])
135 self
._emit
(' Number of section headers: %s' %
137 if header
['e_shnum'] == 0 and self
.elffile
.num_sections() != 0:
138 self
._emitline
(' (%d)' % self
.elffile
.num_sections())
141 self
._emit
(' Section header string table index: %s' %
142 header
['e_shstrndx'])
143 if header
['e_shstrndx'] == SHN_INDICES
.SHN_XINDEX
:
144 self
._emitline
(' (%d)' % self
.elffile
.get_shstrndx())
148 def decode_flags(self
, flags
):
150 if self
.elffile
['e_machine'] == "EM_ARM":
151 eabi
= flags
& E_FLAGS
.EF_ARM_EABIMASK
152 flags
&= ~E_FLAGS
.EF_ARM_EABIMASK
154 if flags
& E_FLAGS
.EF_ARM_RELEXEC
:
155 description
+= ', relocatable executabl'
156 flags
&= ~E_FLAGS
.EF_ARM_RELEXEC
158 if eabi
== E_FLAGS
.EF_ARM_EABI_VER5
:
159 EF_ARM_KNOWN_FLAGS
= E_FLAGS
.EF_ARM_ABI_FLOAT_SOFT|E_FLAGS
.EF_ARM_ABI_FLOAT_HARD|E_FLAGS
.EF_ARM_LE8|E_FLAGS
.EF_ARM_BE8
160 description
+= ', Version5 EABI'
161 if flags
& E_FLAGS
.EF_ARM_ABI_FLOAT_SOFT
:
162 description
+= ", soft-float ABI"
163 elif flags
& E_FLAGS
.EF_ARM_ABI_FLOAT_HARD
:
164 description
+= ", hard-float ABI"
166 if flags
& E_FLAGS
.EF_ARM_BE8
:
167 description
+= ", BE8"
168 elif flags
& E_FLAGS
.EF_ARM_LE8
:
169 description
+= ", LE8"
171 if flags
& ~EF_ARM_KNOWN_FLAGS
:
172 description
+= ', <unknown>'
174 description
+= ', <unrecognized EABI>'
176 elif self
.elffile
['e_machine'] == "EM_MIPS":
177 if flags
& E_FLAGS
.EF_MIPS_NOREORDER
:
178 description
+= ", noreorder"
179 if flags
& E_FLAGS
.EF_MIPS_PIC
:
180 description
+= ", pic"
181 if flags
& E_FLAGS
.EF_MIPS_CPIC
:
182 description
+= ", cpic"
183 if (flags
& E_FLAGS
.EF_MIPS_ABI2
):
184 description
+= ", abi2"
185 if (flags
& E_FLAGS
.EF_MIPS_32BITMODE
):
186 description
+= ", 32bitmode"
187 if (flags
& E_FLAGS_MASKS
.EFM_MIPS_ABI_O32
):
188 description
+= ", o32"
189 elif (flags
& E_FLAGS_MASKS
.EFM_MIPS_ABI_O64
):
190 description
+= ", o64"
191 elif (flags
& E_FLAGS_MASKS
.EFM_MIPS_ABI_EABI32
):
192 description
+= ", eabi32"
193 elif (flags
& E_FLAGS_MASKS
.EFM_MIPS_ABI_EABI64
):
194 description
+= ", eabi64"
195 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_1
:
196 description
+= ", mips1"
197 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_2
:
198 description
+= ", mips2"
199 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_3
:
200 description
+= ", mips3"
201 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_4
:
202 description
+= ", mips4"
203 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_5
:
204 description
+= ", mips5"
205 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_32R2
:
206 description
+= ", mips32r2"
207 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_64R2
:
208 description
+= ", mips64r2"
209 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_32
:
210 description
+= ", mips32"
211 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_64
:
212 description
+= ", mips64"
216 def display_program_headers(self
, show_heading
=True):
217 """ Display the ELF program headers.
218 If show_heading is True, displays the heading for this information
219 (Elf file type is...)
222 if self
.elffile
.num_segments() == 0:
223 self
._emitline
('There are no program headers in this file.')
226 elfheader
= self
.elffile
.header
228 self
._emitline
('Elf file type is %s' %
229 describe_e_type(elfheader
['e_type']))
230 self
._emitline
('Entry point is %s' %
231 self
._format
_hex
(elfheader
['e_entry']))
232 # readelf weirness - why isn't e_phoff printed as hex? (for section
234 self
._emitline
('There are %s program headers, starting at offset %s' % (
235 self
.elffile
.num_segments(), elfheader
['e_phoff']))
238 self
._emitline
('Program Headers:')
240 # Now comes the table of program headers with their attributes. Note
241 # that due to different formatting constraints of 32-bit and 64-bit
242 # addresses, there are some conditions on elfclass here.
244 # First comes the table heading
246 if self
.elffile
.elfclass
== 32:
247 self
._emitline
(' Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align')
249 self
._emitline
(' Type Offset VirtAddr PhysAddr')
250 self
._emitline
(' FileSiz MemSiz Flags Align')
254 for segment
in self
.elffile
.iter_segments():
255 self
._emit
(' %-14s ' % describe_p_type(segment
['p_type']))
257 if self
.elffile
.elfclass
== 32:
258 self
._emitline
('%s %s %s %s %s %-3s %s' % (
259 self
._format
_hex
(segment
['p_offset'], fieldsize
=6),
260 self
._format
_hex
(segment
['p_vaddr'], fullhex
=True),
261 self
._format
_hex
(segment
['p_paddr'], fullhex
=True),
262 self
._format
_hex
(segment
['p_filesz'], fieldsize
=5),
263 self
._format
_hex
(segment
['p_memsz'], fieldsize
=5),
264 describe_p_flags(segment
['p_flags']),
265 self
._format
_hex
(segment
['p_align'])))
267 self
._emitline
('%s %s %s' % (
268 self
._format
_hex
(segment
['p_offset'], fullhex
=True),
269 self
._format
_hex
(segment
['p_vaddr'], fullhex
=True),
270 self
._format
_hex
(segment
['p_paddr'], fullhex
=True)))
271 self
._emitline
(' %s %s %-3s %s' % (
272 self
._format
_hex
(segment
['p_filesz'], fullhex
=True),
273 self
._format
_hex
(segment
['p_memsz'], fullhex
=True),
274 describe_p_flags(segment
['p_flags']),
275 # lead0x set to False for p_align, to mimic readelf.
276 # No idea why the difference from 32-bit mode :-|
277 self
._format
_hex
(segment
['p_align'], lead0x
=False)))
279 if isinstance(segment
, InterpSegment
):
280 self
._emitline
(' [Requesting program interpreter: %s]' %
281 segment
.get_interp_name())
283 # Sections to segments mapping
285 if self
.elffile
.num_sections() == 0:
286 # No sections? We're done
289 self
._emitline
('\n Section to Segment mapping:')
290 self
._emitline
(' Segment Sections...')
292 for nseg
, segment
in enumerate(self
.elffile
.iter_segments()):
293 self
._emit
(' %2.2d ' % nseg
)
295 for section
in self
.elffile
.iter_sections():
296 if ( not section
.is_null() and
297 not ((section
['sh_flags'] & SH_FLAGS
.SHF_TLS
) != 0 and
298 section
['sh_type'] == 'SHT_NOBITS' and
299 segment
['p_type'] != 'PT_TLS') and
300 segment
.section_in_segment(section
)):
301 self
._emit
('%s ' % section
.name
)
305 def display_section_headers(self
, show_heading
=True):
306 """ Display the ELF section headers
308 elfheader
= self
.elffile
.header
310 self
._emitline
('There are %s section headers, starting at offset %s' % (
311 elfheader
['e_shnum'], self
._format
_hex
(elfheader
['e_shoff'])))
313 if self
.elffile
.num_sections() == 0:
314 self
._emitline
('There are no sections in this file.')
317 self
._emitline
('\nSection Header%s:' % (
318 's' if self
.elffile
.num_sections() > 1 else ''))
320 # Different formatting constraints of 32-bit and 64-bit addresses
322 if self
.elffile
.elfclass
== 32:
323 self
._emitline
(' [Nr] Name Type Addr Off Size ES Flg Lk Inf Al')
325 self
._emitline
(' [Nr] Name Type Address Offset')
326 self
._emitline
(' Size EntSize Flags Link Info Align')
330 for nsec
, section
in enumerate(self
.elffile
.iter_sections()):
331 self
._emit
(' [%2u] %-17.17s %-15.15s ' % (
332 nsec
, section
.name
, describe_sh_type(section
['sh_type'])))
334 if self
.elffile
.elfclass
== 32:
335 self
._emitline
('%s %s %s %s %3s %2s %3s %2s' % (
336 self
._format
_hex
(section
['sh_addr'], fieldsize
=8, lead0x
=False),
337 self
._format
_hex
(section
['sh_offset'], fieldsize
=6, lead0x
=False),
338 self
._format
_hex
(section
['sh_size'], fieldsize
=6, lead0x
=False),
339 self
._format
_hex
(section
['sh_entsize'], fieldsize
=2, lead0x
=False),
340 describe_sh_flags(section
['sh_flags']),
341 section
['sh_link'], section
['sh_info'],
342 section
['sh_addralign']))
344 self
._emitline
(' %s %s' % (
345 self
._format
_hex
(section
['sh_addr'], fullhex
=True, lead0x
=False),
346 self
._format
_hex
(section
['sh_offset'],
347 fieldsize
=16 if section
['sh_offset'] > 0xffffffff else 8,
349 self
._emitline
(' %s %s %3s %2s %3s %s' % (
350 self
._format
_hex
(section
['sh_size'], fullhex
=True, lead0x
=False),
351 self
._format
_hex
(section
['sh_entsize'], fullhex
=True, lead0x
=False),
352 describe_sh_flags(section
['sh_flags']),
353 section
['sh_link'], section
['sh_info'],
354 section
['sh_addralign']))
356 self
._emitline
('Key to Flags:')
357 self
._emitline
(' W (write), A (alloc), X (execute), M (merge),'
358 ' S (strings), I (info),')
359 self
._emitline
(' L (link order), O (extra OS processing required),'
360 ' G (group), T (TLS),')
361 self
._emitline
(' C (compressed), x (unknown), o (OS specific),'
364 if self
.elffile
['e_machine'] == 'EM_ARM':
365 self
._emit
('y (purecode), ')
366 self
._emitline
('p (processor specific)')
368 def display_symbol_tables(self
):
369 """ Display the symbol tables contained in the file
371 self
._init
_versioninfo
()
373 symbol_tables
= [(idx
, s
) for idx
, s
in enumerate(self
.elffile
.iter_sections())
374 if isinstance(s
, SymbolTableSection
)]
376 if not symbol_tables
and self
.elffile
.num_sections() == 0:
378 self
._emitline
('Dynamic symbol information is not available for'
379 ' displaying symbols.')
381 for section_index
, section
in symbol_tables
:
382 if not isinstance(section
, SymbolTableSection
):
385 if section
['sh_entsize'] == 0:
386 self
._emitline
("\nSymbol table '%s' has a sh_entsize of zero!" % (
390 self
._emitline
("\nSymbol table '%s' contains %s entries:" % (
391 section
.name
, section
.num_symbols()))
393 if self
.elffile
.elfclass
== 32:
394 self
._emitline
(' Num: Value Size Type Bind Vis Ndx Name')
396 self
._emitline
(' Num: Value Size Type Bind Vis Ndx Name')
398 for nsym
, symbol
in enumerate(section
.iter_symbols()):
400 # readelf doesn't display version info for Solaris versioning
401 if (section
['sh_type'] == 'SHT_DYNSYM' and
402 self
._versioninfo
['type'] == 'GNU'):
403 version
= self
._symbol
_version
(nsym
)
404 if (version
['name'] != symbol
.name
and
405 version
['index'] not in ('VER_NDX_LOCAL',
407 if version
['filename']:
409 version_info
= '@%(name)s (%(index)i)' % version
412 if version
['hidden']:
413 version_info
= '@%(name)s' % version
415 version_info
= '@@%(name)s' % version
417 # symbol names are truncated to 25 chars, similarly to readelf
418 self
._emitline
('%6d: %s %s %-7s %-6s %-7s %4s %.25s%s' % (
421 symbol
['st_value'], fullhex
=True, lead0x
=False),
422 "%5d" % symbol
['st_size'] if symbol
['st_size'] < 100000 else hex(symbol
['st_size']),
423 describe_symbol_type(symbol
['st_info']['type']),
424 describe_symbol_bind(symbol
['st_info']['bind']),
425 describe_symbol_visibility(symbol
['st_other']['visibility']),
426 describe_symbol_shndx(self
._get
_symbol
_shndx
(symbol
,
432 def display_dynamic_tags(self
):
433 """ Display the dynamic tags contained in the file
435 has_dynamic_sections
= False
436 for section
in self
.elffile
.iter_sections():
437 if not isinstance(section
, DynamicSection
):
440 has_dynamic_sections
= True
441 self
._emitline
("\nDynamic section at offset %s contains %s entries:" % (
442 self
._format
_hex
(section
['sh_offset']),
444 self
._emitline
(" Tag Type Name/Value")
446 padding
= 20 + (8 if self
.elffile
.elfclass
== 32 else 0)
447 for tag
in section
.iter_tags():
448 if tag
.entry
.d_tag
== 'DT_NEEDED':
449 parsed
= 'Shared library: [%s]' % tag
.needed
450 elif tag
.entry
.d_tag
== 'DT_RPATH':
451 parsed
= 'Library rpath: [%s]' % tag
.rpath
452 elif tag
.entry
.d_tag
== 'DT_RUNPATH':
453 parsed
= 'Library runpath: [%s]' % tag
.runpath
454 elif tag
.entry
.d_tag
== 'DT_SONAME':
455 parsed
= 'Library soname: [%s]' % tag
.soname
456 elif tag
.entry
.d_tag
.endswith(('SZ', 'ENT')):
457 parsed
= '%i (bytes)' % tag
['d_val']
458 elif tag
.entry
.d_tag
== 'DT_FLAGS':
459 parsed
= describe_dt_flags(tag
.entry
.d_val
)
460 elif tag
.entry
.d_tag
== 'DT_FLAGS_1':
461 parsed
= 'Flags: %s' % describe_dt_flags_1(tag
.entry
.d_val
)
462 elif tag
.entry
.d_tag
.endswith(('NUM', 'COUNT')):
463 parsed
= '%i' % tag
['d_val']
464 elif tag
.entry
.d_tag
== 'DT_PLTREL':
465 s
= describe_dyn_tag(tag
.entry
.d_val
)
466 if s
.startswith('DT_'):
469 elif tag
.entry
.d_tag
== 'DT_MIPS_FLAGS':
470 parsed
= describe_rh_flags(tag
.entry
.d_val
)
471 elif tag
.entry
.d_tag
in ('DT_MIPS_SYMTABNO',
472 'DT_MIPS_LOCAL_GOTNO'):
473 parsed
= str(tag
.entry
.d_val
)
475 parsed
= '%#x' % tag
['d_val']
477 self
._emitline
(" %s %-*s %s" % (
478 self
._format
_hex
(ENUM_D_TAG
.get(tag
.entry
.d_tag
, tag
.entry
.d_tag
),
479 fullhex
=True, lead0x
=True),
481 '(%s)' % (tag
.entry
.d_tag
[3:],),
483 if not has_dynamic_sections
:
484 self
._emitline
("\nThere is no dynamic section in this file.")
486 def display_notes(self
):
487 """ Display the notes contained in the file
489 for section
in self
.elffile
.iter_sections():
490 if isinstance(section
, NoteSection
):
491 for note
in section
.iter_notes():
492 self
._emitline
("\nDisplaying notes found in: {}".format(
494 self
._emitline
(' Owner Data size Description')
495 self
._emitline
(' %s %s\t%s' % (
496 note
['n_name'].ljust(20),
497 self
._format
_hex
(note
['n_descsz'], fieldsize
=8),
498 describe_note(note
)))
500 def display_relocations(self
):
501 """ Display the relocations contained in the file
503 has_relocation_sections
= False
504 for section
in self
.elffile
.iter_sections():
505 if not isinstance(section
, RelocationSection
):
508 has_relocation_sections
= True
509 self
._emitline
("\nRelocation section '%.128s' at offset %s contains %s entries:" % (
511 self
._format
_hex
(section
['sh_offset']),
512 section
.num_relocations()))
513 if section
.is_RELA():
514 self
._emitline
(" Offset Info Type Sym. Value Sym. Name + Addend")
516 self
._emitline
(" Offset Info Type Sym.Value Sym. Name")
518 # The symbol table section pointed to in sh_link
519 symtable
= self
.elffile
.get_section(section
['sh_link'])
521 for rel
in section
.iter_relocations():
522 hexwidth
= 8 if self
.elffile
.elfclass
== 32 else 12
523 self
._emit
('%s %s %-17.17s' % (
524 self
._format
_hex
(rel
['r_offset'],
525 fieldsize
=hexwidth
, lead0x
=False),
526 self
._format
_hex
(rel
['r_info'],
527 fieldsize
=hexwidth
, lead0x
=False),
529 rel
['r_info_type'], self
.elffile
)))
531 if rel
['r_info_sym'] == 0:
532 if section
.is_RELA():
533 fieldsize
= 8 if self
.elffile
.elfclass
== 32 else 16
534 addend
= self
._format
_hex
(rel
['r_addend'], lead0x
=False)
535 self
._emit
(' %s %s' % (' ' * fieldsize
, addend
))
539 symbol
= symtable
.get_symbol(rel
['r_info_sym'])
540 # Some symbols have zero 'st_name', so instead what's used
541 # is the name of the section they point at. Truncate symbol
542 # names (excluding version info) to 22 chars, similarly to
544 if symbol
['st_name'] == 0:
545 symsecidx
= self
._get
_symbol
_shndx
(symbol
,
548 symsec
= self
.elffile
.get_section(symsecidx
)
549 symbol_name
= symsec
.name
552 symbol_name
= symbol
.name
553 version
= self
._symbol
_version
(rel
['r_info_sym'])
554 version
= (version
['name']
555 if version
and version
['name'] else '')
556 symbol_name
= '%.22s' % symbol_name
558 symbol_name
+= '@' + version
560 self
._emit
(' %s %s' % (
563 fullhex
=True, lead0x
=False),
565 if section
.is_RELA():
566 self
._emit
(' %s %x' % (
567 '+' if rel
['r_addend'] >= 0 else '-',
568 abs(rel
['r_addend'])))
571 # Emit the two additional relocation types for ELF64 MIPS
573 if (self
.elffile
.elfclass
== 64 and
574 self
.elffile
['e_machine'] == 'EM_MIPS'):
576 rtype
= rel
['r_info_type%s' % i
]
577 self
._emit
(' Type%s: %s' % (
579 describe_reloc_type(rtype
, self
.elffile
)))
582 if not has_relocation_sections
:
583 self
._emitline
('\nThere are no relocations in this file.')
585 def display_arm_unwind(self
):
586 if not self
.elffile
.has_ehabi_info():
587 self
._emitline
('There are no .ARM.idx sections in this file.')
589 for ehabi_info
in self
.elffile
.get_ehabi_infos():
590 # Unwind section '.ARM.exidx' at offset 0x203e8 contains 1009 entries:
591 self
._emitline
("\nUnwind section '%s' at offset 0x%x contains %d entries" % (
592 ehabi_info
.section_name(),
593 ehabi_info
.section_offset(),
594 ehabi_info
.num_entry()
597 for i
in range(ehabi_info
.num_entry()):
598 entry
= ehabi_info
.get_entry(i
)
600 self
._emitline
("Entry %d:" % i
)
601 if isinstance(entry
, CorruptEHABIEntry
):
602 self
._emitline
(" [corrupt] %s" % entry
.reason
)
604 self
._emit
(" Function offset 0x%x: " % entry
.function_offset
)
605 if isinstance(entry
, CannotUnwindEHABIEntry
):
606 self
._emitline
("[cantunwind]")
608 elif entry
.eh_table_offset
:
609 self
._emitline
("@0x%x" % entry
.eh_table_offset
)
611 self
._emitline
("Compact (inline)")
612 if isinstance(entry
, GenericEHABIEntry
):
613 self
._emitline
(" Personality: 0x%x" % entry
.personality
)
615 self
._emitline
(" Compact model index: %d" % entry
.personality
)
616 for mnemonic_item
in entry
.mnmemonic_array():
618 self
._emitline
(mnemonic_item
)
620 def display_version_info(self
):
621 """ Display the version info contained in the file
623 self
._init
_versioninfo
()
625 if not self
._versioninfo
['type']:
626 self
._emitline
("\nNo version information found in this file.")
629 for section
in self
.elffile
.iter_sections():
630 if isinstance(section
, GNUVerSymSection
):
631 self
._print
_version
_section
_header
(
632 section
, 'Version symbols', lead0x
=False)
634 num_symbols
= section
.num_symbols()
636 # Symbol version info are printed four by four entries
637 for idx_by_4
in range(0, num_symbols
, 4):
639 self
._emit
(' %03x:' % idx_by_4
)
641 for idx
in range(idx_by_4
, min(idx_by_4
+ 4, num_symbols
)):
643 symbol_version
= self
._symbol
_version
(idx
)
644 if symbol_version
['index'] == 'VER_NDX_LOCAL':
646 version_name
= '(*local*)'
647 elif symbol_version
['index'] == 'VER_NDX_GLOBAL':
649 version_name
= '(*global*)'
651 version_index
= symbol_version
['index']
652 version_name
= '(%(name)s)' % symbol_version
654 visibility
= 'h' if symbol_version
['hidden'] else ' '
656 self
._emit
('%4x%s%-13s' % (
657 version_index
, visibility
, version_name
))
661 elif isinstance(section
, GNUVerDefSection
):
662 self
._print
_version
_section
_header
(
663 section
, 'Version definition', indent
=2)
666 for verdef
, verdaux_iter
in section
.iter_versions():
667 verdaux
= next(verdaux_iter
)
670 if verdef
['vd_flags']:
671 flags
= describe_ver_flags(verdef
['vd_flags'])
672 # Mimic exactly the readelf output
677 self
._emitline
(' %s: Rev: %i Flags: %s Index: %i'
678 ' Cnt: %i Name: %s' % (
679 self
._format
_hex
(offset
, fieldsize
=6,
681 verdef
['vd_version'], flags
, verdef
['vd_ndx'],
682 verdef
['vd_cnt'], name
))
685 offset
+ verdef
['vd_aux'] + verdaux
['vda_next'])
686 for idx
, verdaux
in enumerate(verdaux_iter
, start
=1):
687 self
._emitline
(' %s: Parent %i: %s' %
688 (self
._format
_hex
(verdaux_offset
, fieldsize
=4),
690 verdaux_offset
+= verdaux
['vda_next']
692 offset
+= verdef
['vd_next']
694 elif isinstance(section
, GNUVerNeedSection
):
695 self
._print
_version
_section
_header
(section
, 'Version needs')
698 for verneed
, verneed_iter
in section
.iter_versions():
700 self
._emitline
(' %s: Version: %i File: %s Cnt: %i' % (
701 self
._format
_hex
(offset
, fieldsize
=6,
703 verneed
['vn_version'], verneed
.name
,
706 vernaux_offset
= offset
+ verneed
['vn_aux']
707 for idx
, vernaux
in enumerate(verneed_iter
, start
=1):
708 if vernaux
['vna_flags']:
709 flags
= describe_ver_flags(vernaux
['vna_flags'])
710 # Mimic exactly the readelf output
716 ' %s: Name: %s Flags: %s Version: %i' % (
717 self
._format
_hex
(vernaux_offset
, fieldsize
=4),
719 vernaux
['vna_other']))
721 vernaux_offset
+= vernaux
['vna_next']
723 offset
+= verneed
['vn_next']
725 def display_arch_specific(self
):
726 """ Display the architecture-specific info contained in the file.
728 if self
.elffile
['e_machine'] == 'EM_ARM':
729 self
._display
_arch
_specific
_arm
()
731 def display_hex_dump(self
, section_spec
):
732 """ Display a hex dump of a section. section_spec is either a section
735 section
= self
._section
_from
_spec
(section_spec
)
737 # readelf prints the warning to stderr. Even though stderrs are not compared
738 # in tests, we comply with that behavior.
739 sys
.stderr
.write('readelf: Warning: Section \'%s\' was not dumped because it does not exist!\n' % (
742 if section
['sh_type'] == 'SHT_NOBITS':
743 self
._emitline
("\nSection '%s' has no data to dump." % (
747 self
._emitline
("\nHex dump of section '%s':" % section
.name
)
748 self
._note
_relocs
_for
_section
(section
)
749 addr
= section
['sh_addr']
750 data
= section
.data()
753 while dataptr
< len(data
):
754 bytesleft
= len(data
) - dataptr
755 # chunks of 16 bytes per line
756 linebytes
= 16 if bytesleft
> 16 else bytesleft
758 self
._emit
(' %s ' % self
._format
_hex
(addr
, fieldsize
=8))
761 self
._emit
('%2.2x' % byte2int(data
[dataptr
+ i
]))
767 for i
in range(linebytes
):
768 c
= data
[dataptr
+ i
: dataptr
+ i
+ 1]
769 if byte2int(c
[0]) >= 32 and byte2int(c
[0]) < 0x7f:
770 self
._emit
(bytes2str(c
))
772 self
._emit
(bytes2str(b
'.'))
780 def display_string_dump(self
, section_spec
):
781 """ Display a strings dump of a section. section_spec is either a
782 section number or a name.
784 section
= self
._section
_from
_spec
(section_spec
)
786 # readelf prints the warning to stderr. Even though stderrs are not compared
787 # in tests, we comply with that behavior.
788 sys
.stderr
.write('readelf.py: Warning: Section \'%s\' was not dumped because it does not exist!\n' % (
791 if section
['sh_type'] == 'SHT_NOBITS':
792 self
._emitline
("\nSection '%s' has no data to dump." % (
796 self
._emitline
("\nString dump of section '%s':" % section
.name
)
799 data
= section
.data()
802 while dataptr
< len(data
):
803 while ( dataptr
< len(data
) and
804 not (32 <= byte2int(data
[dataptr
]) <= 127)):
807 if dataptr
>= len(data
):
811 while endptr
< len(data
) and byte2int(data
[endptr
]) != 0:
815 self
._emitline
(' [%6x] %s' % (
816 dataptr
, bytes2str(data
[dataptr
:endptr
])))
821 self
._emitline
(' No strings found in this section.')
825 def display_debug_dump(self
, dump_what
):
826 """ Dump a DWARF section
828 self
._init
_dwarfinfo
()
829 if self
._dwarfinfo
is None:
832 set_global_machine_arch(self
.elffile
.get_machine_arch())
834 if dump_what
== 'info':
835 self
._dump
_debug
_info
()
836 elif dump_what
== 'decodedline':
837 self
._dump
_debug
_line
_programs
()
838 elif dump_what
== 'frames':
839 self
._dump
_debug
_frames
()
840 elif dump_what
== 'frames-interp':
841 self
._dump
_debug
_frames
_interp
()
842 elif dump_what
== 'aranges':
843 self
._dump
_debug
_aranges
()
844 elif dump_what
in { 'pubtypes', 'pubnames' }:
845 self
._dump
_debug
_namelut
(dump_what
)
846 elif dump_what
== 'loc':
847 self
._dump
_debug
_locations
()
849 self
._emitline
('debug dump not yet supported for "%s"' % dump_what
)
851 def _format_hex(self
, addr
, fieldsize
=None, fullhex
=False, lead0x
=True,
853 """ Format an address into a hexadecimal string.
856 Size of the hexadecimal field (with leading zeros to fit the
857 address into. For example with fieldsize=8, the format will
859 If None, the minimal required field size will be used.
862 If True, override fieldsize to set it to the maximal size
863 needed for the elfclass
866 If True, leading 0x is added
869 If True, override lead0x to emulate the alternate
870 hexadecimal form specified in format string with the #
871 character: only non-zero values are prefixed with 0x.
872 This form is used by readelf.
881 s
= '0x' if lead0x
else ''
883 fieldsize
= 8 if self
.elffile
.elfclass
== 32 else 16
884 if fieldsize
is None:
887 field
= '%' + '0%sx' % fieldsize
888 return s
+ field
% addr
890 def _print_version_section_header(self
, version_section
, name
, lead0x
=True,
892 """ Print a section header of one version related section (versym,
893 verneed or verdef) with some options to accomodate readelf
894 little differences between each header (e.g. indentation
897 if hasattr(version_section
, 'num_versions'):
898 num_entries
= version_section
.num_versions()
900 num_entries
= version_section
.num_symbols()
902 self
._emitline
("\n%s section '%s' contains %s entries:" %
903 (name
, version_section
.name
, num_entries
))
904 self
._emitline
('%sAddr: %s Offset: %s Link: %i (%s)' % (
907 version_section
['sh_addr'], fieldsize
=16, lead0x
=lead0x
),
909 version_section
['sh_offset'], fieldsize
=6, lead0x
=True),
910 version_section
['sh_link'],
911 self
.elffile
.get_section(version_section
['sh_link']).name
915 def _init_versioninfo(self
):
916 """ Search and initialize informations about version related sections
917 and the kind of versioning used (GNU or Solaris).
919 if self
._versioninfo
is not None:
922 self
._versioninfo
= {'versym': None, 'verdef': None,
923 'verneed': None, 'type': None}
925 for section
in self
.elffile
.iter_sections():
926 if isinstance(section
, GNUVerSymSection
):
927 self
._versioninfo
['versym'] = section
928 elif isinstance(section
, GNUVerDefSection
):
929 self
._versioninfo
['verdef'] = section
930 elif isinstance(section
, GNUVerNeedSection
):
931 self
._versioninfo
['verneed'] = section
932 elif isinstance(section
, DynamicSection
):
933 for tag
in section
.iter_tags():
934 if tag
['d_tag'] == 'DT_VERSYM':
935 self
._versioninfo
['type'] = 'GNU'
938 if not self
._versioninfo
['type'] and (
939 self
._versioninfo
['verneed'] or self
._versioninfo
['verdef']):
940 self
._versioninfo
['type'] = 'Solaris'
942 def _symbol_version(self
, nsym
):
943 """ Return a dict containing information on the
944 or None if no version information is available
946 self
._init
_versioninfo
()
948 symbol_version
= dict.fromkeys(('index', 'name', 'filename', 'hidden'))
950 if (not self
._versioninfo
['versym'] or
951 nsym
>= self
._versioninfo
['versym'].num_symbols()):
954 symbol
= self
._versioninfo
['versym'].get_symbol(nsym
)
955 index
= symbol
.entry
['ndx']
956 if not index
in ('VER_NDX_LOCAL', 'VER_NDX_GLOBAL'):
959 if self
._versioninfo
['type'] == 'GNU':
960 # In GNU versioning mode, the highest bit is used to
961 # store whether the symbol is hidden or not
964 symbol_version
['hidden'] = True
966 if (self
._versioninfo
['verdef'] and
967 index
<= self
._versioninfo
['verdef'].num_versions()):
969 self
._versioninfo
['verdef'].get_version(index
)
970 symbol_version
['name'] = next(verdaux_iter
).name
973 self
._versioninfo
['verneed'].get_version(index
)
974 symbol_version
['name'] = vernaux
.name
975 symbol_version
['filename'] = verneed
.name
977 symbol_version
['index'] = index
978 return symbol_version
980 def _section_from_spec(self
, spec
):
981 """ Retrieve a section given a "spec" (either number or name).
982 Return None if no such section exists in the file.
986 if num
< self
.elffile
.num_sections():
987 return self
.elffile
.get_section(num
)
991 # Not a number. Must be a name then
992 return self
.elffile
.get_section_by_name(spec
)
994 def _get_symbol_shndx(self
, symbol
, symbol_index
, symtab_index
):
995 """ Get the index into the section header table for the "symbol"
996 at "symbol_index" located in the symbol table with section index
999 symbol_shndx
= symbol
['st_shndx']
1000 if symbol_shndx
!= SHN_INDICES
.SHN_XINDEX
:
1003 # Check for or lazily construct index section mapping (symbol table
1004 # index -> corresponding symbol table index section object)
1005 if self
._shndx
_sections
is None:
1006 self
._shndx
_sections
= {sec
.symboltable
: sec
for sec
in self
.elffile
.iter_sections()
1007 if isinstance(sec
, SymbolTableIndexSection
)}
1008 return self
._shndx
_sections
[symtab_index
].get_section_index(symbol_index
)
1010 def _note_relocs_for_section(self
, section
):
1011 """ If there are relocation sections pointing to the givne section,
1012 emit a note about it.
1014 for relsec
in self
.elffile
.iter_sections():
1015 if isinstance(relsec
, RelocationSection
):
1016 info_idx
= relsec
['sh_info']
1017 if self
.elffile
.get_section(info_idx
) == section
:
1018 self
._emitline
(' Note: This section has relocations against it, but these have NOT been applied to this dump.')
1021 def _init_dwarfinfo(self
):
1022 """ Initialize the DWARF info contained in the file and assign it to
1024 Leave self._dwarfinfo at None if no DWARF info was found in the file
1026 if self
._dwarfinfo
is not None:
1029 if self
.elffile
.has_dwarf_info():
1030 self
._dwarfinfo
= self
.elffile
.get_dwarf_info()
1032 self
._dwarfinfo
= None
1034 def _dump_debug_info(self
):
1035 """ Dump the debugging info section.
1037 if not self
._dwarfinfo
.has_debug_info
:
1039 self
._emitline
('Contents of the %s section:\n' % self
._dwarfinfo
.debug_info_sec
.name
)
1041 # Offset of the .debug_info section in the stream
1042 section_offset
= self
._dwarfinfo
.debug_info_sec
.global_offset
1044 for cu
in self
._dwarfinfo
.iter_CUs():
1045 self
._emitline
(' Compilation Unit @ offset %s:' %
1046 self
._format
_hex
(cu
.cu_offset
))
1047 self
._emitline
(' Length: %s (%s)' % (
1048 self
._format
_hex
(cu
['unit_length']),
1049 '%s-bit' % cu
.dwarf_format()))
1050 self
._emitline
(' Version: %s' % cu
['version']),
1051 self
._emitline
(' Abbrev Offset: %s' % (
1052 self
._format
_hex
(cu
['debug_abbrev_offset']))),
1053 self
._emitline
(' Pointer Size: %s' % cu
['address_size'])
1055 # The nesting depth of each DIE within the tree of DIEs must be
1056 # displayed. To implement this, a counter is incremented each time
1057 # the current DIE has children, and decremented when a null die is
1058 # encountered. Due to the way the DIE tree is serialized, this will
1059 # correctly reflect the nesting depth
1062 current_function
= None
1063 for die
in cu
.iter_DIEs():
1064 if die
.tag
== 'DW_TAG_subprogram':
1065 current_function
= die
1066 self
._emitline
(' <%s><%x>: Abbrev Number: %s%s' % (
1070 (' (%s)' % die
.tag
) if not die
.is_null() else ''))
1075 for attr
in itervalues(die
.attributes
):
1077 # Unknown attribute values are passed-through as integers
1078 if isinstance(name
, int):
1079 name
= 'Unknown AT value: %x' % name
1081 attr_desc
= describe_attr_value(attr
, die
, section_offset
)
1083 if 'DW_OP_fbreg' in attr_desc
and current_function
and not 'DW_AT_frame_base' in current_function
.attributes
:
1084 postfix
= ' [without dw_at_frame_base]'
1088 self
._emitline
(' <%x> %-18s: %s%s' % (
1094 if die
.has_children
:
1099 def _dump_debug_line_programs(self
):
1100 """ Dump the (decoded) line programs from .debug_line
1101 The programs are dumped in the order of the CUs they belong to.
1103 if not self
._dwarfinfo
.has_debug_info
:
1105 self
._emitline
('Decoded dump of debug contents of section %s:\n' % self
._dwarfinfo
.debug_line_sec
.name
)
1107 for cu
in self
._dwarfinfo
.iter_CUs():
1108 lineprogram
= self
._dwarfinfo
.line_program_for_CU(cu
)
1110 cu_filename
= bytes2str(lineprogram
['file_entry'][0].name
)
1111 if len(lineprogram
['include_directory']) > 0:
1112 dir_index
= lineprogram
['file_entry'][0].dir_index
1114 dir = lineprogram
['include_directory'][dir_index
- 1]
1117 cu_filename
= '%s/%s' % (bytes2str(dir), cu_filename
)
1119 self
._emitline
('CU: %s:' % cu_filename
)
1120 self
._emitline
('File name Line number Starting address')
1122 # Print each state's file, line and address information. For some
1123 # instructions other output is needed to be compatible with
1125 for entry
in lineprogram
.get_entries():
1128 # Special handling for commands that don't set a new state
1129 if entry
.command
== DW_LNS_set_file
:
1130 file_entry
= lineprogram
['file_entry'][entry
.args
[0] - 1]
1131 if file_entry
.dir_index
== 0:
1133 self
._emitline
('\n./%s:[++]' % (
1134 bytes2str(file_entry
.name
)))
1136 self
._emitline
('\n%s/%s:' % (
1137 bytes2str(lineprogram
['include_directory'][file_entry
.dir_index
- 1]),
1138 bytes2str(file_entry
.name
)))
1139 elif entry
.command
== DW_LNE_define_file
:
1140 self
._emitline
('%s:' % (
1141 bytes2str(lineprogram
['include_directory'][entry
.args
[0].dir_index
])))
1142 elif not state
.end_sequence
:
1143 # readelf doesn't print the state after end_sequence
1144 # instructions. I think it's a bug but to be compatible
1145 # I don't print them too.
1146 if lineprogram
['version'] < 4:
1147 self
._emitline
('%-35s %11d %18s' % (
1148 bytes2str(lineprogram
['file_entry'][state
.file - 1].name
),
1150 '0' if state
.address
== 0 else
1151 self
._format
_hex
(state
.address
)))
1153 self
._emitline
('%-35s %11d %18s[%d]' % (
1154 bytes2str(lineprogram
['file_entry'][state
.file - 1].name
),
1156 '0' if state
.address
== 0 else
1157 self
._format
_hex
(state
.address
),
1159 if entry
.command
== DW_LNS_copy
:
1160 # Another readelf oddity...
1163 def _dump_frames_info(self
, section
, cfi_entries
):
1164 """ Dump the raw call frame info in a section.
1166 `section` is the Section instance that contains the call frame info
1167 while `cfi_entries` must be an iterable that yields the sequence of
1168 CIE or FDE instances.
1170 self
._emitline
('Contents of the %s section:' % section
.name
)
1172 for entry
in cfi_entries
:
1173 if isinstance(entry
, CIE
):
1174 self
._emitline
('\n%08x %s %s CIE' % (
1176 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1177 self
._format
_hex
(entry
['CIE_id'], fieldsize
=8, lead0x
=False)))
1178 self
._emitline
(' Version: %d' % entry
['version'])
1179 self
._emitline
(' Augmentation: "%s"' % bytes2str(entry
['augmentation']))
1180 self
._emitline
(' Code alignment factor: %u' % entry
['code_alignment_factor'])
1181 self
._emitline
(' Data alignment factor: %d' % entry
['data_alignment_factor'])
1182 self
._emitline
(' Return address column: %d' % entry
['return_address_register'])
1183 if entry
.augmentation_bytes
:
1184 self
._emitline
(' Augmentation data: {}'.format(' '.join(
1185 '{:02x}'.format(ord(b
))
1186 for b
in iterbytes(entry
.augmentation_bytes
)
1190 elif isinstance(entry
, FDE
):
1191 self
._emitline
('\n%08x %s %s FDE cie=%08x pc=%s..%s' % (
1193 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1194 self
._format
_hex
(entry
['CIE_pointer'], fieldsize
=8, lead0x
=False),
1196 self
._format
_hex
(entry
['initial_location'], fullhex
=True, lead0x
=False),
1198 entry
['initial_location'] + entry
['address_range'],
1199 fullhex
=True, lead0x
=False)))
1200 if entry
.augmentation_bytes
:
1201 self
._emitline
(' Augmentation data: {}'.format(' '.join(
1202 '{:02x}'.format(ord(b
))
1203 for b
in iterbytes(entry
.augmentation_bytes
)
1206 else: # ZERO terminator
1207 assert isinstance(entry
, ZERO
)
1208 self
._emitline
('\n%08x ZERO terminator' % entry
.offset
)
1211 self
._emit
(describe_CFI_instructions(entry
))
1214 def _dump_debug_frames(self
):
1215 """ Dump the raw frame info from .debug_frame and .eh_frame sections.
1217 if self
._dwarfinfo
.has_EH_CFI():
1218 self
._dump
_frames
_info
(
1219 self
._dwarfinfo
.eh_frame_sec
,
1220 self
._dwarfinfo
.EH_CFI_entries())
1223 if self
._dwarfinfo
.has_CFI():
1224 self
._dump
_frames
_info
(
1225 self
._dwarfinfo
.debug_frame_sec
,
1226 self
._dwarfinfo
.CFI_entries())
1228 def _dump_debug_namelut(self
, what
):
1230 Dump the debug pubnames section.
1232 if what
== 'pubnames':
1233 namelut
= self
._dwarfinfo
.get_pubnames()
1234 section
= self
._dwarfinfo
.debug_pubnames_sec
1236 namelut
= self
._dwarfinfo
.get_pubtypes()
1237 section
= self
._dwarfinfo
.debug_pubtypes_sec
1239 # readelf prints nothing if the section is not present.
1240 if namelut
is None or len(namelut
) == 0:
1243 self
._emitline
('Contents of the %s section:' % section
.name
)
1246 cu_headers
= namelut
.get_cu_headers()
1248 # go over CU-by-CU first and item-by-item next.
1249 for (cu_hdr
, (cu_ofs
, items
)) in izip(cu_headers
, itertools
.groupby(
1250 namelut
.items(), key
= lambda x
: x
[1].cu_ofs
)):
1252 self
._emitline
(' Length: %d' % cu_hdr
.unit_length
)
1253 self
._emitline
(' Version: %d' % cu_hdr
.version
)
1254 self
._emitline
(' Offset into .debug_info section: 0x%x' % cu_hdr
.debug_info_offset
)
1255 self
._emitline
(' Size of area in .debug_info section: %d' % cu_hdr
.debug_info_length
)
1257 self
._emitline
(' Offset Name')
1259 self
._emitline
(' %x %s' % (item
[1].die_ofs
- cu_ofs
, item
[0]))
1262 def _dump_debug_aranges(self
):
1263 """ Dump the aranges table
1265 aranges_table
= self
._dwarfinfo
.get_aranges()
1266 if aranges_table
== None:
1268 # seems redundent, but we need to get the unsorted set of entries to match system readelf
1269 unordered_entries
= aranges_table
._get
_entries
()
1271 if len(unordered_entries
) == 0:
1273 self
._emitline
("Section '.debug_aranges' has no debugging data.")
1276 self
._emitline
('Contents of the %s section:' % self
._dwarfinfo
.debug_aranges_sec
.name
)
1279 for entry
in unordered_entries
:
1280 if prev_offset
!= entry
.info_offset
:
1281 if entry
!= unordered_entries
[0]:
1282 self
._emitline
(' %s %s' % (
1283 self
._format
_hex
(0, fullhex
=True, lead0x
=False),
1284 self
._format
_hex
(0, fullhex
=True, lead0x
=False)))
1285 self
._emitline
(' Length: %d' % (entry
.unit_length
))
1286 self
._emitline
(' Version: %d' % (entry
.version
))
1287 self
._emitline
(' Offset into .debug_info: 0x%x' % (entry
.info_offset
))
1288 self
._emitline
(' Pointer Size: %d' % (entry
.address_size
))
1289 self
._emitline
(' Segment Size: %d' % (entry
.segment_size
))
1291 self
._emitline
(' Address Length')
1292 self
._emitline
(' %s %s' % (
1293 self
._format
_hex
(entry
.begin_addr
, fullhex
=True, lead0x
=False),
1294 self
._format
_hex
(entry
.length
, fullhex
=True, lead0x
=False)))
1295 prev_offset
= entry
.info_offset
1296 self
._emitline
(' %s %s' % (
1297 self
._format
_hex
(0, fullhex
=True, lead0x
=False),
1298 self
._format
_hex
(0, fullhex
=True, lead0x
=False)))
1300 def _dump_frames_interp_info(self
, section
, cfi_entries
):
1301 """ Dump interpreted (decoded) frame information in a section.
1303 `section` is the Section instance that contains the call frame info
1304 while `cfi_entries` must be an iterable that yields the sequence of
1305 CIE or FDE instances.
1307 self
._emitline
('Contents of the %s section:' % section
.name
)
1309 for entry
in cfi_entries
:
1310 if isinstance(entry
, CIE
):
1311 self
._emitline
('\n%08x %s %s CIE "%s" cf=%d df=%d ra=%d' % (
1313 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1314 self
._format
_hex
(entry
['CIE_id'], fieldsize
=8, lead0x
=False),
1315 bytes2str(entry
['augmentation']),
1316 entry
['code_alignment_factor'],
1317 entry
['data_alignment_factor'],
1318 entry
['return_address_register']))
1319 ra_regnum
= entry
['return_address_register']
1321 elif isinstance(entry
, FDE
):
1322 self
._emitline
('\n%08x %s %s FDE cie=%08x pc=%s..%s' % (
1324 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1325 self
._format
_hex
(entry
['CIE_pointer'], fieldsize
=8, lead0x
=False),
1327 self
._format
_hex
(entry
['initial_location'], fullhex
=True, lead0x
=False),
1328 self
._format
_hex
(entry
['initial_location'] + entry
['address_range'],
1329 fullhex
=True, lead0x
=False)))
1330 ra_regnum
= entry
.cie
['return_address_register']
1332 # If the FDE brings adds no unwinding information compared to
1333 # its CIE, omit its table.
1334 if (len(entry
.get_decoded().table
) ==
1335 len(entry
.cie
.get_decoded().table
)):
1338 else: # ZERO terminator
1339 assert isinstance(entry
, ZERO
)
1340 self
._emitline
('\n%08x ZERO terminator' % entry
.offset
)
1344 decoded_table
= entry
.get_decoded()
1345 if len(decoded_table
.table
) == 0:
1348 # Print the heading row for the decoded table
1350 self
._emit
(' ' if entry
.structs
.address_size
== 4 else ' ')
1353 # Look at the registers the decoded table describes.
1354 # We build reg_order here to match readelf's order. In particular,
1355 # registers are sorted by their number, and the register matching
1356 # ra_regnum is always listed last with a special heading.
1357 decoded_table
= entry
.get_decoded()
1358 reg_order
= sorted(ifilter(
1359 lambda r
: r
!= ra_regnum
,
1360 decoded_table
.reg_order
))
1361 if len(decoded_table
.reg_order
):
1363 # Headings for the registers
1364 for regnum
in reg_order
:
1365 self
._emit
('%-6s' % describe_reg_name(regnum
))
1366 self
._emitline
('ra ')
1368 # Now include ra_regnum in reg_order to print its values
1369 # similarly to the other registers.
1370 reg_order
.append(ra_regnum
)
1374 for line
in decoded_table
.table
:
1375 self
._emit
(self
._format
_hex
(
1376 line
['pc'], fullhex
=True, lead0x
=False))
1378 if line
['cfa'] is not None:
1379 s
= describe_CFI_CFA_rule(line
['cfa'])
1382 self
._emit
(' %-9s' % s
)
1384 for regnum
in reg_order
:
1386 s
= describe_CFI_register_rule(line
[regnum
])
1389 self
._emit
('%-6s' % s
)
1393 def _dump_debug_frames_interp(self
):
1394 """ Dump the interpreted (decoded) frame information from .debug_frame
1395 and .eh_framae sections.
1397 if self
._dwarfinfo
.has_EH_CFI():
1398 self
._dump
_frames
_interp
_info
(
1399 self
._dwarfinfo
.eh_frame_sec
,
1400 self
._dwarfinfo
.EH_CFI_entries())
1403 if self
._dwarfinfo
.has_CFI():
1404 self
._dump
_frames
_interp
_info
(
1405 self
._dwarfinfo
.debug_frame_sec
,
1406 self
._dwarfinfo
.CFI_entries())
1408 def _dump_debug_locations(self
):
1409 """ Dump the location lists from .debug_location section
1411 def _get_cu_base(cu
):
1412 top_die
= cu
.get_top_DIE()
1413 attr
= top_die
.attributes
1414 if 'DW_AT_low_pc' in attr
:
1415 return attr
['DW_AT_low_pc'].value
1416 elif 'DW_AT_entry_pc' in attr
:
1417 return attr
['DW_AT_entry_pc'].value
1419 raise ValueError("Can't find the base IP (low_pc) for a CU")
1421 di
= self
._dwarfinfo
1422 loc_lists
= di
.location_lists()
1423 if not loc_lists
: # No locations section - readelf outputs nothing
1426 loc_lists
= list(loc_lists
.iter_location_lists())
1427 if len(loc_lists
) == 0:
1428 # Present but empty locations section - readelf outputs a message
1429 self
._emitline
("\nSection '%s' has no debugging data." % di
.debug_loc_sec
.name
)
1432 # To dump a location list, one needs to know the CU.
1433 # Scroll through DIEs once, list the known location list offsets
1434 cu_map
= dict() # Loc list offset => CU
1435 for cu
in di
.iter_CUs():
1436 for die
in cu
.iter_DIEs():
1437 for key
in die
.attributes
:
1438 attr
= die
.attributes
[key
]
1439 if (LocationParser
.attribute_has_location(attr
, cu
['version']) and
1440 not LocationParser
._attribute
_has
_loc
_expr
(attr
, cu
['version'])):
1441 cu_map
[attr
.value
] = cu
1443 addr_size
= di
.config
.default_address_size
# In bytes, 4 or 8
1444 addr_width
= addr_size
* 2 # In hex digits, 8 or 16
1445 line_template
= " %%08x %%0%dx %%0%dx %%s%%s" % (addr_width
, addr_width
)
1447 self
._emitline
('Contents of the %s section:\n' % di
.debug_loc_sec
.name
)
1448 self
._emitline
(' Offset Begin End Expression')
1449 for loc_list
in loc_lists
:
1450 cu
= cu_map
.get(loc_list
[0].entry_offset
, False)
1452 raise ValueError("Location list can't be tracked to a CU")
1453 base_ip
= _get_cu_base(cu
)
1454 for entry
in loc_list
:
1455 # TODO: support BaseAddressEntry lines
1456 expr
= describe_DWARF_expr(entry
.loc_expr
, cu
.structs
, cu
.cu_offset
)
1457 postfix
= ' (start == end)' if entry
.begin_offset
== entry
.end_offset
else ''
1458 self
._emitline
(line_template
% (
1460 base_ip
+ entry
.begin_offset
,
1461 base_ip
+ entry
.end_offset
,
1464 # Pyelftools doesn't store the terminating entry,
1465 # but readelf emits its offset, so this should too.
1467 last_len
= 2*addr_size
1468 if isinstance(last
, LocationEntry
):
1469 last_len
+= 2 + len(last
.loc_expr
)
1470 self
._emitline
(" %08x <End of list>" % (last
.entry_offset
+ last_len
))
1472 def _display_arch_specific_arm(self
):
1473 """ Display the ARM architecture-specific info contained in the file.
1475 attr_sec
= self
.elffile
.get_section_by_name('.ARM.attributes')
1477 for s
in attr_sec
.iter_subsections():
1478 self
._emitline
("Attribute Section: %s" % s
.header
['vendor_name'])
1479 for ss
in s
.iter_subsubsections():
1480 h_val
= "" if ss
.header
.extra
is None else " ".join("%d" % x
for x
in ss
.header
.extra
)
1481 self
._emitline
(describe_attr_tag_arm(ss
.header
.tag
, h_val
, None))
1483 for attr
in ss
.iter_attributes():
1485 self
._emitline
(describe_attr_tag_arm(attr
.tag
,
1489 def _emit(self
, s
=''):
1490 """ Emit an object to output
1492 self
.output
.write(str(s
))
1494 def _emitline(self
, s
=''):
1495 """ Emit an object to output, followed by a newline
1497 self
.output
.write(str(s
).rstrip() + '\n')
1500 SCRIPT_DESCRIPTION
= 'Display information about the contents of ELF format files'
1501 VERSION_STRING
= '%%(prog)s: based on pyelftools %s' % __version__
1504 def main(stream
=None):
1505 # parse the command-line arguments and invoke ReadElf
1506 argparser
= argparse
.ArgumentParser(
1507 usage
='usage: %(prog)s [options] <elf-file>',
1508 description
=SCRIPT_DESCRIPTION
,
1509 add_help
=False, # -h is a real option of readelf
1511 argparser
.add_argument('file',
1512 nargs
='?', default
=None,
1513 help='ELF file to parse')
1514 argparser
.add_argument('-v', '--version',
1515 action
='version', version
=VERSION_STRING
)
1516 argparser
.add_argument('-d', '--dynamic',
1517 action
='store_true', dest
='show_dynamic_tags',
1518 help='Display the dynamic section')
1519 argparser
.add_argument('-H', '--help',
1520 action
='store_true', dest
='help',
1521 help='Display this information')
1522 argparser
.add_argument('-h', '--file-header',
1523 action
='store_true', dest
='show_file_header',
1524 help='Display the ELF file header')
1525 argparser
.add_argument('-l', '--program-headers', '--segments',
1526 action
='store_true', dest
='show_program_header',
1527 help='Display the program headers')
1528 argparser
.add_argument('-S', '--section-headers', '--sections',
1529 action
='store_true', dest
='show_section_header',
1530 help="Display the sections' headers")
1531 argparser
.add_argument('-e', '--headers',
1532 action
='store_true', dest
='show_all_headers',
1533 help='Equivalent to: -h -l -S')
1534 argparser
.add_argument('-s', '--symbols', '--syms',
1535 action
='store_true', dest
='show_symbols',
1536 help='Display the symbol table')
1537 argparser
.add_argument('-n', '--notes',
1538 action
='store_true', dest
='show_notes',
1539 help='Display the core notes (if present)')
1540 argparser
.add_argument('-r', '--relocs',
1541 action
='store_true', dest
='show_relocs',
1542 help='Display the relocations (if present)')
1543 argparser
.add_argument('-au', '--arm-unwind',
1544 action
='store_true', dest
='show_arm_unwind',
1545 help='Display the armeabi unwind information (if present)')
1546 argparser
.add_argument('-x', '--hex-dump',
1547 action
='store', dest
='show_hex_dump', metavar
='<number|name>',
1548 help='Dump the contents of section <number|name> as bytes')
1549 argparser
.add_argument('-p', '--string-dump',
1550 action
='store', dest
='show_string_dump', metavar
='<number|name>',
1551 help='Dump the contents of section <number|name> as strings')
1552 argparser
.add_argument('-V', '--version-info',
1553 action
='store_true', dest
='show_version_info',
1554 help='Display the version sections (if present)')
1555 argparser
.add_argument('-A', '--arch-specific',
1556 action
='store_true', dest
='show_arch_specific',
1557 help='Display the architecture-specific information (if present)')
1558 argparser
.add_argument('--debug-dump',
1559 action
='store', dest
='debug_dump_what', metavar
='<what>',
1561 'Display the contents of DWARF debug sections. <what> can ' +
1562 'one of {info,decodedline,frames,frames-interp,aranges,pubtypes,pubnames,loc}'))
1563 argparser
.add_argument('--traceback',
1564 action
='store_true', dest
='show_traceback',
1565 help='Dump the Python traceback on ELFError'
1566 ' exceptions from elftools')
1568 args
= argparser
.parse_args()
1570 if args
.help or not args
.file:
1571 argparser
.print_help()
1574 if args
.show_all_headers
:
1575 do_file_header
= do_section_header
= do_program_header
= True
1577 do_file_header
= args
.show_file_header
1578 do_section_header
= args
.show_section_header
1579 do_program_header
= args
.show_program_header
1581 with
open(args
.file, 'rb') as file:
1583 readelf
= ReadElf(file, stream
or sys
.stdout
)
1585 readelf
.display_file_header()
1586 if do_section_header
:
1587 readelf
.display_section_headers(
1588 show_heading
=not do_file_header
)
1589 if do_program_header
:
1590 readelf
.display_program_headers(
1591 show_heading
=not do_file_header
)
1592 if args
.show_dynamic_tags
:
1593 readelf
.display_dynamic_tags()
1594 if args
.show_symbols
:
1595 readelf
.display_symbol_tables()
1597 readelf
.display_notes()
1598 if args
.show_relocs
:
1599 readelf
.display_relocations()
1600 if args
.show_arm_unwind
:
1601 readelf
.display_arm_unwind()
1602 if args
.show_version_info
:
1603 readelf
.display_version_info()
1604 if args
.show_arch_specific
:
1605 readelf
.display_arch_specific()
1606 if args
.show_hex_dump
:
1607 readelf
.display_hex_dump(args
.show_hex_dump
)
1608 if args
.show_string_dump
:
1609 readelf
.display_string_dump(args
.show_string_dump
)
1610 if args
.debug_dump_what
:
1611 readelf
.display_debug_dump(args
.debug_dump_what
)
1612 except ELFError
as ex
:
1614 sys
.stderr
.write('ELF error: %s\n' % ex
)
1615 if args
.show_traceback
:
1616 traceback
.print_exc()
1621 # Run 'main' redirecting its output to readelfout.txt
1622 # Saves profiling information in readelf.profile
1623 PROFFILE
= 'readelf.profile'
1625 cProfile
.run('main(open("readelfout.txt", "w"))', PROFFILE
)
1627 # Dig in some profiling stats
1629 p
= pstats
.Stats(PROFFILE
)
1630 p
.sort_stats('cumulative').print_stats(25)
1633 #-------------------------------------------------------------------------------
1634 if __name__
== '__main__':