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
,
51 describe_attr_tag_arm
, describe_symbol_other
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_PPC64':
177 if flags
& E_FLAGS
.EF_PPC64_ABI_V2
:
178 description
+= ', abiv2'
180 elif self
.elffile
['e_machine'] == "EM_MIPS":
181 if flags
& E_FLAGS
.EF_MIPS_NOREORDER
:
182 description
+= ", noreorder"
183 if flags
& E_FLAGS
.EF_MIPS_PIC
:
184 description
+= ", pic"
185 if flags
& E_FLAGS
.EF_MIPS_CPIC
:
186 description
+= ", cpic"
187 if (flags
& E_FLAGS
.EF_MIPS_ABI2
):
188 description
+= ", abi2"
189 if (flags
& E_FLAGS
.EF_MIPS_32BITMODE
):
190 description
+= ", 32bitmode"
191 if (flags
& E_FLAGS_MASKS
.EFM_MIPS_ABI_O32
):
192 description
+= ", o32"
193 elif (flags
& E_FLAGS_MASKS
.EFM_MIPS_ABI_O64
):
194 description
+= ", o64"
195 elif (flags
& E_FLAGS_MASKS
.EFM_MIPS_ABI_EABI32
):
196 description
+= ", eabi32"
197 elif (flags
& E_FLAGS_MASKS
.EFM_MIPS_ABI_EABI64
):
198 description
+= ", eabi64"
199 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_1
:
200 description
+= ", mips1"
201 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_2
:
202 description
+= ", mips2"
203 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_3
:
204 description
+= ", mips3"
205 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_4
:
206 description
+= ", mips4"
207 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_5
:
208 description
+= ", mips5"
209 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_32R2
:
210 description
+= ", mips32r2"
211 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_64R2
:
212 description
+= ", mips64r2"
213 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_32
:
214 description
+= ", mips32"
215 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_64
:
216 description
+= ", mips64"
220 def display_program_headers(self
, show_heading
=True):
221 """ Display the ELF program headers.
222 If show_heading is True, displays the heading for this information
223 (Elf file type is...)
226 if self
.elffile
.num_segments() == 0:
227 self
._emitline
('There are no program headers in this file.')
230 elfheader
= self
.elffile
.header
232 self
._emitline
('Elf file type is %s' %
233 describe_e_type(elfheader
['e_type']))
234 self
._emitline
('Entry point is %s' %
235 self
._format
_hex
(elfheader
['e_entry']))
236 # readelf weirness - why isn't e_phoff printed as hex? (for section
238 self
._emitline
('There are %s program headers, starting at offset %s' % (
239 self
.elffile
.num_segments(), elfheader
['e_phoff']))
242 self
._emitline
('Program Headers:')
244 # Now comes the table of program headers with their attributes. Note
245 # that due to different formatting constraints of 32-bit and 64-bit
246 # addresses, there are some conditions on elfclass here.
248 # First comes the table heading
250 if self
.elffile
.elfclass
== 32:
251 self
._emitline
(' Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align')
253 self
._emitline
(' Type Offset VirtAddr PhysAddr')
254 self
._emitline
(' FileSiz MemSiz Flags Align')
258 for segment
in self
.elffile
.iter_segments():
259 self
._emit
(' %-14s ' % describe_p_type(segment
['p_type']))
261 if self
.elffile
.elfclass
== 32:
262 self
._emitline
('%s %s %s %s %s %-3s %s' % (
263 self
._format
_hex
(segment
['p_offset'], fieldsize
=6),
264 self
._format
_hex
(segment
['p_vaddr'], fullhex
=True),
265 self
._format
_hex
(segment
['p_paddr'], fullhex
=True),
266 self
._format
_hex
(segment
['p_filesz'], fieldsize
=5),
267 self
._format
_hex
(segment
['p_memsz'], fieldsize
=5),
268 describe_p_flags(segment
['p_flags']),
269 self
._format
_hex
(segment
['p_align'])))
271 self
._emitline
('%s %s %s' % (
272 self
._format
_hex
(segment
['p_offset'], fullhex
=True),
273 self
._format
_hex
(segment
['p_vaddr'], fullhex
=True),
274 self
._format
_hex
(segment
['p_paddr'], fullhex
=True)))
275 self
._emitline
(' %s %s %-3s %s' % (
276 self
._format
_hex
(segment
['p_filesz'], fullhex
=True),
277 self
._format
_hex
(segment
['p_memsz'], fullhex
=True),
278 describe_p_flags(segment
['p_flags']),
279 # lead0x set to False for p_align, to mimic readelf.
280 # No idea why the difference from 32-bit mode :-|
281 self
._format
_hex
(segment
['p_align'], lead0x
=False)))
283 if isinstance(segment
, InterpSegment
):
284 self
._emitline
(' [Requesting program interpreter: %s]' %
285 segment
.get_interp_name())
287 # Sections to segments mapping
289 if self
.elffile
.num_sections() == 0:
290 # No sections? We're done
293 self
._emitline
('\n Section to Segment mapping:')
294 self
._emitline
(' Segment Sections...')
296 for nseg
, segment
in enumerate(self
.elffile
.iter_segments()):
297 self
._emit
(' %2.2d ' % nseg
)
299 for section
in self
.elffile
.iter_sections():
300 if ( not section
.is_null() and
301 not ((section
['sh_flags'] & SH_FLAGS
.SHF_TLS
) != 0 and
302 section
['sh_type'] == 'SHT_NOBITS' and
303 segment
['p_type'] != 'PT_TLS') and
304 segment
.section_in_segment(section
)):
305 self
._emit
('%s ' % section
.name
)
309 def display_section_headers(self
, show_heading
=True):
310 """ Display the ELF section headers
312 elfheader
= self
.elffile
.header
314 self
._emitline
('There are %s section headers, starting at offset %s' % (
315 elfheader
['e_shnum'], self
._format
_hex
(elfheader
['e_shoff'])))
317 if self
.elffile
.num_sections() == 0:
318 self
._emitline
('There are no sections in this file.')
321 self
._emitline
('\nSection Header%s:' % (
322 's' if self
.elffile
.num_sections() > 1 else ''))
324 # Different formatting constraints of 32-bit and 64-bit addresses
326 if self
.elffile
.elfclass
== 32:
327 self
._emitline
(' [Nr] Name Type Addr Off Size ES Flg Lk Inf Al')
329 self
._emitline
(' [Nr] Name Type Address Offset')
330 self
._emitline
(' Size EntSize Flags Link Info Align')
334 for nsec
, section
in enumerate(self
.elffile
.iter_sections()):
335 self
._emit
(' [%2u] %-17.17s %-15.15s ' % (
336 nsec
, section
.name
, describe_sh_type(section
['sh_type'])))
338 if self
.elffile
.elfclass
== 32:
339 self
._emitline
('%s %s %s %s %3s %2s %3s %2s' % (
340 self
._format
_hex
(section
['sh_addr'], fieldsize
=8, lead0x
=False),
341 self
._format
_hex
(section
['sh_offset'], fieldsize
=6, lead0x
=False),
342 self
._format
_hex
(section
['sh_size'], fieldsize
=6, lead0x
=False),
343 self
._format
_hex
(section
['sh_entsize'], fieldsize
=2, lead0x
=False),
344 describe_sh_flags(section
['sh_flags']),
345 section
['sh_link'], section
['sh_info'],
346 section
['sh_addralign']))
348 self
._emitline
(' %s %s' % (
349 self
._format
_hex
(section
['sh_addr'], fullhex
=True, lead0x
=False),
350 self
._format
_hex
(section
['sh_offset'],
351 fieldsize
=16 if section
['sh_offset'] > 0xffffffff else 8,
353 self
._emitline
(' %s %s %3s %2s %3s %s' % (
354 self
._format
_hex
(section
['sh_size'], fullhex
=True, lead0x
=False),
355 self
._format
_hex
(section
['sh_entsize'], fullhex
=True, lead0x
=False),
356 describe_sh_flags(section
['sh_flags']),
357 section
['sh_link'], section
['sh_info'],
358 section
['sh_addralign']))
360 self
._emitline
('Key to Flags:')
361 self
._emitline
(' W (write), A (alloc), X (execute), M (merge),'
362 ' S (strings), I (info),')
363 self
._emitline
(' L (link order), O (extra OS processing required),'
364 ' G (group), T (TLS),')
365 self
._emitline
(' C (compressed), x (unknown), o (OS specific),'
368 if self
.elffile
['e_machine'] == 'EM_ARM':
369 self
._emit
('y (purecode), ')
370 self
._emitline
('p (processor specific)')
372 def display_symbol_tables(self
):
373 """ Display the symbol tables contained in the file
375 self
._init
_versioninfo
()
377 symbol_tables
= [(idx
, s
) for idx
, s
in enumerate(self
.elffile
.iter_sections())
378 if isinstance(s
, SymbolTableSection
)]
380 if not symbol_tables
and self
.elffile
.num_sections() == 0:
382 self
._emitline
('Dynamic symbol information is not available for'
383 ' displaying symbols.')
385 for section_index
, section
in symbol_tables
:
386 if not isinstance(section
, SymbolTableSection
):
389 if section
['sh_entsize'] == 0:
390 self
._emitline
("\nSymbol table '%s' has a sh_entsize of zero!" % (
394 self
._emitline
("\nSymbol table '%s' contains %s entries:" % (
395 section
.name
, section
.num_symbols()))
397 if self
.elffile
.elfclass
== 32:
398 self
._emitline
(' Num: Value Size Type Bind Vis Ndx Name')
400 self
._emitline
(' Num: Value Size Type Bind Vis Ndx Name')
402 for nsym
, symbol
in enumerate(section
.iter_symbols()):
404 # readelf doesn't display version info for Solaris versioning
405 if (section
['sh_type'] == 'SHT_DYNSYM' and
406 self
._versioninfo
['type'] == 'GNU'):
407 version
= self
._symbol
_version
(nsym
)
408 if (version
['name'] != symbol
.name
and
409 version
['index'] not in ('VER_NDX_LOCAL',
411 if version
['filename']:
413 version_info
= '@%(name)s (%(index)i)' % version
416 if version
['hidden']:
417 version_info
= '@%(name)s' % version
419 version_info
= '@@%(name)s' % version
421 # symbol names are truncated to 25 chars, similarly to readelf
422 self
._emitline
('%6d: %s %s %-7s %-6s %-7s %4s %.25s%s' % (
425 symbol
['st_value'], fullhex
=True, lead0x
=False),
426 "%5d" % symbol
['st_size'] if symbol
['st_size'] < 100000 else hex(symbol
['st_size']),
427 describe_symbol_type(symbol
['st_info']['type']),
428 describe_symbol_bind(symbol
['st_info']['bind']),
429 describe_symbol_other(symbol
['st_other']),
430 describe_symbol_shndx(self
._get
_symbol
_shndx
(symbol
,
436 def display_dynamic_tags(self
):
437 """ Display the dynamic tags contained in the file
439 has_dynamic_sections
= False
440 for section
in self
.elffile
.iter_sections():
441 if not isinstance(section
, DynamicSection
):
444 has_dynamic_sections
= True
445 self
._emitline
("\nDynamic section at offset %s contains %s entries:" % (
446 self
._format
_hex
(section
['sh_offset']),
448 self
._emitline
(" Tag Type Name/Value")
450 padding
= 20 + (8 if self
.elffile
.elfclass
== 32 else 0)
451 for tag
in section
.iter_tags():
452 if tag
.entry
.d_tag
== 'DT_NEEDED':
453 parsed
= 'Shared library: [%s]' % tag
.needed
454 elif tag
.entry
.d_tag
== 'DT_RPATH':
455 parsed
= 'Library rpath: [%s]' % tag
.rpath
456 elif tag
.entry
.d_tag
== 'DT_RUNPATH':
457 parsed
= 'Library runpath: [%s]' % tag
.runpath
458 elif tag
.entry
.d_tag
== 'DT_SONAME':
459 parsed
= 'Library soname: [%s]' % tag
.soname
460 elif tag
.entry
.d_tag
.endswith(('SZ', 'ENT')):
461 parsed
= '%i (bytes)' % tag
['d_val']
462 elif tag
.entry
.d_tag
== 'DT_FLAGS':
463 parsed
= describe_dt_flags(tag
.entry
.d_val
)
464 elif tag
.entry
.d_tag
== 'DT_FLAGS_1':
465 parsed
= 'Flags: %s' % describe_dt_flags_1(tag
.entry
.d_val
)
466 elif tag
.entry
.d_tag
.endswith(('NUM', 'COUNT')):
467 parsed
= '%i' % tag
['d_val']
468 elif tag
.entry
.d_tag
== 'DT_PLTREL':
469 s
= describe_dyn_tag(tag
.entry
.d_val
)
470 if s
.startswith('DT_'):
473 elif tag
.entry
.d_tag
== 'DT_MIPS_FLAGS':
474 parsed
= describe_rh_flags(tag
.entry
.d_val
)
475 elif tag
.entry
.d_tag
in ('DT_MIPS_SYMTABNO',
476 'DT_MIPS_LOCAL_GOTNO'):
477 parsed
= str(tag
.entry
.d_val
)
479 parsed
= '%#x' % tag
['d_val']
481 self
._emitline
(" %s %-*s %s" % (
482 self
._format
_hex
(ENUM_D_TAG
.get(tag
.entry
.d_tag
, tag
.entry
.d_tag
),
483 fullhex
=True, lead0x
=True),
485 '(%s)' % (tag
.entry
.d_tag
[3:],),
487 if not has_dynamic_sections
:
488 self
._emitline
("\nThere is no dynamic section in this file.")
490 def display_notes(self
):
491 """ Display the notes contained in the file
493 for section
in self
.elffile
.iter_sections():
494 if isinstance(section
, NoteSection
):
495 for note
in section
.iter_notes():
496 self
._emitline
("\nDisplaying notes found in: {}".format(
498 self
._emitline
(' Owner Data size Description')
499 self
._emitline
(' %s %s\t%s' % (
500 note
['n_name'].ljust(20),
501 self
._format
_hex
(note
['n_descsz'], fieldsize
=8),
502 describe_note(note
)))
504 def display_relocations(self
):
505 """ Display the relocations contained in the file
507 has_relocation_sections
= False
508 for section
in self
.elffile
.iter_sections():
509 if not isinstance(section
, RelocationSection
):
512 has_relocation_sections
= True
513 self
._emitline
("\nRelocation section '%.128s' at offset %s contains %s entries:" % (
515 self
._format
_hex
(section
['sh_offset']),
516 section
.num_relocations()))
517 if section
.is_RELA():
518 self
._emitline
(" Offset Info Type Sym. Value Sym. Name + Addend")
520 self
._emitline
(" Offset Info Type Sym.Value Sym. Name")
522 # The symbol table section pointed to in sh_link
523 symtable
= self
.elffile
.get_section(section
['sh_link'])
525 for rel
in section
.iter_relocations():
526 hexwidth
= 8 if self
.elffile
.elfclass
== 32 else 12
527 self
._emit
('%s %s %-17.17s' % (
528 self
._format
_hex
(rel
['r_offset'],
529 fieldsize
=hexwidth
, lead0x
=False),
530 self
._format
_hex
(rel
['r_info'],
531 fieldsize
=hexwidth
, lead0x
=False),
533 rel
['r_info_type'], self
.elffile
)))
535 if rel
['r_info_sym'] == 0:
536 if section
.is_RELA():
537 fieldsize
= 8 if self
.elffile
.elfclass
== 32 else 16
538 addend
= self
._format
_hex
(rel
['r_addend'], lead0x
=False)
539 self
._emit
(' %s %s' % (' ' * fieldsize
, addend
))
543 symbol
= symtable
.get_symbol(rel
['r_info_sym'])
544 # Some symbols have zero 'st_name', so instead what's used
545 # is the name of the section they point at. Truncate symbol
546 # names (excluding version info) to 22 chars, similarly to
548 if symbol
['st_name'] == 0:
549 symsecidx
= self
._get
_symbol
_shndx
(symbol
,
552 symsec
= self
.elffile
.get_section(symsecidx
)
553 symbol_name
= symsec
.name
556 symbol_name
= symbol
.name
557 version
= self
._symbol
_version
(rel
['r_info_sym'])
558 version
= (version
['name']
559 if version
and version
['name'] else '')
560 symbol_name
= '%.22s' % symbol_name
562 symbol_name
+= '@' + version
564 self
._emit
(' %s %s' % (
567 fullhex
=True, lead0x
=False),
569 if section
.is_RELA():
570 self
._emit
(' %s %x' % (
571 '+' if rel
['r_addend'] >= 0 else '-',
572 abs(rel
['r_addend'])))
575 # Emit the two additional relocation types for ELF64 MIPS
577 if (self
.elffile
.elfclass
== 64 and
578 self
.elffile
['e_machine'] == 'EM_MIPS'):
580 rtype
= rel
['r_info_type%s' % i
]
581 self
._emit
(' Type%s: %s' % (
583 describe_reloc_type(rtype
, self
.elffile
)))
586 if not has_relocation_sections
:
587 self
._emitline
('\nThere are no relocations in this file.')
589 def display_arm_unwind(self
):
590 if not self
.elffile
.has_ehabi_info():
591 self
._emitline
('There are no .ARM.idx sections in this file.')
593 for ehabi_info
in self
.elffile
.get_ehabi_infos():
594 # Unwind section '.ARM.exidx' at offset 0x203e8 contains 1009 entries:
595 self
._emitline
("\nUnwind section '%s' at offset 0x%x contains %d entries" % (
596 ehabi_info
.section_name(),
597 ehabi_info
.section_offset(),
598 ehabi_info
.num_entry()
601 for i
in range(ehabi_info
.num_entry()):
602 entry
= ehabi_info
.get_entry(i
)
604 self
._emitline
("Entry %d:" % i
)
605 if isinstance(entry
, CorruptEHABIEntry
):
606 self
._emitline
(" [corrupt] %s" % entry
.reason
)
608 self
._emit
(" Function offset 0x%x: " % entry
.function_offset
)
609 if isinstance(entry
, CannotUnwindEHABIEntry
):
610 self
._emitline
("[cantunwind]")
612 elif entry
.eh_table_offset
:
613 self
._emitline
("@0x%x" % entry
.eh_table_offset
)
615 self
._emitline
("Compact (inline)")
616 if isinstance(entry
, GenericEHABIEntry
):
617 self
._emitline
(" Personality: 0x%x" % entry
.personality
)
619 self
._emitline
(" Compact model index: %d" % entry
.personality
)
620 for mnemonic_item
in entry
.mnmemonic_array():
622 self
._emitline
(mnemonic_item
)
624 def display_version_info(self
):
625 """ Display the version info contained in the file
627 self
._init
_versioninfo
()
629 if not self
._versioninfo
['type']:
630 self
._emitline
("\nNo version information found in this file.")
633 for section
in self
.elffile
.iter_sections():
634 if isinstance(section
, GNUVerSymSection
):
635 self
._print
_version
_section
_header
(
636 section
, 'Version symbols', lead0x
=False)
638 num_symbols
= section
.num_symbols()
640 # Symbol version info are printed four by four entries
641 for idx_by_4
in range(0, num_symbols
, 4):
643 self
._emit
(' %03x:' % idx_by_4
)
645 for idx
in range(idx_by_4
, min(idx_by_4
+ 4, num_symbols
)):
647 symbol_version
= self
._symbol
_version
(idx
)
648 if symbol_version
['index'] == 'VER_NDX_LOCAL':
650 version_name
= '(*local*)'
651 elif symbol_version
['index'] == 'VER_NDX_GLOBAL':
653 version_name
= '(*global*)'
655 version_index
= symbol_version
['index']
656 version_name
= '(%(name)s)' % symbol_version
658 visibility
= 'h' if symbol_version
['hidden'] else ' '
660 self
._emit
('%4x%s%-13s' % (
661 version_index
, visibility
, version_name
))
665 elif isinstance(section
, GNUVerDefSection
):
666 self
._print
_version
_section
_header
(
667 section
, 'Version definition', indent
=2)
670 for verdef
, verdaux_iter
in section
.iter_versions():
671 verdaux
= next(verdaux_iter
)
674 if verdef
['vd_flags']:
675 flags
= describe_ver_flags(verdef
['vd_flags'])
676 # Mimic exactly the readelf output
681 self
._emitline
(' %s: Rev: %i Flags: %s Index: %i'
682 ' Cnt: %i Name: %s' % (
683 self
._format
_hex
(offset
, fieldsize
=6,
685 verdef
['vd_version'], flags
, verdef
['vd_ndx'],
686 verdef
['vd_cnt'], name
))
689 offset
+ verdef
['vd_aux'] + verdaux
['vda_next'])
690 for idx
, verdaux
in enumerate(verdaux_iter
, start
=1):
691 self
._emitline
(' %s: Parent %i: %s' %
692 (self
._format
_hex
(verdaux_offset
, fieldsize
=4),
694 verdaux_offset
+= verdaux
['vda_next']
696 offset
+= verdef
['vd_next']
698 elif isinstance(section
, GNUVerNeedSection
):
699 self
._print
_version
_section
_header
(section
, 'Version needs')
702 for verneed
, verneed_iter
in section
.iter_versions():
704 self
._emitline
(' %s: Version: %i File: %s Cnt: %i' % (
705 self
._format
_hex
(offset
, fieldsize
=6,
707 verneed
['vn_version'], verneed
.name
,
710 vernaux_offset
= offset
+ verneed
['vn_aux']
711 for idx
, vernaux
in enumerate(verneed_iter
, start
=1):
712 if vernaux
['vna_flags']:
713 flags
= describe_ver_flags(vernaux
['vna_flags'])
714 # Mimic exactly the readelf output
720 ' %s: Name: %s Flags: %s Version: %i' % (
721 self
._format
_hex
(vernaux_offset
, fieldsize
=4),
723 vernaux
['vna_other']))
725 vernaux_offset
+= vernaux
['vna_next']
727 offset
+= verneed
['vn_next']
729 def display_arch_specific(self
):
730 """ Display the architecture-specific info contained in the file.
732 if self
.elffile
['e_machine'] == 'EM_ARM':
733 self
._display
_arch
_specific
_arm
()
735 def display_hex_dump(self
, section_spec
):
736 """ Display a hex dump of a section. section_spec is either a section
739 section
= self
._section
_from
_spec
(section_spec
)
741 # readelf prints the warning to stderr. Even though stderrs are not compared
742 # in tests, we comply with that behavior.
743 sys
.stderr
.write('readelf: Warning: Section \'%s\' was not dumped because it does not exist!\n' % (
746 if section
['sh_type'] == 'SHT_NOBITS':
747 self
._emitline
("\nSection '%s' has no data to dump." % (
751 self
._emitline
("\nHex dump of section '%s':" % section
.name
)
752 self
._note
_relocs
_for
_section
(section
)
753 addr
= section
['sh_addr']
754 data
= section
.data()
757 while dataptr
< len(data
):
758 bytesleft
= len(data
) - dataptr
759 # chunks of 16 bytes per line
760 linebytes
= 16 if bytesleft
> 16 else bytesleft
762 self
._emit
(' %s ' % self
._format
_hex
(addr
, fieldsize
=8))
765 self
._emit
('%2.2x' % byte2int(data
[dataptr
+ i
]))
771 for i
in range(linebytes
):
772 c
= data
[dataptr
+ i
: dataptr
+ i
+ 1]
773 if byte2int(c
[0]) >= 32 and byte2int(c
[0]) < 0x7f:
774 self
._emit
(bytes2str(c
))
776 self
._emit
(bytes2str(b
'.'))
784 def display_string_dump(self
, section_spec
):
785 """ Display a strings dump of a section. section_spec is either a
786 section number or a name.
788 section
= self
._section
_from
_spec
(section_spec
)
790 # readelf prints the warning to stderr. Even though stderrs are not compared
791 # in tests, we comply with that behavior.
792 sys
.stderr
.write('readelf.py: Warning: Section \'%s\' was not dumped because it does not exist!\n' % (
795 if section
['sh_type'] == 'SHT_NOBITS':
796 self
._emitline
("\nSection '%s' has no data to dump." % (
800 self
._emitline
("\nString dump of section '%s':" % section
.name
)
803 data
= section
.data()
806 while dataptr
< len(data
):
807 while ( dataptr
< len(data
) and
808 not (32 <= byte2int(data
[dataptr
]) <= 127)):
811 if dataptr
>= len(data
):
815 while endptr
< len(data
) and byte2int(data
[endptr
]) != 0:
819 self
._emitline
(' [%6x] %s' % (
820 dataptr
, bytes2str(data
[dataptr
:endptr
])))
825 self
._emitline
(' No strings found in this section.')
829 def display_debug_dump(self
, dump_what
):
830 """ Dump a DWARF section
832 self
._init
_dwarfinfo
()
833 if self
._dwarfinfo
is None:
836 set_global_machine_arch(self
.elffile
.get_machine_arch())
838 if dump_what
== 'info':
839 self
._dump
_debug
_info
()
840 elif dump_what
== 'decodedline':
841 self
._dump
_debug
_line
_programs
()
842 elif dump_what
== 'frames':
843 self
._dump
_debug
_frames
()
844 elif dump_what
== 'frames-interp':
845 self
._dump
_debug
_frames
_interp
()
846 elif dump_what
== 'aranges':
847 self
._dump
_debug
_aranges
()
848 elif dump_what
in { 'pubtypes', 'pubnames' }:
849 self
._dump
_debug
_namelut
(dump_what
)
850 elif dump_what
== 'loc':
851 self
._dump
_debug
_locations
()
853 self
._emitline
('debug dump not yet supported for "%s"' % dump_what
)
855 def _format_hex(self
, addr
, fieldsize
=None, fullhex
=False, lead0x
=True,
857 """ Format an address into a hexadecimal string.
860 Size of the hexadecimal field (with leading zeros to fit the
861 address into. For example with fieldsize=8, the format will
863 If None, the minimal required field size will be used.
866 If True, override fieldsize to set it to the maximal size
867 needed for the elfclass
870 If True, leading 0x is added
873 If True, override lead0x to emulate the alternate
874 hexadecimal form specified in format string with the #
875 character: only non-zero values are prefixed with 0x.
876 This form is used by readelf.
885 s
= '0x' if lead0x
else ''
887 fieldsize
= 8 if self
.elffile
.elfclass
== 32 else 16
888 if fieldsize
is None:
891 field
= '%' + '0%sx' % fieldsize
892 return s
+ field
% addr
894 def _print_version_section_header(self
, version_section
, name
, lead0x
=True,
896 """ Print a section header of one version related section (versym,
897 verneed or verdef) with some options to accomodate readelf
898 little differences between each header (e.g. indentation
901 if hasattr(version_section
, 'num_versions'):
902 num_entries
= version_section
.num_versions()
904 num_entries
= version_section
.num_symbols()
906 self
._emitline
("\n%s section '%s' contains %s entries:" %
907 (name
, version_section
.name
, num_entries
))
908 self
._emitline
('%sAddr: %s Offset: %s Link: %i (%s)' % (
911 version_section
['sh_addr'], fieldsize
=16, lead0x
=lead0x
),
913 version_section
['sh_offset'], fieldsize
=6, lead0x
=True),
914 version_section
['sh_link'],
915 self
.elffile
.get_section(version_section
['sh_link']).name
919 def _init_versioninfo(self
):
920 """ Search and initialize informations about version related sections
921 and the kind of versioning used (GNU or Solaris).
923 if self
._versioninfo
is not None:
926 self
._versioninfo
= {'versym': None, 'verdef': None,
927 'verneed': None, 'type': None}
929 for section
in self
.elffile
.iter_sections():
930 if isinstance(section
, GNUVerSymSection
):
931 self
._versioninfo
['versym'] = section
932 elif isinstance(section
, GNUVerDefSection
):
933 self
._versioninfo
['verdef'] = section
934 elif isinstance(section
, GNUVerNeedSection
):
935 self
._versioninfo
['verneed'] = section
936 elif isinstance(section
, DynamicSection
):
937 for tag
in section
.iter_tags():
938 if tag
['d_tag'] == 'DT_VERSYM':
939 self
._versioninfo
['type'] = 'GNU'
942 if not self
._versioninfo
['type'] and (
943 self
._versioninfo
['verneed'] or self
._versioninfo
['verdef']):
944 self
._versioninfo
['type'] = 'Solaris'
946 def _symbol_version(self
, nsym
):
947 """ Return a dict containing information on the
948 or None if no version information is available
950 self
._init
_versioninfo
()
952 symbol_version
= dict.fromkeys(('index', 'name', 'filename', 'hidden'))
954 if (not self
._versioninfo
['versym'] or
955 nsym
>= self
._versioninfo
['versym'].num_symbols()):
958 symbol
= self
._versioninfo
['versym'].get_symbol(nsym
)
959 index
= symbol
.entry
['ndx']
960 if not index
in ('VER_NDX_LOCAL', 'VER_NDX_GLOBAL'):
963 if self
._versioninfo
['type'] == 'GNU':
964 # In GNU versioning mode, the highest bit is used to
965 # store whether the symbol is hidden or not
968 symbol_version
['hidden'] = True
970 if (self
._versioninfo
['verdef'] and
971 index
<= self
._versioninfo
['verdef'].num_versions()):
973 self
._versioninfo
['verdef'].get_version(index
)
974 symbol_version
['name'] = next(verdaux_iter
).name
977 self
._versioninfo
['verneed'].get_version(index
)
978 symbol_version
['name'] = vernaux
.name
979 symbol_version
['filename'] = verneed
.name
981 symbol_version
['index'] = index
982 return symbol_version
984 def _section_from_spec(self
, spec
):
985 """ Retrieve a section given a "spec" (either number or name).
986 Return None if no such section exists in the file.
990 if num
< self
.elffile
.num_sections():
991 return self
.elffile
.get_section(num
)
995 # Not a number. Must be a name then
996 return self
.elffile
.get_section_by_name(spec
)
998 def _get_symbol_shndx(self
, symbol
, symbol_index
, symtab_index
):
999 """ Get the index into the section header table for the "symbol"
1000 at "symbol_index" located in the symbol table with section index
1003 symbol_shndx
= symbol
['st_shndx']
1004 if symbol_shndx
!= SHN_INDICES
.SHN_XINDEX
:
1007 # Check for or lazily construct index section mapping (symbol table
1008 # index -> corresponding symbol table index section object)
1009 if self
._shndx
_sections
is None:
1010 self
._shndx
_sections
= {sec
.symboltable
: sec
for sec
in self
.elffile
.iter_sections()
1011 if isinstance(sec
, SymbolTableIndexSection
)}
1012 return self
._shndx
_sections
[symtab_index
].get_section_index(symbol_index
)
1014 def _note_relocs_for_section(self
, section
):
1015 """ If there are relocation sections pointing to the givne section,
1016 emit a note about it.
1018 for relsec
in self
.elffile
.iter_sections():
1019 if isinstance(relsec
, RelocationSection
):
1020 info_idx
= relsec
['sh_info']
1021 if self
.elffile
.get_section(info_idx
) == section
:
1022 self
._emitline
(' Note: This section has relocations against it, but these have NOT been applied to this dump.')
1025 def _init_dwarfinfo(self
):
1026 """ Initialize the DWARF info contained in the file and assign it to
1028 Leave self._dwarfinfo at None if no DWARF info was found in the file
1030 if self
._dwarfinfo
is not None:
1033 if self
.elffile
.has_dwarf_info():
1034 self
._dwarfinfo
= self
.elffile
.get_dwarf_info()
1036 self
._dwarfinfo
= None
1038 def _dump_debug_info(self
):
1039 """ Dump the debugging info section.
1041 if not self
._dwarfinfo
.has_debug_info
:
1043 self
._emitline
('Contents of the %s section:\n' % self
._dwarfinfo
.debug_info_sec
.name
)
1045 # Offset of the .debug_info section in the stream
1046 section_offset
= self
._dwarfinfo
.debug_info_sec
.global_offset
1048 for cu
in self
._dwarfinfo
.iter_CUs():
1049 self
._emitline
(' Compilation Unit @ offset %s:' %
1050 self
._format
_hex
(cu
.cu_offset
))
1051 self
._emitline
(' Length: %s (%s)' % (
1052 self
._format
_hex
(cu
['unit_length']),
1053 '%s-bit' % cu
.dwarf_format()))
1054 self
._emitline
(' Version: %s' % cu
['version']),
1055 self
._emitline
(' Abbrev Offset: %s' % (
1056 self
._format
_hex
(cu
['debug_abbrev_offset']))),
1057 self
._emitline
(' Pointer Size: %s' % cu
['address_size'])
1059 # The nesting depth of each DIE within the tree of DIEs must be
1060 # displayed. To implement this, a counter is incremented each time
1061 # the current DIE has children, and decremented when a null die is
1062 # encountered. Due to the way the DIE tree is serialized, this will
1063 # correctly reflect the nesting depth
1066 current_function
= None
1067 for die
in cu
.iter_DIEs():
1068 if die
.tag
== 'DW_TAG_subprogram':
1069 current_function
= die
1070 self
._emitline
(' <%s><%x>: Abbrev Number: %s%s' % (
1074 (' (%s)' % die
.tag
) if not die
.is_null() else ''))
1079 for attr
in itervalues(die
.attributes
):
1081 # Unknown attribute values are passed-through as integers
1082 if isinstance(name
, int):
1083 name
= 'Unknown AT value: %x' % name
1085 attr_desc
= describe_attr_value(attr
, die
, section_offset
)
1087 if 'DW_OP_fbreg' in attr_desc
and current_function
and not 'DW_AT_frame_base' in current_function
.attributes
:
1088 postfix
= ' [without dw_at_frame_base]'
1092 self
._emitline
(' <%x> %-18s: %s%s' % (
1098 if die
.has_children
:
1103 def _dump_debug_line_programs(self
):
1104 """ Dump the (decoded) line programs from .debug_line
1105 The programs are dumped in the order of the CUs they belong to.
1107 if not self
._dwarfinfo
.has_debug_info
:
1109 self
._emitline
('Decoded dump of debug contents of section %s:\n' % self
._dwarfinfo
.debug_line_sec
.name
)
1111 for cu
in self
._dwarfinfo
.iter_CUs():
1112 lineprogram
= self
._dwarfinfo
.line_program_for_CU(cu
)
1114 cu_filename
= bytes2str(lineprogram
['file_entry'][0].name
)
1115 if len(lineprogram
['include_directory']) > 0:
1116 dir_index
= lineprogram
['file_entry'][0].dir_index
1118 dir = lineprogram
['include_directory'][dir_index
- 1]
1121 cu_filename
= '%s/%s' % (bytes2str(dir), cu_filename
)
1123 self
._emitline
('CU: %s:' % cu_filename
)
1124 self
._emitline
('File name Line number Starting address')
1126 # Print each state's file, line and address information. For some
1127 # instructions other output is needed to be compatible with
1129 for entry
in lineprogram
.get_entries():
1132 # Special handling for commands that don't set a new state
1133 if entry
.command
== DW_LNS_set_file
:
1134 file_entry
= lineprogram
['file_entry'][entry
.args
[0] - 1]
1135 if file_entry
.dir_index
== 0:
1137 self
._emitline
('\n./%s:[++]' % (
1138 bytes2str(file_entry
.name
)))
1140 self
._emitline
('\n%s/%s:' % (
1141 bytes2str(lineprogram
['include_directory'][file_entry
.dir_index
- 1]),
1142 bytes2str(file_entry
.name
)))
1143 elif entry
.command
== DW_LNE_define_file
:
1144 self
._emitline
('%s:' % (
1145 bytes2str(lineprogram
['include_directory'][entry
.args
[0].dir_index
])))
1146 elif not state
.end_sequence
:
1147 # readelf doesn't print the state after end_sequence
1148 # instructions. I think it's a bug but to be compatible
1149 # I don't print them too.
1150 if lineprogram
['version'] < 4 or self
.elffile
['e_machine'] == 'EM_PPC64':
1151 self
._emitline
('%-35s %11d %18s' % (
1152 bytes2str(lineprogram
['file_entry'][state
.file - 1].name
),
1154 '0' if state
.address
== 0 else
1155 self
._format
_hex
(state
.address
)))
1157 self
._emitline
('%-35s %11d %18s[%d]' % (
1158 bytes2str(lineprogram
['file_entry'][state
.file - 1].name
),
1160 '0' if state
.address
== 0 else
1161 self
._format
_hex
(state
.address
),
1163 if entry
.command
== DW_LNS_copy
:
1164 # Another readelf oddity...
1167 def _dump_frames_info(self
, section
, cfi_entries
):
1168 """ Dump the raw call frame info in a section.
1170 `section` is the Section instance that contains the call frame info
1171 while `cfi_entries` must be an iterable that yields the sequence of
1172 CIE or FDE instances.
1174 self
._emitline
('Contents of the %s section:' % section
.name
)
1176 for entry
in cfi_entries
:
1177 if isinstance(entry
, CIE
):
1178 self
._emitline
('\n%08x %s %s CIE' % (
1180 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1181 self
._format
_hex
(entry
['CIE_id'], fieldsize
=8, lead0x
=False)))
1182 self
._emitline
(' Version: %d' % entry
['version'])
1183 self
._emitline
(' Augmentation: "%s"' % bytes2str(entry
['augmentation']))
1184 self
._emitline
(' Code alignment factor: %u' % entry
['code_alignment_factor'])
1185 self
._emitline
(' Data alignment factor: %d' % entry
['data_alignment_factor'])
1186 self
._emitline
(' Return address column: %d' % entry
['return_address_register'])
1187 if entry
.augmentation_bytes
:
1188 self
._emitline
(' Augmentation data: {}'.format(' '.join(
1189 '{:02x}'.format(ord(b
))
1190 for b
in iterbytes(entry
.augmentation_bytes
)
1194 elif isinstance(entry
, FDE
):
1195 self
._emitline
('\n%08x %s %s FDE cie=%08x pc=%s..%s' % (
1197 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1198 self
._format
_hex
(entry
['CIE_pointer'], fieldsize
=8, lead0x
=False),
1200 self
._format
_hex
(entry
['initial_location'], fullhex
=True, lead0x
=False),
1202 entry
['initial_location'] + entry
['address_range'],
1203 fullhex
=True, lead0x
=False)))
1204 if entry
.augmentation_bytes
:
1205 self
._emitline
(' Augmentation data: {}'.format(' '.join(
1206 '{:02x}'.format(ord(b
))
1207 for b
in iterbytes(entry
.augmentation_bytes
)
1210 else: # ZERO terminator
1211 assert isinstance(entry
, ZERO
)
1212 self
._emitline
('\n%08x ZERO terminator' % entry
.offset
)
1215 self
._emit
(describe_CFI_instructions(entry
))
1218 def _dump_debug_frames(self
):
1219 """ Dump the raw frame info from .debug_frame and .eh_frame sections.
1221 if self
._dwarfinfo
.has_EH_CFI():
1222 self
._dump
_frames
_info
(
1223 self
._dwarfinfo
.eh_frame_sec
,
1224 self
._dwarfinfo
.EH_CFI_entries())
1227 if self
._dwarfinfo
.has_CFI():
1228 self
._dump
_frames
_info
(
1229 self
._dwarfinfo
.debug_frame_sec
,
1230 self
._dwarfinfo
.CFI_entries())
1232 def _dump_debug_namelut(self
, what
):
1234 Dump the debug pubnames section.
1236 if what
== 'pubnames':
1237 namelut
= self
._dwarfinfo
.get_pubnames()
1238 section
= self
._dwarfinfo
.debug_pubnames_sec
1240 namelut
= self
._dwarfinfo
.get_pubtypes()
1241 section
= self
._dwarfinfo
.debug_pubtypes_sec
1243 # readelf prints nothing if the section is not present.
1244 if namelut
is None or len(namelut
) == 0:
1247 self
._emitline
('Contents of the %s section:' % section
.name
)
1250 cu_headers
= namelut
.get_cu_headers()
1252 # go over CU-by-CU first and item-by-item next.
1253 for (cu_hdr
, (cu_ofs
, items
)) in izip(cu_headers
, itertools
.groupby(
1254 namelut
.items(), key
= lambda x
: x
[1].cu_ofs
)):
1256 self
._emitline
(' Length: %d' % cu_hdr
.unit_length
)
1257 self
._emitline
(' Version: %d' % cu_hdr
.version
)
1258 self
._emitline
(' Offset into .debug_info section: 0x%x' % cu_hdr
.debug_info_offset
)
1259 self
._emitline
(' Size of area in .debug_info section: %d' % cu_hdr
.debug_info_length
)
1261 self
._emitline
(' Offset Name')
1263 self
._emitline
(' %x %s' % (item
[1].die_ofs
- cu_ofs
, item
[0]))
1266 def _dump_debug_aranges(self
):
1267 """ Dump the aranges table
1269 aranges_table
= self
._dwarfinfo
.get_aranges()
1270 if aranges_table
== None:
1272 # seems redundent, but we need to get the unsorted set of entries to match system readelf
1273 unordered_entries
= aranges_table
._get
_entries
()
1275 if len(unordered_entries
) == 0:
1277 self
._emitline
("Section '.debug_aranges' has no debugging data.")
1280 self
._emitline
('Contents of the %s section:' % self
._dwarfinfo
.debug_aranges_sec
.name
)
1283 for entry
in unordered_entries
:
1284 if prev_offset
!= entry
.info_offset
:
1285 if entry
!= unordered_entries
[0]:
1286 self
._emitline
(' %s %s' % (
1287 self
._format
_hex
(0, fullhex
=True, lead0x
=False),
1288 self
._format
_hex
(0, fullhex
=True, lead0x
=False)))
1289 self
._emitline
(' Length: %d' % (entry
.unit_length
))
1290 self
._emitline
(' Version: %d' % (entry
.version
))
1291 self
._emitline
(' Offset into .debug_info: 0x%x' % (entry
.info_offset
))
1292 self
._emitline
(' Pointer Size: %d' % (entry
.address_size
))
1293 self
._emitline
(' Segment Size: %d' % (entry
.segment_size
))
1295 self
._emitline
(' Address Length')
1296 self
._emitline
(' %s %s' % (
1297 self
._format
_hex
(entry
.begin_addr
, fullhex
=True, lead0x
=False),
1298 self
._format
_hex
(entry
.length
, fullhex
=True, lead0x
=False)))
1299 prev_offset
= entry
.info_offset
1300 self
._emitline
(' %s %s' % (
1301 self
._format
_hex
(0, fullhex
=True, lead0x
=False),
1302 self
._format
_hex
(0, fullhex
=True, lead0x
=False)))
1304 def _dump_frames_interp_info(self
, section
, cfi_entries
):
1305 """ Dump interpreted (decoded) frame information in a section.
1307 `section` is the Section instance that contains the call frame info
1308 while `cfi_entries` must be an iterable that yields the sequence of
1309 CIE or FDE instances.
1311 self
._emitline
('Contents of the %s section:' % section
.name
)
1313 for entry
in cfi_entries
:
1314 if isinstance(entry
, CIE
):
1315 self
._emitline
('\n%08x %s %s CIE "%s" cf=%d df=%d ra=%d' % (
1317 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1318 self
._format
_hex
(entry
['CIE_id'], fieldsize
=8, lead0x
=False),
1319 bytes2str(entry
['augmentation']),
1320 entry
['code_alignment_factor'],
1321 entry
['data_alignment_factor'],
1322 entry
['return_address_register']))
1323 ra_regnum
= entry
['return_address_register']
1325 elif isinstance(entry
, FDE
):
1326 self
._emitline
('\n%08x %s %s FDE cie=%08x pc=%s..%s' % (
1328 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1329 self
._format
_hex
(entry
['CIE_pointer'], fieldsize
=8, lead0x
=False),
1331 self
._format
_hex
(entry
['initial_location'], fullhex
=True, lead0x
=False),
1332 self
._format
_hex
(entry
['initial_location'] + entry
['address_range'],
1333 fullhex
=True, lead0x
=False)))
1334 ra_regnum
= entry
.cie
['return_address_register']
1336 # If the FDE brings adds no unwinding information compared to
1337 # its CIE, omit its table.
1338 if (len(entry
.get_decoded().table
) ==
1339 len(entry
.cie
.get_decoded().table
)):
1342 else: # ZERO terminator
1343 assert isinstance(entry
, ZERO
)
1344 self
._emitline
('\n%08x ZERO terminator' % entry
.offset
)
1348 decoded_table
= entry
.get_decoded()
1349 if len(decoded_table
.table
) == 0:
1352 # Print the heading row for the decoded table
1354 self
._emit
(' ' if entry
.structs
.address_size
== 4 else ' ')
1357 # Look at the registers the decoded table describes.
1358 # We build reg_order here to match readelf's order. In particular,
1359 # registers are sorted by their number, and the register matching
1360 # ra_regnum is always listed last with a special heading.
1361 decoded_table
= entry
.get_decoded()
1362 reg_order
= sorted(ifilter(
1363 lambda r
: r
!= ra_regnum
,
1364 decoded_table
.reg_order
))
1365 if len(decoded_table
.reg_order
):
1367 # Headings for the registers
1368 for regnum
in reg_order
:
1369 self
._emit
('%-6s' % describe_reg_name(regnum
))
1370 self
._emitline
('ra ')
1372 # Now include ra_regnum in reg_order to print its values
1373 # similarly to the other registers.
1374 reg_order
.append(ra_regnum
)
1378 for line
in decoded_table
.table
:
1379 self
._emit
(self
._format
_hex
(
1380 line
['pc'], fullhex
=True, lead0x
=False))
1382 if line
['cfa'] is not None:
1383 s
= describe_CFI_CFA_rule(line
['cfa'])
1386 self
._emit
(' %-9s' % s
)
1388 for regnum
in reg_order
:
1390 s
= describe_CFI_register_rule(line
[regnum
])
1393 self
._emit
('%-6s' % s
)
1397 def _dump_debug_frames_interp(self
):
1398 """ Dump the interpreted (decoded) frame information from .debug_frame
1399 and .eh_framae sections.
1401 if self
._dwarfinfo
.has_EH_CFI():
1402 self
._dump
_frames
_interp
_info
(
1403 self
._dwarfinfo
.eh_frame_sec
,
1404 self
._dwarfinfo
.EH_CFI_entries())
1407 if self
._dwarfinfo
.has_CFI():
1408 self
._dump
_frames
_interp
_info
(
1409 self
._dwarfinfo
.debug_frame_sec
,
1410 self
._dwarfinfo
.CFI_entries())
1412 def _dump_debug_locations(self
):
1413 """ Dump the location lists from .debug_location section
1415 def _get_cu_base(cu
):
1416 top_die
= cu
.get_top_DIE()
1417 attr
= top_die
.attributes
1418 if 'DW_AT_low_pc' in attr
:
1419 return attr
['DW_AT_low_pc'].value
1420 elif 'DW_AT_entry_pc' in attr
:
1421 return attr
['DW_AT_entry_pc'].value
1423 raise ValueError("Can't find the base IP (low_pc) for a CU")
1425 di
= self
._dwarfinfo
1426 loc_lists
= di
.location_lists()
1427 if not loc_lists
: # No locations section - readelf outputs nothing
1430 loc_lists
= list(loc_lists
.iter_location_lists())
1431 if len(loc_lists
) == 0:
1432 # Present but empty locations section - readelf outputs a message
1433 self
._emitline
("\nSection '%s' has no debugging data." % di
.debug_loc_sec
.name
)
1436 # To dump a location list, one needs to know the CU.
1437 # Scroll through DIEs once, list the known location list offsets
1438 cu_map
= dict() # Loc list offset => CU
1439 for cu
in di
.iter_CUs():
1440 for die
in cu
.iter_DIEs():
1441 for key
in die
.attributes
:
1442 attr
= die
.attributes
[key
]
1443 if (LocationParser
.attribute_has_location(attr
, cu
['version']) and
1444 not LocationParser
._attribute
_has
_loc
_expr
(attr
, cu
['version'])):
1445 cu_map
[attr
.value
] = cu
1447 addr_size
= di
.config
.default_address_size
# In bytes, 4 or 8
1448 addr_width
= addr_size
* 2 # In hex digits, 8 or 16
1449 line_template
= " %%08x %%0%dx %%0%dx %%s%%s" % (addr_width
, addr_width
)
1451 self
._emitline
('Contents of the %s section:\n' % di
.debug_loc_sec
.name
)
1452 self
._emitline
(' Offset Begin End Expression')
1453 for loc_list
in loc_lists
:
1454 cu
= cu_map
.get(loc_list
[0].entry_offset
, False)
1456 raise ValueError("Location list can't be tracked to a CU")
1457 base_ip
= _get_cu_base(cu
)
1458 for entry
in loc_list
:
1459 # TODO: support BaseAddressEntry lines
1460 expr
= describe_DWARF_expr(entry
.loc_expr
, cu
.structs
, cu
.cu_offset
)
1461 postfix
= ' (start == end)' if entry
.begin_offset
== entry
.end_offset
else ''
1462 self
._emitline
(line_template
% (
1464 base_ip
+ entry
.begin_offset
,
1465 base_ip
+ entry
.end_offset
,
1468 # Pyelftools doesn't store the terminating entry,
1469 # but readelf emits its offset, so this should too.
1471 last_len
= 2*addr_size
1472 if isinstance(last
, LocationEntry
):
1473 last_len
+= 2 + len(last
.loc_expr
)
1474 self
._emitline
(" %08x <End of list>" % (last
.entry_offset
+ last_len
))
1476 def _display_arch_specific_arm(self
):
1477 """ Display the ARM architecture-specific info contained in the file.
1479 attr_sec
= self
.elffile
.get_section_by_name('.ARM.attributes')
1481 for s
in attr_sec
.iter_subsections():
1482 self
._emitline
("Attribute Section: %s" % s
.header
['vendor_name'])
1483 for ss
in s
.iter_subsubsections():
1484 h_val
= "" if ss
.header
.extra
is None else " ".join("%d" % x
for x
in ss
.header
.extra
)
1485 self
._emitline
(describe_attr_tag_arm(ss
.header
.tag
, h_val
, None))
1487 for attr
in ss
.iter_attributes():
1489 self
._emitline
(describe_attr_tag_arm(attr
.tag
,
1493 def _emit(self
, s
=''):
1494 """ Emit an object to output
1496 self
.output
.write(str(s
))
1498 def _emitline(self
, s
=''):
1499 """ Emit an object to output, followed by a newline
1501 self
.output
.write(str(s
).rstrip() + '\n')
1504 SCRIPT_DESCRIPTION
= 'Display information about the contents of ELF format files'
1505 VERSION_STRING
= '%%(prog)s: based on pyelftools %s' % __version__
1508 def main(stream
=None):
1509 # parse the command-line arguments and invoke ReadElf
1510 argparser
= argparse
.ArgumentParser(
1511 usage
='usage: %(prog)s [options] <elf-file>',
1512 description
=SCRIPT_DESCRIPTION
,
1513 add_help
=False, # -h is a real option of readelf
1515 argparser
.add_argument('file',
1516 nargs
='?', default
=None,
1517 help='ELF file to parse')
1518 argparser
.add_argument('-v', '--version',
1519 action
='version', version
=VERSION_STRING
)
1520 argparser
.add_argument('-d', '--dynamic',
1521 action
='store_true', dest
='show_dynamic_tags',
1522 help='Display the dynamic section')
1523 argparser
.add_argument('-H', '--help',
1524 action
='store_true', dest
='help',
1525 help='Display this information')
1526 argparser
.add_argument('-h', '--file-header',
1527 action
='store_true', dest
='show_file_header',
1528 help='Display the ELF file header')
1529 argparser
.add_argument('-l', '--program-headers', '--segments',
1530 action
='store_true', dest
='show_program_header',
1531 help='Display the program headers')
1532 argparser
.add_argument('-S', '--section-headers', '--sections',
1533 action
='store_true', dest
='show_section_header',
1534 help="Display the sections' headers")
1535 argparser
.add_argument('-e', '--headers',
1536 action
='store_true', dest
='show_all_headers',
1537 help='Equivalent to: -h -l -S')
1538 argparser
.add_argument('-s', '--symbols', '--syms',
1539 action
='store_true', dest
='show_symbols',
1540 help='Display the symbol table')
1541 argparser
.add_argument('-n', '--notes',
1542 action
='store_true', dest
='show_notes',
1543 help='Display the core notes (if present)')
1544 argparser
.add_argument('-r', '--relocs',
1545 action
='store_true', dest
='show_relocs',
1546 help='Display the relocations (if present)')
1547 argparser
.add_argument('-au', '--arm-unwind',
1548 action
='store_true', dest
='show_arm_unwind',
1549 help='Display the armeabi unwind information (if present)')
1550 argparser
.add_argument('-x', '--hex-dump',
1551 action
='store', dest
='show_hex_dump', metavar
='<number|name>',
1552 help='Dump the contents of section <number|name> as bytes')
1553 argparser
.add_argument('-p', '--string-dump',
1554 action
='store', dest
='show_string_dump', metavar
='<number|name>',
1555 help='Dump the contents of section <number|name> as strings')
1556 argparser
.add_argument('-V', '--version-info',
1557 action
='store_true', dest
='show_version_info',
1558 help='Display the version sections (if present)')
1559 argparser
.add_argument('-A', '--arch-specific',
1560 action
='store_true', dest
='show_arch_specific',
1561 help='Display the architecture-specific information (if present)')
1562 argparser
.add_argument('--debug-dump',
1563 action
='store', dest
='debug_dump_what', metavar
='<what>',
1565 'Display the contents of DWARF debug sections. <what> can ' +
1566 'one of {info,decodedline,frames,frames-interp,aranges,pubtypes,pubnames,loc}'))
1567 argparser
.add_argument('--traceback',
1568 action
='store_true', dest
='show_traceback',
1569 help='Dump the Python traceback on ELFError'
1570 ' exceptions from elftools')
1572 args
= argparser
.parse_args()
1574 if args
.help or not args
.file:
1575 argparser
.print_help()
1578 if args
.show_all_headers
:
1579 do_file_header
= do_section_header
= do_program_header
= True
1581 do_file_header
= args
.show_file_header
1582 do_section_header
= args
.show_section_header
1583 do_program_header
= args
.show_program_header
1585 with
open(args
.file, 'rb') as file:
1587 readelf
= ReadElf(file, stream
or sys
.stdout
)
1589 readelf
.display_file_header()
1590 if do_section_header
:
1591 readelf
.display_section_headers(
1592 show_heading
=not do_file_header
)
1593 if do_program_header
:
1594 readelf
.display_program_headers(
1595 show_heading
=not do_file_header
)
1596 if args
.show_dynamic_tags
:
1597 readelf
.display_dynamic_tags()
1598 if args
.show_symbols
:
1599 readelf
.display_symbol_tables()
1601 readelf
.display_notes()
1602 if args
.show_relocs
:
1603 readelf
.display_relocations()
1604 if args
.show_arm_unwind
:
1605 readelf
.display_arm_unwind()
1606 if args
.show_version_info
:
1607 readelf
.display_version_info()
1608 if args
.show_arch_specific
:
1609 readelf
.display_arch_specific()
1610 if args
.show_hex_dump
:
1611 readelf
.display_hex_dump(args
.show_hex_dump
)
1612 if args
.show_string_dump
:
1613 readelf
.display_string_dump(args
.show_string_dump
)
1614 if args
.debug_dump_what
:
1615 readelf
.display_debug_dump(args
.debug_dump_what
)
1616 except ELFError
as ex
:
1618 sys
.stderr
.write('ELF error: %s\n' % ex
)
1619 if args
.show_traceback
:
1620 traceback
.print_exc()
1625 # Run 'main' redirecting its output to readelfout.txt
1626 # Saves profiling information in readelf.profile
1627 PROFFILE
= 'readelf.profile'
1629 cProfile
.run('main(open("readelfout.txt", "w"))', PROFFILE
)
1631 # Dig in some profiling stats
1633 p
= pstats
.Stats(PROFFILE
)
1634 p
.sort_stats('cumulative').print_stats(25)
1637 #-------------------------------------------------------------------------------
1638 if __name__
== '__main__':