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'], self
.elffile
))
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'], self
.elffile
))
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 %d %s:" % (
396 section
.num_symbols(),
397 'entry' if section
.num_symbols() == 1 else 'entries'))
399 if self
.elffile
.elfclass
== 32:
400 self
._emitline
(' Num: Value Size Type Bind Vis Ndx Name')
402 self
._emitline
(' Num: Value Size Type Bind Vis Ndx Name')
404 for nsym
, symbol
in enumerate(section
.iter_symbols()):
406 # readelf doesn't display version info for Solaris versioning
407 if (section
['sh_type'] == 'SHT_DYNSYM' and
408 self
._versioninfo
['type'] == 'GNU'):
409 version
= self
._symbol
_version
(nsym
)
410 if (version
['name'] != symbol
.name
and
411 version
['index'] not in ('VER_NDX_LOCAL',
413 if version
['filename']:
415 version_info
= '@%(name)s (%(index)i)' % version
418 if version
['hidden']:
419 version_info
= '@%(name)s' % version
421 version_info
= '@@%(name)s' % version
423 symbol_name
= symbol
.name
424 # Print section names for STT_SECTION symbols as readelf does
425 if (symbol
['st_info']['type'] == 'STT_SECTION'
426 and symbol
['st_shndx'] < self
.elffile
.num_sections()
427 and symbol
['st_name'] == 0):
428 symbol_name
= self
.elffile
.get_section(symbol
['st_shndx']).name
430 # symbol names are truncated to 25 chars, similarly to readelf
431 self
._emitline
('%6d: %s %s %-7s %-6s %-7s %4s %.25s%s' % (
434 symbol
['st_value'], fullhex
=True, lead0x
=False),
435 "%5d" % symbol
['st_size'] if symbol
['st_size'] < 100000 else hex(symbol
['st_size']),
436 describe_symbol_type(symbol
['st_info']['type']),
437 describe_symbol_bind(symbol
['st_info']['bind']),
438 describe_symbol_other(symbol
['st_other']),
439 describe_symbol_shndx(self
._get
_symbol
_shndx
(symbol
,
445 def display_dynamic_tags(self
):
446 """ Display the dynamic tags contained in the file
448 has_dynamic_sections
= False
449 for section
in self
.elffile
.iter_sections():
450 if not isinstance(section
, DynamicSection
):
453 has_dynamic_sections
= True
454 self
._emitline
("\nDynamic section at offset %s contains %d %s:" % (
455 self
._format
_hex
(section
['sh_offset']),
457 'entry' if section
.num_tags() == 1 else 'entries'))
458 self
._emitline
(" Tag Type Name/Value")
460 padding
= 20 + (8 if self
.elffile
.elfclass
== 32 else 0)
461 for tag
in section
.iter_tags():
462 if tag
.entry
.d_tag
== 'DT_NEEDED':
463 parsed
= 'Shared library: [%s]' % tag
.needed
464 elif tag
.entry
.d_tag
== 'DT_RPATH':
465 parsed
= 'Library rpath: [%s]' % tag
.rpath
466 elif tag
.entry
.d_tag
== 'DT_RUNPATH':
467 parsed
= 'Library runpath: [%s]' % tag
.runpath
468 elif tag
.entry
.d_tag
== 'DT_SONAME':
469 parsed
= 'Library soname: [%s]' % tag
.soname
470 elif tag
.entry
.d_tag
.endswith(('SZ', 'ENT')):
471 parsed
= '%i (bytes)' % tag
['d_val']
472 elif tag
.entry
.d_tag
== 'DT_FLAGS':
473 parsed
= describe_dt_flags(tag
.entry
.d_val
)
474 elif tag
.entry
.d_tag
== 'DT_FLAGS_1':
475 parsed
= 'Flags: %s' % describe_dt_flags_1(tag
.entry
.d_val
)
476 elif tag
.entry
.d_tag
.endswith(('NUM', 'COUNT')):
477 parsed
= '%i' % tag
['d_val']
478 elif tag
.entry
.d_tag
== 'DT_PLTREL':
479 s
= describe_dyn_tag(tag
.entry
.d_val
)
480 if s
.startswith('DT_'):
483 elif tag
.entry
.d_tag
== 'DT_MIPS_FLAGS':
484 parsed
= describe_rh_flags(tag
.entry
.d_val
)
485 elif tag
.entry
.d_tag
in ('DT_MIPS_SYMTABNO',
486 'DT_MIPS_LOCAL_GOTNO'):
487 parsed
= str(tag
.entry
.d_val
)
489 parsed
= '%#x' % tag
['d_val']
491 self
._emitline
(" %s %-*s %s" % (
492 self
._format
_hex
(ENUM_D_TAG
.get(tag
.entry
.d_tag
, tag
.entry
.d_tag
),
493 fullhex
=True, lead0x
=True),
495 '(%s)' % (tag
.entry
.d_tag
[3:],),
497 if not has_dynamic_sections
:
498 self
._emitline
("\nThere is no dynamic section in this file.")
500 def display_notes(self
):
501 """ Display the notes contained in the file
503 for section
in self
.elffile
.iter_sections():
504 if isinstance(section
, NoteSection
):
505 for note
in section
.iter_notes():
506 self
._emitline
("\nDisplaying notes found in: {}".format(
508 self
._emitline
(' Owner Data size Description')
509 self
._emitline
(' %s %s\t%s' % (
510 note
['n_name'].ljust(20),
511 self
._format
_hex
(note
['n_descsz'], fieldsize
=8),
512 describe_note(note
)))
514 def display_relocations(self
):
515 """ Display the relocations contained in the file
517 has_relocation_sections
= False
518 for section
in self
.elffile
.iter_sections():
519 if not isinstance(section
, RelocationSection
):
522 has_relocation_sections
= True
523 self
._emitline
("\nRelocation section '%.128s' at offset %s contains %d %s:" % (
525 self
._format
_hex
(section
['sh_offset']),
526 section
.num_relocations(),
527 'entry' if section
.num_relocations() == 1 else 'entries'))
528 if section
.is_RELA():
529 self
._emitline
(" Offset Info Type Sym. Value Sym. Name + Addend")
531 self
._emitline
(" Offset Info Type Sym.Value Sym. Name")
533 # The symbol table section pointed to in sh_link
534 symtable
= self
.elffile
.get_section(section
['sh_link'])
536 for rel
in section
.iter_relocations():
537 hexwidth
= 8 if self
.elffile
.elfclass
== 32 else 12
538 self
._emit
('%s %s %-17.17s' % (
539 self
._format
_hex
(rel
['r_offset'],
540 fieldsize
=hexwidth
, lead0x
=False),
541 self
._format
_hex
(rel
['r_info'],
542 fieldsize
=hexwidth
, lead0x
=False),
544 rel
['r_info_type'], self
.elffile
)))
546 if rel
['r_info_sym'] == 0:
547 if section
.is_RELA():
548 fieldsize
= 8 if self
.elffile
.elfclass
== 32 else 16
549 addend
= self
._format
_hex
(rel
['r_addend'], lead0x
=False)
550 self
._emit
(' %s %s' % (' ' * fieldsize
, addend
))
554 symbol
= symtable
.get_symbol(rel
['r_info_sym'])
555 # Some symbols have zero 'st_name', so instead what's used
556 # is the name of the section they point at. Truncate symbol
557 # names (excluding version info) to 22 chars, similarly to
559 if symbol
['st_name'] == 0:
560 symsecidx
= self
._get
_symbol
_shndx
(symbol
,
563 symsec
= self
.elffile
.get_section(symsecidx
)
564 symbol_name
= symsec
.name
567 symbol_name
= symbol
.name
568 version
= self
._symbol
_version
(rel
['r_info_sym'])
569 version
= (version
['name']
570 if version
and version
['name'] else '')
571 symbol_name
= '%.22s' % symbol_name
573 symbol_name
+= '@' + version
575 self
._emit
(' %s %s' % (
578 fullhex
=True, lead0x
=False),
580 if section
.is_RELA():
581 self
._emit
(' %s %x' % (
582 '+' if rel
['r_addend'] >= 0 else '-',
583 abs(rel
['r_addend'])))
586 # Emit the two additional relocation types for ELF64 MIPS
588 if (self
.elffile
.elfclass
== 64 and
589 self
.elffile
['e_machine'] == 'EM_MIPS'):
591 rtype
= rel
['r_info_type%s' % i
]
592 self
._emit
(' Type%s: %s' % (
594 describe_reloc_type(rtype
, self
.elffile
)))
597 if not has_relocation_sections
:
598 self
._emitline
('\nThere are no relocations in this file.')
600 def display_arm_unwind(self
):
601 if not self
.elffile
.has_ehabi_info():
602 self
._emitline
('There are no .ARM.idx sections in this file.')
604 for ehabi_info
in self
.elffile
.get_ehabi_infos():
605 # Unwind section '.ARM.exidx' at offset 0x203e8 contains 1009 entries:
606 self
._emitline
("\nUnwind section '%s' at offset 0x%x contains %d %s" % (
607 ehabi_info
.section_name(),
608 ehabi_info
.section_offset(),
609 ehabi_info
.num_entry(),
610 'entry' if ehabi_info
.num_entry() == 1 else 'entries'))
612 for i
in range(ehabi_info
.num_entry()):
613 entry
= ehabi_info
.get_entry(i
)
615 self
._emitline
("Entry %d:" % i
)
616 if isinstance(entry
, CorruptEHABIEntry
):
617 self
._emitline
(" [corrupt] %s" % entry
.reason
)
619 self
._emit
(" Function offset 0x%x: " % entry
.function_offset
)
620 if isinstance(entry
, CannotUnwindEHABIEntry
):
621 self
._emitline
("[cantunwind]")
623 elif entry
.eh_table_offset
:
624 self
._emitline
("@0x%x" % entry
.eh_table_offset
)
626 self
._emitline
("Compact (inline)")
627 if isinstance(entry
, GenericEHABIEntry
):
628 self
._emitline
(" Personality: 0x%x" % entry
.personality
)
630 self
._emitline
(" Compact model index: %d" % entry
.personality
)
631 for mnemonic_item
in entry
.mnmemonic_array():
633 self
._emitline
(mnemonic_item
)
635 def display_version_info(self
):
636 """ Display the version info contained in the file
638 self
._init
_versioninfo
()
640 if not self
._versioninfo
['type']:
641 self
._emitline
("\nNo version information found in this file.")
644 for section
in self
.elffile
.iter_sections():
645 if isinstance(section
, GNUVerSymSection
):
646 self
._print
_version
_section
_header
(section
, 'Version symbols')
647 num_symbols
= section
.num_symbols()
649 # Symbol version info are printed four by four entries
650 for idx_by_4
in range(0, num_symbols
, 4):
652 self
._emit
(' %03x:' % idx_by_4
)
654 for idx
in range(idx_by_4
, min(idx_by_4
+ 4, num_symbols
)):
656 symbol_version
= self
._symbol
_version
(idx
)
657 if symbol_version
['index'] == 'VER_NDX_LOCAL':
659 version_name
= '(*local*)'
660 elif symbol_version
['index'] == 'VER_NDX_GLOBAL':
662 version_name
= '(*global*)'
664 version_index
= symbol_version
['index']
665 version_name
= '(%(name)s)' % symbol_version
667 visibility
= 'h' if symbol_version
['hidden'] else ' '
669 self
._emit
('%4x%s%-13s' % (
670 version_index
, visibility
, version_name
))
674 elif isinstance(section
, GNUVerDefSection
):
675 self
._print
_version
_section
_header
(
676 section
, 'Version definition', indent
=2)
679 for verdef
, verdaux_iter
in section
.iter_versions():
680 verdaux
= next(verdaux_iter
)
683 if verdef
['vd_flags']:
684 flags
= describe_ver_flags(verdef
['vd_flags'])
685 # Mimic exactly the readelf output
690 self
._emitline
(' %s: Rev: %i Flags: %s Index: %i'
691 ' Cnt: %i Name: %s' % (
692 self
._format
_hex
(offset
, fieldsize
=6,
694 verdef
['vd_version'], flags
, verdef
['vd_ndx'],
695 verdef
['vd_cnt'], name
))
698 offset
+ verdef
['vd_aux'] + verdaux
['vda_next'])
699 for idx
, verdaux
in enumerate(verdaux_iter
, start
=1):
700 self
._emitline
(' %s: Parent %i: %s' %
701 (self
._format
_hex
(verdaux_offset
, fieldsize
=4),
703 verdaux_offset
+= verdaux
['vda_next']
705 offset
+= verdef
['vd_next']
707 elif isinstance(section
, GNUVerNeedSection
):
708 self
._print
_version
_section
_header
(section
, 'Version needs')
711 for verneed
, verneed_iter
in section
.iter_versions():
713 self
._emitline
(' %s: Version: %i File: %s Cnt: %i' % (
714 self
._format
_hex
(offset
, fieldsize
=6,
716 verneed
['vn_version'], verneed
.name
,
719 vernaux_offset
= offset
+ verneed
['vn_aux']
720 for idx
, vernaux
in enumerate(verneed_iter
, start
=1):
721 if vernaux
['vna_flags']:
722 flags
= describe_ver_flags(vernaux
['vna_flags'])
723 # Mimic exactly the readelf output
729 ' %s: Name: %s Flags: %s Version: %i' % (
730 self
._format
_hex
(vernaux_offset
, fieldsize
=4),
732 vernaux
['vna_other']))
734 vernaux_offset
+= vernaux
['vna_next']
736 offset
+= verneed
['vn_next']
738 def display_arch_specific(self
):
739 """ Display the architecture-specific info contained in the file.
741 if self
.elffile
['e_machine'] == 'EM_ARM':
742 self
._display
_arch
_specific
_arm
()
744 def display_hex_dump(self
, section_spec
):
745 """ Display a hex dump of a section. section_spec is either a section
748 section
= self
._section
_from
_spec
(section_spec
)
750 # readelf prints the warning to stderr. Even though stderrs are not compared
751 # in tests, we comply with that behavior.
752 sys
.stderr
.write('readelf: Warning: Section \'%s\' was not dumped because it does not exist!\n' % (
755 if section
['sh_type'] == 'SHT_NOBITS':
756 self
._emitline
("\nSection '%s' has no data to dump." % (
760 self
._emitline
("\nHex dump of section '%s':" % section
.name
)
761 self
._note
_relocs
_for
_section
(section
)
762 addr
= section
['sh_addr']
763 data
= section
.data()
766 while dataptr
< len(data
):
767 bytesleft
= len(data
) - dataptr
768 # chunks of 16 bytes per line
769 linebytes
= 16 if bytesleft
> 16 else bytesleft
771 self
._emit
(' %s ' % self
._format
_hex
(addr
, fieldsize
=8))
774 self
._emit
('%2.2x' % byte2int(data
[dataptr
+ i
]))
780 for i
in range(linebytes
):
781 c
= data
[dataptr
+ i
: dataptr
+ i
+ 1]
782 if byte2int(c
[0]) >= 32 and byte2int(c
[0]) < 0x7f:
783 self
._emit
(bytes2str(c
))
785 self
._emit
(bytes2str(b
'.'))
793 def display_string_dump(self
, section_spec
):
794 """ Display a strings dump of a section. section_spec is either a
795 section number or a name.
797 section
= self
._section
_from
_spec
(section_spec
)
799 # readelf prints the warning to stderr. Even though stderrs are not compared
800 # in tests, we comply with that behavior.
801 sys
.stderr
.write('readelf.py: Warning: Section \'%s\' was not dumped because it does not exist!\n' % (
804 if section
['sh_type'] == 'SHT_NOBITS':
805 self
._emitline
("\nSection '%s' has no data to dump." % (
809 self
._emitline
("\nString dump of section '%s':" % section
.name
)
812 data
= section
.data()
815 while dataptr
< len(data
):
816 while ( dataptr
< len(data
) and
817 not (32 <= byte2int(data
[dataptr
]) <= 127)):
820 if dataptr
>= len(data
):
824 while endptr
< len(data
) and byte2int(data
[endptr
]) != 0:
828 self
._emitline
(' [%6x] %s' % (
829 dataptr
, bytes2str(data
[dataptr
:endptr
])))
834 self
._emitline
(' No strings found in this section.')
838 def display_debug_dump(self
, dump_what
):
839 """ Dump a DWARF section
841 self
._init
_dwarfinfo
()
842 if self
._dwarfinfo
is None:
845 set_global_machine_arch(self
.elffile
.get_machine_arch())
847 if dump_what
== 'info':
848 self
._dump
_debug
_info
()
849 elif dump_what
== 'decodedline':
850 self
._dump
_debug
_line
_programs
()
851 elif dump_what
== 'frames':
852 self
._dump
_debug
_frames
()
853 elif dump_what
== 'frames-interp':
854 self
._dump
_debug
_frames
_interp
()
855 elif dump_what
== 'aranges':
856 self
._dump
_debug
_aranges
()
857 elif dump_what
in { 'pubtypes', 'pubnames' }:
858 self
._dump
_debug
_namelut
(dump_what
)
859 elif dump_what
== 'loc':
860 self
._dump
_debug
_locations
()
862 self
._emitline
('debug dump not yet supported for "%s"' % dump_what
)
864 def _format_hex(self
, addr
, fieldsize
=None, fullhex
=False, lead0x
=True,
866 """ Format an address into a hexadecimal string.
869 Size of the hexadecimal field (with leading zeros to fit the
870 address into. For example with fieldsize=8, the format will
872 If None, the minimal required field size will be used.
875 If True, override fieldsize to set it to the maximal size
876 needed for the elfclass
879 If True, leading 0x is added
882 If True, override lead0x to emulate the alternate
883 hexadecimal form specified in format string with the #
884 character: only non-zero values are prefixed with 0x.
885 This form is used by readelf.
894 s
= '0x' if lead0x
else ''
896 fieldsize
= 8 if self
.elffile
.elfclass
== 32 else 16
897 if fieldsize
is None:
900 field
= '%' + '0%sx' % fieldsize
901 return s
+ field
% addr
903 def _print_version_section_header(self
, version_section
, name
, lead0x
=True,
905 """ Print a section header of one version related section (versym,
906 verneed or verdef) with some options to accomodate readelf
907 little differences between each header (e.g. indentation
910 if hasattr(version_section
, 'num_versions'):
911 num_entries
= version_section
.num_versions()
913 num_entries
= version_section
.num_symbols()
915 self
._emitline
("\n%s section '%s' contains %d %s:" % (
916 name
, version_section
.name
, num_entries
,
917 'entry' if num_entries
== 1 else 'entries'))
918 self
._emitline
('%sAddr: %s Offset: %s Link: %i (%s)' % (
921 version_section
['sh_addr'], fieldsize
=16, lead0x
=lead0x
),
923 version_section
['sh_offset'], fieldsize
=6, lead0x
=True),
924 version_section
['sh_link'],
925 self
.elffile
.get_section(version_section
['sh_link']).name
929 def _init_versioninfo(self
):
930 """ Search and initialize informations about version related sections
931 and the kind of versioning used (GNU or Solaris).
933 if self
._versioninfo
is not None:
936 self
._versioninfo
= {'versym': None, 'verdef': None,
937 'verneed': None, 'type': None}
939 for section
in self
.elffile
.iter_sections():
940 if isinstance(section
, GNUVerSymSection
):
941 self
._versioninfo
['versym'] = section
942 elif isinstance(section
, GNUVerDefSection
):
943 self
._versioninfo
['verdef'] = section
944 elif isinstance(section
, GNUVerNeedSection
):
945 self
._versioninfo
['verneed'] = section
946 elif isinstance(section
, DynamicSection
):
947 for tag
in section
.iter_tags():
948 if tag
['d_tag'] == 'DT_VERSYM':
949 self
._versioninfo
['type'] = 'GNU'
952 if not self
._versioninfo
['type'] and (
953 self
._versioninfo
['verneed'] or self
._versioninfo
['verdef']):
954 self
._versioninfo
['type'] = 'Solaris'
956 def _symbol_version(self
, nsym
):
957 """ Return a dict containing information on the
958 or None if no version information is available
960 self
._init
_versioninfo
()
962 symbol_version
= dict.fromkeys(('index', 'name', 'filename', 'hidden'))
964 if (not self
._versioninfo
['versym'] or
965 nsym
>= self
._versioninfo
['versym'].num_symbols()):
968 symbol
= self
._versioninfo
['versym'].get_symbol(nsym
)
969 index
= symbol
.entry
['ndx']
970 if not index
in ('VER_NDX_LOCAL', 'VER_NDX_GLOBAL'):
973 if self
._versioninfo
['type'] == 'GNU':
974 # In GNU versioning mode, the highest bit is used to
975 # store whether the symbol is hidden or not
978 symbol_version
['hidden'] = True
980 if (self
._versioninfo
['verdef'] and
981 index
<= self
._versioninfo
['verdef'].num_versions()):
983 self
._versioninfo
['verdef'].get_version(index
)
984 symbol_version
['name'] = next(verdaux_iter
).name
987 self
._versioninfo
['verneed'].get_version(index
)
988 symbol_version
['name'] = vernaux
.name
989 symbol_version
['filename'] = verneed
.name
991 symbol_version
['index'] = index
992 return symbol_version
994 def _section_from_spec(self
, spec
):
995 """ Retrieve a section given a "spec" (either number or name).
996 Return None if no such section exists in the file.
1000 if num
< self
.elffile
.num_sections():
1001 return self
.elffile
.get_section(num
)
1005 # Not a number. Must be a name then
1006 return self
.elffile
.get_section_by_name(spec
)
1008 def _get_symbol_shndx(self
, symbol
, symbol_index
, symtab_index
):
1009 """ Get the index into the section header table for the "symbol"
1010 at "symbol_index" located in the symbol table with section index
1013 symbol_shndx
= symbol
['st_shndx']
1014 if symbol_shndx
!= SHN_INDICES
.SHN_XINDEX
:
1017 # Check for or lazily construct index section mapping (symbol table
1018 # index -> corresponding symbol table index section object)
1019 if self
._shndx
_sections
is None:
1020 self
._shndx
_sections
= {sec
.symboltable
: sec
for sec
in self
.elffile
.iter_sections()
1021 if isinstance(sec
, SymbolTableIndexSection
)}
1022 return self
._shndx
_sections
[symtab_index
].get_section_index(symbol_index
)
1024 def _note_relocs_for_section(self
, section
):
1025 """ If there are relocation sections pointing to the givne section,
1026 emit a note about it.
1028 for relsec
in self
.elffile
.iter_sections():
1029 if isinstance(relsec
, RelocationSection
):
1030 info_idx
= relsec
['sh_info']
1031 if self
.elffile
.get_section(info_idx
) == section
:
1032 self
._emitline
(' Note: This section has relocations against it, but these have NOT been applied to this dump.')
1035 def _init_dwarfinfo(self
):
1036 """ Initialize the DWARF info contained in the file and assign it to
1038 Leave self._dwarfinfo at None if no DWARF info was found in the file
1040 if self
._dwarfinfo
is not None:
1043 if self
.elffile
.has_dwarf_info():
1044 self
._dwarfinfo
= self
.elffile
.get_dwarf_info()
1046 self
._dwarfinfo
= None
1048 def _dump_debug_info(self
):
1049 """ Dump the debugging info section.
1051 if not self
._dwarfinfo
.has_debug_info
:
1053 self
._emitline
('Contents of the %s section:\n' % self
._dwarfinfo
.debug_info_sec
.name
)
1055 # Offset of the .debug_info section in the stream
1056 section_offset
= self
._dwarfinfo
.debug_info_sec
.global_offset
1058 for cu
in self
._dwarfinfo
.iter_CUs():
1059 self
._emitline
(' Compilation Unit @ offset %s:' %
1060 self
._format
_hex
(cu
.cu_offset
))
1061 self
._emitline
(' Length: %s (%s)' % (
1062 self
._format
_hex
(cu
['unit_length']),
1063 '%s-bit' % cu
.dwarf_format()))
1064 self
._emitline
(' Version: %s' % cu
['version']),
1065 self
._emitline
(' Abbrev Offset: %s' % (
1066 self
._format
_hex
(cu
['debug_abbrev_offset']))),
1067 self
._emitline
(' Pointer Size: %s' % cu
['address_size'])
1069 # The nesting depth of each DIE within the tree of DIEs must be
1070 # displayed. To implement this, a counter is incremented each time
1071 # the current DIE has children, and decremented when a null die is
1072 # encountered. Due to the way the DIE tree is serialized, this will
1073 # correctly reflect the nesting depth
1076 current_function
= None
1077 for die
in cu
.iter_DIEs():
1078 if die
.tag
== 'DW_TAG_subprogram':
1079 current_function
= die
1080 self
._emitline
(' <%s><%x>: Abbrev Number: %s%s' % (
1084 (' (%s)' % die
.tag
) if not die
.is_null() else ''))
1089 for attr
in itervalues(die
.attributes
):
1091 # Unknown attribute values are passed-through as integers
1092 if isinstance(name
, int):
1093 name
= 'Unknown AT value: %x' % name
1095 attr_desc
= describe_attr_value(attr
, die
, section_offset
)
1097 if 'DW_OP_fbreg' in attr_desc
and current_function
and not 'DW_AT_frame_base' in current_function
.attributes
:
1098 postfix
= ' [without dw_at_frame_base]'
1102 self
._emitline
(' <%x> %-18s: %s%s' % (
1108 if die
.has_children
:
1113 def _dump_debug_line_programs(self
):
1114 """ Dump the (decoded) line programs from .debug_line
1115 The programs are dumped in the order of the CUs they belong to.
1117 if not self
._dwarfinfo
.has_debug_info
:
1119 self
._emitline
('Contents of the %s section:' % self
._dwarfinfo
.debug_line_sec
.name
)
1122 for cu
in self
._dwarfinfo
.iter_CUs():
1123 lineprogram
= self
._dwarfinfo
.line_program_for_CU(cu
)
1125 cu_filename
= bytes2str(lineprogram
['file_entry'][0].name
)
1126 if len(lineprogram
['include_directory']) > 0:
1127 dir_index
= lineprogram
['file_entry'][0].dir_index
1129 dir = lineprogram
['include_directory'][dir_index
- 1]
1132 cu_filename
= '%s/%s' % (bytes2str(dir), cu_filename
)
1134 self
._emitline
('CU: %s:' % cu_filename
)
1135 self
._emitline
('File name Line number Starting address Stmt')
1137 # Print each state's file, line and address information. For some
1138 # instructions other output is needed to be compatible with
1140 for entry
in lineprogram
.get_entries():
1143 # Special handling for commands that don't set a new state
1144 if entry
.command
== DW_LNS_set_file
:
1145 file_entry
= lineprogram
['file_entry'][entry
.args
[0] - 1]
1146 if file_entry
.dir_index
== 0:
1148 self
._emitline
('\n./%s:[++]' % (
1149 bytes2str(file_entry
.name
)))
1151 self
._emitline
('\n%s/%s:' % (
1152 bytes2str(lineprogram
['include_directory'][file_entry
.dir_index
- 1]),
1153 bytes2str(file_entry
.name
)))
1154 elif entry
.command
== DW_LNE_define_file
:
1155 self
._emitline
('%s:' % (
1156 bytes2str(lineprogram
['include_directory'][entry
.args
[0].dir_index
])))
1157 elif lineprogram
['version'] < 4 or self
.elffile
['e_machine'] == 'EM_PPC64':
1158 self
._emitline
('%-35s %11s %18s %s' % (
1159 bytes2str(lineprogram
['file_entry'][state
.file - 1].name
),
1160 state
.line
if not state
.end_sequence
else '-',
1161 '0' if state
.address
== 0 else self
._format
_hex
(state
.address
),
1162 'x' if state
.is_stmt
and not state
.end_sequence
else ''))
1164 self
._emitline
('%-35s %11d %18s[%d] %s' % (
1165 bytes2str(lineprogram
['file_entry'][state
.file - 1].name
),
1166 state
.line
if not state
.end_sequence
else '-',
1167 '0' if state
.address
== 0 else self
._format
_hex
(state
.address
),
1169 'x' if state
.is_stmt
and not state
.end_sequence
else ''))
1170 if entry
.command
== DW_LNS_copy
:
1171 # Another readelf oddity...
1174 def _dump_frames_info(self
, section
, cfi_entries
):
1175 """ Dump the raw call frame info in a section.
1177 `section` is the Section instance that contains the call frame info
1178 while `cfi_entries` must be an iterable that yields the sequence of
1179 CIE or FDE instances.
1181 self
._emitline
('Contents of the %s section:' % section
.name
)
1183 for entry
in cfi_entries
:
1184 if isinstance(entry
, CIE
):
1185 self
._emitline
('\n%08x %s %s CIE' % (
1187 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1188 self
._format
_hex
(entry
['CIE_id'], fieldsize
=8, lead0x
=False)))
1189 self
._emitline
(' Version: %d' % entry
['version'])
1190 self
._emitline
(' Augmentation: "%s"' % bytes2str(entry
['augmentation']))
1191 self
._emitline
(' Code alignment factor: %u' % entry
['code_alignment_factor'])
1192 self
._emitline
(' Data alignment factor: %d' % entry
['data_alignment_factor'])
1193 self
._emitline
(' Return address column: %d' % entry
['return_address_register'])
1194 if entry
.augmentation_bytes
:
1195 self
._emitline
(' Augmentation data: {}'.format(' '.join(
1196 '{:02x}'.format(ord(b
))
1197 for b
in iterbytes(entry
.augmentation_bytes
)
1201 elif isinstance(entry
, FDE
):
1202 self
._emitline
('\n%08x %s %s FDE cie=%08x pc=%s..%s' % (
1204 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1205 self
._format
_hex
(entry
['CIE_pointer'], fieldsize
=8, lead0x
=False),
1207 self
._format
_hex
(entry
['initial_location'], fullhex
=True, lead0x
=False),
1209 entry
['initial_location'] + entry
['address_range'],
1210 fullhex
=True, lead0x
=False)))
1211 if entry
.augmentation_bytes
:
1212 self
._emitline
(' Augmentation data: {}'.format(' '.join(
1213 '{:02x}'.format(ord(b
))
1214 for b
in iterbytes(entry
.augmentation_bytes
)
1217 else: # ZERO terminator
1218 assert isinstance(entry
, ZERO
)
1219 self
._emitline
('\n%08x ZERO terminator' % entry
.offset
)
1222 self
._emit
(describe_CFI_instructions(entry
))
1225 def _dump_debug_frames(self
):
1226 """ Dump the raw frame info from .debug_frame and .eh_frame sections.
1228 if self
._dwarfinfo
.has_EH_CFI():
1229 self
._dump
_frames
_info
(
1230 self
._dwarfinfo
.eh_frame_sec
,
1231 self
._dwarfinfo
.EH_CFI_entries())
1234 if self
._dwarfinfo
.has_CFI():
1235 self
._dump
_frames
_info
(
1236 self
._dwarfinfo
.debug_frame_sec
,
1237 self
._dwarfinfo
.CFI_entries())
1239 def _dump_debug_namelut(self
, what
):
1241 Dump the debug pubnames section.
1243 if what
== 'pubnames':
1244 namelut
= self
._dwarfinfo
.get_pubnames()
1245 section
= self
._dwarfinfo
.debug_pubnames_sec
1247 namelut
= self
._dwarfinfo
.get_pubtypes()
1248 section
= self
._dwarfinfo
.debug_pubtypes_sec
1250 # readelf prints nothing if the section is not present.
1251 if namelut
is None or len(namelut
) == 0:
1254 self
._emitline
('Contents of the %s section:' % section
.name
)
1257 cu_headers
= namelut
.get_cu_headers()
1259 # go over CU-by-CU first and item-by-item next.
1260 for (cu_hdr
, (cu_ofs
, items
)) in izip(cu_headers
, itertools
.groupby(
1261 namelut
.items(), key
= lambda x
: x
[1].cu_ofs
)):
1263 self
._emitline
(' Length: %d' % cu_hdr
.unit_length
)
1264 self
._emitline
(' Version: %d' % cu_hdr
.version
)
1265 self
._emitline
(' Offset into .debug_info section: 0x%x' % cu_hdr
.debug_info_offset
)
1266 self
._emitline
(' Size of area in .debug_info section: %d' % cu_hdr
.debug_info_length
)
1268 self
._emitline
(' Offset Name')
1270 self
._emitline
(' %x %s' % (item
[1].die_ofs
- cu_ofs
, item
[0]))
1273 def _dump_debug_aranges(self
):
1274 """ Dump the aranges table
1276 aranges_table
= self
._dwarfinfo
.get_aranges()
1277 if aranges_table
== None:
1279 # seems redundent, but we need to get the unsorted set of entries to match system readelf
1280 unordered_entries
= aranges_table
._get
_entries
()
1282 if len(unordered_entries
) == 0:
1284 self
._emitline
("Section '.debug_aranges' has no debugging data.")
1287 self
._emitline
('Contents of the %s section:' % self
._dwarfinfo
.debug_aranges_sec
.name
)
1290 for entry
in unordered_entries
:
1291 if prev_offset
!= entry
.info_offset
:
1292 if entry
!= unordered_entries
[0]:
1293 self
._emitline
(' %s %s' % (
1294 self
._format
_hex
(0, fullhex
=True, lead0x
=False),
1295 self
._format
_hex
(0, fullhex
=True, lead0x
=False)))
1296 self
._emitline
(' Length: %d' % (entry
.unit_length
))
1297 self
._emitline
(' Version: %d' % (entry
.version
))
1298 self
._emitline
(' Offset into .debug_info: 0x%x' % (entry
.info_offset
))
1299 self
._emitline
(' Pointer Size: %d' % (entry
.address_size
))
1300 self
._emitline
(' Segment Size: %d' % (entry
.segment_size
))
1302 self
._emitline
(' Address Length')
1303 self
._emitline
(' %s %s' % (
1304 self
._format
_hex
(entry
.begin_addr
, fullhex
=True, lead0x
=False),
1305 self
._format
_hex
(entry
.length
, fullhex
=True, lead0x
=False)))
1306 prev_offset
= entry
.info_offset
1307 self
._emitline
(' %s %s' % (
1308 self
._format
_hex
(0, fullhex
=True, lead0x
=False),
1309 self
._format
_hex
(0, fullhex
=True, lead0x
=False)))
1311 def _dump_frames_interp_info(self
, section
, cfi_entries
):
1312 """ Dump interpreted (decoded) frame information in a section.
1314 `section` is the Section instance that contains the call frame info
1315 while `cfi_entries` must be an iterable that yields the sequence of
1316 CIE or FDE instances.
1318 self
._emitline
('Contents of the %s section:' % section
.name
)
1320 for entry
in cfi_entries
:
1321 if isinstance(entry
, CIE
):
1322 self
._emitline
('\n%08x %s %s CIE "%s" cf=%d df=%d ra=%d' % (
1324 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1325 self
._format
_hex
(entry
['CIE_id'], fieldsize
=8, lead0x
=False),
1326 bytes2str(entry
['augmentation']),
1327 entry
['code_alignment_factor'],
1328 entry
['data_alignment_factor'],
1329 entry
['return_address_register']))
1330 ra_regnum
= entry
['return_address_register']
1332 elif isinstance(entry
, FDE
):
1333 self
._emitline
('\n%08x %s %s FDE cie=%08x pc=%s..%s' % (
1335 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1336 self
._format
_hex
(entry
['CIE_pointer'], fieldsize
=8, lead0x
=False),
1338 self
._format
_hex
(entry
['initial_location'], fullhex
=True, lead0x
=False),
1339 self
._format
_hex
(entry
['initial_location'] + entry
['address_range'],
1340 fullhex
=True, lead0x
=False)))
1341 ra_regnum
= entry
.cie
['return_address_register']
1343 # If the FDE brings adds no unwinding information compared to
1344 # its CIE, omit its table.
1345 if (len(entry
.get_decoded().table
) ==
1346 len(entry
.cie
.get_decoded().table
)):
1349 else: # ZERO terminator
1350 assert isinstance(entry
, ZERO
)
1351 self
._emitline
('\n%08x ZERO terminator' % entry
.offset
)
1355 decoded_table
= entry
.get_decoded()
1356 if len(decoded_table
.table
) == 0:
1359 # Print the heading row for the decoded table
1361 self
._emit
(' ' if entry
.structs
.address_size
== 4 else ' ')
1364 # Look at the registers the decoded table describes.
1365 # We build reg_order here to match readelf's order. In particular,
1366 # registers are sorted by their number, and the register matching
1367 # ra_regnum is always listed last with a special heading.
1368 decoded_table
= entry
.get_decoded()
1369 reg_order
= sorted(ifilter(
1370 lambda r
: r
!= ra_regnum
,
1371 decoded_table
.reg_order
))
1372 if len(decoded_table
.reg_order
):
1374 # Headings for the registers
1375 for regnum
in reg_order
:
1376 self
._emit
('%-6s' % describe_reg_name(regnum
))
1377 self
._emitline
('ra ')
1379 # Now include ra_regnum in reg_order to print its values
1380 # similarly to the other registers.
1381 reg_order
.append(ra_regnum
)
1385 for line
in decoded_table
.table
:
1386 self
._emit
(self
._format
_hex
(
1387 line
['pc'], fullhex
=True, lead0x
=False))
1389 if line
['cfa'] is not None:
1390 s
= describe_CFI_CFA_rule(line
['cfa'])
1393 self
._emit
(' %-9s' % s
)
1395 for regnum
in reg_order
:
1397 s
= describe_CFI_register_rule(line
[regnum
])
1400 self
._emit
('%-6s' % s
)
1404 def _dump_debug_frames_interp(self
):
1405 """ Dump the interpreted (decoded) frame information from .debug_frame
1406 and .eh_framae sections.
1408 if self
._dwarfinfo
.has_EH_CFI():
1409 self
._dump
_frames
_interp
_info
(
1410 self
._dwarfinfo
.eh_frame_sec
,
1411 self
._dwarfinfo
.EH_CFI_entries())
1414 if self
._dwarfinfo
.has_CFI():
1415 self
._dump
_frames
_interp
_info
(
1416 self
._dwarfinfo
.debug_frame_sec
,
1417 self
._dwarfinfo
.CFI_entries())
1419 def _dump_debug_locations(self
):
1420 """ Dump the location lists from .debug_location section
1422 def _get_cu_base(cu
):
1423 top_die
= cu
.get_top_DIE()
1424 attr
= top_die
.attributes
1425 if 'DW_AT_low_pc' in attr
:
1426 return attr
['DW_AT_low_pc'].value
1427 elif 'DW_AT_entry_pc' in attr
:
1428 return attr
['DW_AT_entry_pc'].value
1430 raise ValueError("Can't find the base IP (low_pc) for a CU")
1432 di
= self
._dwarfinfo
1433 loc_lists
= di
.location_lists()
1434 if not loc_lists
: # No locations section - readelf outputs nothing
1437 loc_lists
= list(loc_lists
.iter_location_lists())
1438 if len(loc_lists
) == 0:
1439 # Present but empty locations section - readelf outputs a message
1440 self
._emitline
("\nSection '%s' has no debugging data." % di
.debug_loc_sec
.name
)
1443 # To dump a location list, one needs to know the CU.
1444 # Scroll through DIEs once, list the known location list offsets
1445 cu_map
= dict() # Loc list offset => CU
1446 for cu
in di
.iter_CUs():
1447 for die
in cu
.iter_DIEs():
1448 for key
in die
.attributes
:
1449 attr
= die
.attributes
[key
]
1450 if (LocationParser
.attribute_has_location(attr
, cu
['version']) and
1451 not LocationParser
._attribute
_has
_loc
_expr
(attr
, cu
['version'])):
1452 cu_map
[attr
.value
] = cu
1454 addr_size
= di
.config
.default_address_size
# In bytes, 4 or 8
1455 addr_width
= addr_size
* 2 # In hex digits, 8 or 16
1456 line_template
= " %%08x %%0%dx %%0%dx %%s%%s" % (addr_width
, addr_width
)
1458 self
._emitline
('Contents of the %s section:\n' % di
.debug_loc_sec
.name
)
1459 self
._emitline
(' Offset Begin End Expression')
1460 for loc_list
in loc_lists
:
1461 cu
= cu_map
.get(loc_list
[0].entry_offset
, False)
1463 raise ValueError("Location list can't be tracked to a CU")
1464 base_ip
= _get_cu_base(cu
)
1465 for entry
in loc_list
:
1466 # TODO: support BaseAddressEntry lines
1467 expr
= describe_DWARF_expr(entry
.loc_expr
, cu
.structs
, cu
.cu_offset
)
1468 postfix
= ' (start == end)' if entry
.begin_offset
== entry
.end_offset
else ''
1469 self
._emitline
(line_template
% (
1471 base_ip
+ entry
.begin_offset
,
1472 base_ip
+ entry
.end_offset
,
1475 # Pyelftools doesn't store the terminating entry,
1476 # but readelf emits its offset, so this should too.
1478 last_len
= 2*addr_size
1479 if isinstance(last
, LocationEntry
):
1480 last_len
+= 2 + len(last
.loc_expr
)
1481 self
._emitline
(" %08x <End of list>" % (last
.entry_offset
+ last_len
))
1483 def _display_arch_specific_arm(self
):
1484 """ Display the ARM architecture-specific info contained in the file.
1486 attr_sec
= self
.elffile
.get_section_by_name('.ARM.attributes')
1488 for s
in attr_sec
.iter_subsections():
1489 self
._emitline
("Attribute Section: %s" % s
.header
['vendor_name'])
1490 for ss
in s
.iter_subsubsections():
1491 h_val
= "" if ss
.header
.extra
is None else " ".join("%d" % x
for x
in ss
.header
.extra
)
1492 self
._emitline
(describe_attr_tag_arm(ss
.header
.tag
, h_val
, None))
1494 for attr
in ss
.iter_attributes():
1496 self
._emitline
(describe_attr_tag_arm(attr
.tag
,
1500 def _emit(self
, s
=''):
1501 """ Emit an object to output
1503 self
.output
.write(str(s
))
1505 def _emitline(self
, s
=''):
1506 """ Emit an object to output, followed by a newline
1508 self
.output
.write(str(s
).rstrip() + '\n')
1511 SCRIPT_DESCRIPTION
= 'Display information about the contents of ELF format files'
1512 VERSION_STRING
= '%%(prog)s: based on pyelftools %s' % __version__
1515 def main(stream
=None):
1516 # parse the command-line arguments and invoke ReadElf
1517 argparser
= argparse
.ArgumentParser(
1518 usage
='usage: %(prog)s [options] <elf-file>',
1519 description
=SCRIPT_DESCRIPTION
,
1520 add_help
=False, # -h is a real option of readelf
1522 argparser
.add_argument('file',
1523 nargs
='?', default
=None,
1524 help='ELF file to parse')
1525 argparser
.add_argument('-v', '--version',
1526 action
='version', version
=VERSION_STRING
)
1527 argparser
.add_argument('-d', '--dynamic',
1528 action
='store_true', dest
='show_dynamic_tags',
1529 help='Display the dynamic section')
1530 argparser
.add_argument('-H', '--help',
1531 action
='store_true', dest
='help',
1532 help='Display this information')
1533 argparser
.add_argument('-h', '--file-header',
1534 action
='store_true', dest
='show_file_header',
1535 help='Display the ELF file header')
1536 argparser
.add_argument('-l', '--program-headers', '--segments',
1537 action
='store_true', dest
='show_program_header',
1538 help='Display the program headers')
1539 argparser
.add_argument('-S', '--section-headers', '--sections',
1540 action
='store_true', dest
='show_section_header',
1541 help="Display the sections' headers")
1542 argparser
.add_argument('-e', '--headers',
1543 action
='store_true', dest
='show_all_headers',
1544 help='Equivalent to: -h -l -S')
1545 argparser
.add_argument('-s', '--symbols', '--syms',
1546 action
='store_true', dest
='show_symbols',
1547 help='Display the symbol table')
1548 argparser
.add_argument('-n', '--notes',
1549 action
='store_true', dest
='show_notes',
1550 help='Display the core notes (if present)')
1551 argparser
.add_argument('-r', '--relocs',
1552 action
='store_true', dest
='show_relocs',
1553 help='Display the relocations (if present)')
1554 argparser
.add_argument('-au', '--arm-unwind',
1555 action
='store_true', dest
='show_arm_unwind',
1556 help='Display the armeabi unwind information (if present)')
1557 argparser
.add_argument('-x', '--hex-dump',
1558 action
='store', dest
='show_hex_dump', metavar
='<number|name>',
1559 help='Dump the contents of section <number|name> as bytes')
1560 argparser
.add_argument('-p', '--string-dump',
1561 action
='store', dest
='show_string_dump', metavar
='<number|name>',
1562 help='Dump the contents of section <number|name> as strings')
1563 argparser
.add_argument('-V', '--version-info',
1564 action
='store_true', dest
='show_version_info',
1565 help='Display the version sections (if present)')
1566 argparser
.add_argument('-A', '--arch-specific',
1567 action
='store_true', dest
='show_arch_specific',
1568 help='Display the architecture-specific information (if present)')
1569 argparser
.add_argument('--debug-dump',
1570 action
='store', dest
='debug_dump_what', metavar
='<what>',
1572 'Display the contents of DWARF debug sections. <what> can ' +
1573 'one of {info,decodedline,frames,frames-interp,aranges,pubtypes,pubnames,loc}'))
1574 argparser
.add_argument('--traceback',
1575 action
='store_true', dest
='show_traceback',
1576 help='Dump the Python traceback on ELFError'
1577 ' exceptions from elftools')
1579 args
= argparser
.parse_args()
1581 if args
.help or not args
.file:
1582 argparser
.print_help()
1585 if args
.show_all_headers
:
1586 do_file_header
= do_section_header
= do_program_header
= True
1588 do_file_header
= args
.show_file_header
1589 do_section_header
= args
.show_section_header
1590 do_program_header
= args
.show_program_header
1592 with
open(args
.file, 'rb') as file:
1594 readelf
= ReadElf(file, stream
or sys
.stdout
)
1596 readelf
.display_file_header()
1597 if do_section_header
:
1598 readelf
.display_section_headers(
1599 show_heading
=not do_file_header
)
1600 if do_program_header
:
1601 readelf
.display_program_headers(
1602 show_heading
=not do_file_header
)
1603 if args
.show_dynamic_tags
:
1604 readelf
.display_dynamic_tags()
1605 if args
.show_symbols
:
1606 readelf
.display_symbol_tables()
1608 readelf
.display_notes()
1609 if args
.show_relocs
:
1610 readelf
.display_relocations()
1611 if args
.show_arm_unwind
:
1612 readelf
.display_arm_unwind()
1613 if args
.show_version_info
:
1614 readelf
.display_version_info()
1615 if args
.show_arch_specific
:
1616 readelf
.display_arch_specific()
1617 if args
.show_hex_dump
:
1618 readelf
.display_hex_dump(args
.show_hex_dump
)
1619 if args
.show_string_dump
:
1620 readelf
.display_string_dump(args
.show_string_dump
)
1621 if args
.debug_dump_what
:
1622 readelf
.display_debug_dump(args
.debug_dump_what
)
1623 except ELFError
as ex
:
1625 sys
.stderr
.write('ELF error: %s\n' % ex
)
1626 if args
.show_traceback
:
1627 traceback
.print_exc()
1632 # Run 'main' redirecting its output to readelfout.txt
1633 # Saves profiling information in readelf.profile
1634 PROFFILE
= 'readelf.profile'
1636 cProfile
.run('main(open("readelfout.txt", "w"))', PROFFILE
)
1638 # Dig in some profiling stats
1640 p
= pstats
.Stats(PROFFILE
)
1641 p
.sort_stats('cumulative').print_stats(25)
1644 #-------------------------------------------------------------------------------
1645 if __name__
== '__main__':