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 NoteSection
, SymbolTableSection
36 from elftools
.elf
.gnuversions
import (
37 GNUVerSymSection
, GNUVerDefSection
,
40 from elftools
.elf
.relocation
import RelocationSection
41 from elftools
.elf
.descriptions
import (
42 describe_ei_class
, describe_ei_data
, describe_ei_version
,
43 describe_ei_osabi
, describe_e_type
, describe_e_machine
,
44 describe_e_version_numeric
, describe_p_type
, describe_p_flags
,
45 describe_rh_flags
, describe_sh_type
, describe_sh_flags
,
46 describe_symbol_type
, describe_symbol_bind
, describe_symbol_visibility
,
47 describe_symbol_shndx
, describe_reloc_type
, describe_dyn_tag
,
48 describe_dt_flags
, describe_dt_flags_1
, describe_ver_flags
, describe_note
,
51 from elftools
.elf
.constants
import E_FLAGS
52 from elftools
.elf
.constants
import E_FLAGS_MASKS
53 from elftools
.elf
.constants
import SH_FLAGS
54 from elftools
.dwarf
.dwarfinfo
import DWARFInfo
55 from elftools
.dwarf
.descriptions
import (
56 describe_reg_name
, describe_attr_value
, set_global_machine_arch
,
57 describe_CFI_instructions
, describe_CFI_register_rule
,
58 describe_CFI_CFA_rule
, describe_DWARF_expr
60 from elftools
.dwarf
.constants
import (
61 DW_LNS_copy
, DW_LNS_set_file
, DW_LNE_define_file
)
62 from elftools
.dwarf
.locationlists
import LocationParser
, LocationEntry
63 from elftools
.dwarf
.callframe
import CIE
, FDE
, ZERO
66 class ReadElf(object):
67 """ display_* methods are used to emit output into the output stream
69 def __init__(self
, file, output
):
71 stream object with the ELF file to read
74 output stream to write to
76 self
.elffile
= ELFFile(file)
79 # Lazily initialized if a debug dump is requested
80 self
._dwarfinfo
= None
82 self
._versioninfo
= None
84 def display_file_header(self
):
85 """ Display the ELF file header
87 self
._emitline
('ELF Header:')
88 self
._emit
(' Magic: ')
89 self
._emit
(' '.join('%2.2x' % byte2int(b
)
90 for b
in self
.elffile
.e_ident_raw
))
92 header
= self
.elffile
.header
93 e_ident
= header
['e_ident']
94 self
._emitline
(' Class: %s' %
95 describe_ei_class(e_ident
['EI_CLASS']))
96 self
._emitline
(' Data: %s' %
97 describe_ei_data(e_ident
['EI_DATA']))
98 self
._emitline
(' Version: %s' %
99 describe_ei_version(e_ident
['EI_VERSION']))
100 self
._emitline
(' OS/ABI: %s' %
101 describe_ei_osabi(e_ident
['EI_OSABI']))
102 self
._emitline
(' ABI Version: %d' %
103 e_ident
['EI_ABIVERSION'])
104 self
._emitline
(' Type: %s' %
105 describe_e_type(header
['e_type']))
106 self
._emitline
(' Machine: %s' %
107 describe_e_machine(header
['e_machine']))
108 self
._emitline
(' Version: %s' %
109 describe_e_version_numeric(header
['e_version']))
110 self
._emitline
(' Entry point address: %s' %
111 self
._format
_hex
(header
['e_entry']))
112 self
._emit
(' Start of program headers: %s' %
114 self
._emitline
(' (bytes into file)')
115 self
._emit
(' Start of section headers: %s' %
117 self
._emitline
(' (bytes into file)')
118 self
._emitline
(' Flags: %s%s' %
119 (self
._format
_hex
(header
['e_flags']),
120 self
.decode_flags(header
['e_flags'])))
121 self
._emitline
(' Size of this header: %s (bytes)' %
123 self
._emitline
(' Size of program headers: %s (bytes)' %
124 header
['e_phentsize'])
125 self
._emitline
(' Number of program headers: %s' %
127 self
._emitline
(' Size of section headers: %s (bytes)' %
128 header
['e_shentsize'])
129 self
._emitline
(' Number of section headers: %s' %
131 self
._emitline
(' Section header string table index: %s' %
132 header
['e_shstrndx'])
134 def decode_flags(self
, flags
):
136 if self
.elffile
['e_machine'] == "EM_ARM":
137 eabi
= flags
& E_FLAGS
.EF_ARM_EABIMASK
138 flags
&= ~E_FLAGS
.EF_ARM_EABIMASK
140 if flags
& E_FLAGS
.EF_ARM_RELEXEC
:
141 description
+= ', relocatable executabl'
142 flags
&= ~E_FLAGS
.EF_ARM_RELEXEC
144 if eabi
== E_FLAGS
.EF_ARM_EABI_VER5
:
145 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
146 description
+= ', Version5 EABI'
147 if flags
& E_FLAGS
.EF_ARM_ABI_FLOAT_SOFT
:
148 description
+= ", soft-float ABI"
149 elif flags
& E_FLAGS
.EF_ARM_ABI_FLOAT_HARD
:
150 description
+= ", hard-float ABI"
152 if flags
& E_FLAGS
.EF_ARM_BE8
:
153 description
+= ", BE8"
154 elif flags
& E_FLAGS
.EF_ARM_LE8
:
155 description
+= ", LE8"
157 if flags
& ~EF_ARM_KNOWN_FLAGS
:
158 description
+= ', <unknown>'
160 description
+= ', <unrecognized EABI>'
162 elif self
.elffile
['e_machine'] == "EM_MIPS":
163 if flags
& E_FLAGS
.EF_MIPS_NOREORDER
:
164 description
+= ", noreorder"
165 if flags
& E_FLAGS
.EF_MIPS_PIC
:
166 description
+= ", pic"
167 if flags
& E_FLAGS
.EF_MIPS_CPIC
:
168 description
+= ", cpic"
169 if (flags
& E_FLAGS
.EF_MIPS_ABI2
):
170 description
+= ", abi2"
171 if (flags
& E_FLAGS
.EF_MIPS_32BITMODE
):
172 description
+= ", 32bitmode"
173 if (flags
& E_FLAGS_MASKS
.EFM_MIPS_ABI_O32
):
174 description
+= ", o32"
175 elif (flags
& E_FLAGS_MASKS
.EFM_MIPS_ABI_O64
):
176 description
+= ", o64"
177 elif (flags
& E_FLAGS_MASKS
.EFM_MIPS_ABI_EABI32
):
178 description
+= ", eabi32"
179 elif (flags
& E_FLAGS_MASKS
.EFM_MIPS_ABI_EABI64
):
180 description
+= ", eabi64"
181 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_1
:
182 description
+= ", mips1"
183 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_2
:
184 description
+= ", mips2"
185 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_3
:
186 description
+= ", mips3"
187 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_4
:
188 description
+= ", mips4"
189 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_5
:
190 description
+= ", mips5"
191 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_32R2
:
192 description
+= ", mips32r2"
193 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_64R2
:
194 description
+= ", mips64r2"
195 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_32
:
196 description
+= ", mips32"
197 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_64
:
198 description
+= ", mips64"
202 def display_program_headers(self
, show_heading
=True):
203 """ Display the ELF program headers.
204 If show_heading is True, displays the heading for this information
205 (Elf file type is...)
208 if self
.elffile
.num_segments() == 0:
209 self
._emitline
('There are no program headers in this file.')
212 elfheader
= self
.elffile
.header
214 self
._emitline
('Elf file type is %s' %
215 describe_e_type(elfheader
['e_type']))
216 self
._emitline
('Entry point is %s' %
217 self
._format
_hex
(elfheader
['e_entry']))
218 # readelf weirness - why isn't e_phoff printed as hex? (for section
220 self
._emitline
('There are %s program headers, starting at offset %s' % (
221 elfheader
['e_phnum'], elfheader
['e_phoff']))
224 self
._emitline
('Program Headers:')
226 # Now comes the table of program headers with their attributes. Note
227 # that due to different formatting constraints of 32-bit and 64-bit
228 # addresses, there are some conditions on elfclass here.
230 # First comes the table heading
232 if self
.elffile
.elfclass
== 32:
233 self
._emitline
(' Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align')
235 self
._emitline
(' Type Offset VirtAddr PhysAddr')
236 self
._emitline
(' FileSiz MemSiz Flags Align')
240 for segment
in self
.elffile
.iter_segments():
241 self
._emit
(' %-14s ' % describe_p_type(segment
['p_type']))
243 if self
.elffile
.elfclass
== 32:
244 self
._emitline
('%s %s %s %s %s %-3s %s' % (
245 self
._format
_hex
(segment
['p_offset'], fieldsize
=6),
246 self
._format
_hex
(segment
['p_vaddr'], fullhex
=True),
247 self
._format
_hex
(segment
['p_paddr'], fullhex
=True),
248 self
._format
_hex
(segment
['p_filesz'], fieldsize
=5),
249 self
._format
_hex
(segment
['p_memsz'], fieldsize
=5),
250 describe_p_flags(segment
['p_flags']),
251 self
._format
_hex
(segment
['p_align'])))
253 self
._emitline
('%s %s %s' % (
254 self
._format
_hex
(segment
['p_offset'], fullhex
=True),
255 self
._format
_hex
(segment
['p_vaddr'], fullhex
=True),
256 self
._format
_hex
(segment
['p_paddr'], fullhex
=True)))
257 self
._emitline
(' %s %s %-3s %s' % (
258 self
._format
_hex
(segment
['p_filesz'], fullhex
=True),
259 self
._format
_hex
(segment
['p_memsz'], fullhex
=True),
260 describe_p_flags(segment
['p_flags']),
261 # lead0x set to False for p_align, to mimic readelf.
262 # No idea why the difference from 32-bit mode :-|
263 self
._format
_hex
(segment
['p_align'], lead0x
=False)))
265 if isinstance(segment
, InterpSegment
):
266 self
._emitline
(' [Requesting program interpreter: %s]' %
267 segment
.get_interp_name())
269 # Sections to segments mapping
271 if self
.elffile
.num_sections() == 0:
272 # No sections? We're done
275 self
._emitline
('\n Section to Segment mapping:')
276 self
._emitline
(' Segment Sections...')
278 for nseg
, segment
in enumerate(self
.elffile
.iter_segments()):
279 self
._emit
(' %2.2d ' % nseg
)
281 for section
in self
.elffile
.iter_sections():
282 if ( not section
.is_null() and
283 not ((section
['sh_flags'] & SH_FLAGS
.SHF_TLS
) != 0 and
284 section
['sh_type'] == 'SHT_NOBITS' and
285 segment
['p_type'] != 'PT_TLS') and
286 segment
.section_in_segment(section
)):
287 self
._emit
('%s ' % section
.name
)
291 def display_section_headers(self
, show_heading
=True):
292 """ Display the ELF section headers
294 elfheader
= self
.elffile
.header
296 self
._emitline
('There are %s section headers, starting at offset %s' % (
297 elfheader
['e_shnum'], self
._format
_hex
(elfheader
['e_shoff'])))
299 if self
.elffile
.num_sections() == 0:
300 self
._emitline
('There are no sections in this file.')
303 self
._emitline
('\nSection Header%s:' % (
304 's' if elfheader
['e_shnum'] > 1 else ''))
306 # Different formatting constraints of 32-bit and 64-bit addresses
308 if self
.elffile
.elfclass
== 32:
309 self
._emitline
(' [Nr] Name Type Addr Off Size ES Flg Lk Inf Al')
311 self
._emitline
(' [Nr] Name Type Address Offset')
312 self
._emitline
(' Size EntSize Flags Link Info Align')
316 for nsec
, section
in enumerate(self
.elffile
.iter_sections()):
317 self
._emit
(' [%2u] %-17.17s %-15.15s ' % (
318 nsec
, section
.name
, describe_sh_type(section
['sh_type'])))
320 if self
.elffile
.elfclass
== 32:
321 self
._emitline
('%s %s %s %s %3s %2s %3s %2s' % (
322 self
._format
_hex
(section
['sh_addr'], fieldsize
=8, lead0x
=False),
323 self
._format
_hex
(section
['sh_offset'], fieldsize
=6, lead0x
=False),
324 self
._format
_hex
(section
['sh_size'], fieldsize
=6, lead0x
=False),
325 self
._format
_hex
(section
['sh_entsize'], fieldsize
=2, lead0x
=False),
326 describe_sh_flags(section
['sh_flags']),
327 section
['sh_link'], section
['sh_info'],
328 section
['sh_addralign']))
330 self
._emitline
(' %s %s' % (
331 self
._format
_hex
(section
['sh_addr'], fullhex
=True, lead0x
=False),
332 self
._format
_hex
(section
['sh_offset'],
333 fieldsize
=16 if section
['sh_offset'] > 0xffffffff else 8,
335 self
._emitline
(' %s %s %3s %2s %3s %s' % (
336 self
._format
_hex
(section
['sh_size'], fullhex
=True, lead0x
=False),
337 self
._format
_hex
(section
['sh_entsize'], fullhex
=True, lead0x
=False),
338 describe_sh_flags(section
['sh_flags']),
339 section
['sh_link'], section
['sh_info'],
340 section
['sh_addralign']))
342 self
._emitline
('Key to Flags:')
343 self
._emitline
(' W (write), A (alloc), X (execute), M (merge),'
344 ' S (strings), I (info),')
345 self
._emitline
(' L (link order), O (extra OS processing required),'
346 ' G (group), T (TLS),')
347 self
._emitline
(' C (compressed), x (unknown), o (OS specific),'
350 if self
.elffile
['e_machine'] == 'EM_ARM':
351 self
._emit
('y (purecode), ')
352 self
._emitline
('p (processor specific)')
354 def display_symbol_tables(self
):
355 """ Display the symbol tables contained in the file
357 self
._init
_versioninfo
()
359 symbol_tables
= [s
for s
in self
.elffile
.iter_sections()
360 if isinstance(s
, SymbolTableSection
)]
362 if not symbol_tables
and self
.elffile
.num_sections() == 0:
364 self
._emitline
('Dynamic symbol information is not available for'
365 ' displaying symbols.')
367 for section
in symbol_tables
:
368 if not isinstance(section
, SymbolTableSection
):
371 if section
['sh_entsize'] == 0:
372 self
._emitline
("\nSymbol table '%s' has a sh_entsize of zero!" % (
376 self
._emitline
("\nSymbol table '%s' contains %s entries:" % (
377 section
.name
, section
.num_symbols()))
379 if self
.elffile
.elfclass
== 32:
380 self
._emitline
(' Num: Value Size Type Bind Vis Ndx Name')
382 self
._emitline
(' Num: Value Size Type Bind Vis Ndx Name')
384 for nsym
, symbol
in enumerate(section
.iter_symbols()):
386 # readelf doesn't display version info for Solaris versioning
387 if (section
['sh_type'] == 'SHT_DYNSYM' and
388 self
._versioninfo
['type'] == 'GNU'):
389 version
= self
._symbol
_version
(nsym
)
390 if (version
['name'] != symbol
.name
and
391 version
['index'] not in ('VER_NDX_LOCAL',
393 if version
['filename']:
395 version_info
= '@%(name)s (%(index)i)' % version
398 if version
['hidden']:
399 version_info
= '@%(name)s' % version
401 version_info
= '@@%(name)s' % version
403 # symbol names are truncated to 25 chars, similarly to readelf
404 self
._emitline
('%6d: %s %s %-7s %-6s %-7s %4s %.25s%s' % (
407 symbol
['st_value'], fullhex
=True, lead0x
=False),
408 "%5d" % symbol
['st_size'] if symbol
['st_size'] < 100000 else hex(symbol
['st_size']),
409 describe_symbol_type(symbol
['st_info']['type']),
410 describe_symbol_bind(symbol
['st_info']['bind']),
411 describe_symbol_visibility(symbol
['st_other']['visibility']),
412 describe_symbol_shndx(symbol
['st_shndx']),
416 def display_dynamic_tags(self
):
417 """ Display the dynamic tags contained in the file
419 has_dynamic_sections
= False
420 for section
in self
.elffile
.iter_sections():
421 if not isinstance(section
, DynamicSection
):
424 has_dynamic_sections
= True
425 self
._emitline
("\nDynamic section at offset %s contains %s entries:" % (
426 self
._format
_hex
(section
['sh_offset']),
428 self
._emitline
(" Tag Type Name/Value")
430 padding
= 20 + (8 if self
.elffile
.elfclass
== 32 else 0)
431 for tag
in section
.iter_tags():
432 if tag
.entry
.d_tag
== 'DT_NEEDED':
433 parsed
= 'Shared library: [%s]' % tag
.needed
434 elif tag
.entry
.d_tag
== 'DT_RPATH':
435 parsed
= 'Library rpath: [%s]' % tag
.rpath
436 elif tag
.entry
.d_tag
== 'DT_RUNPATH':
437 parsed
= 'Library runpath: [%s]' % tag
.runpath
438 elif tag
.entry
.d_tag
== 'DT_SONAME':
439 parsed
= 'Library soname: [%s]' % tag
.soname
440 elif tag
.entry
.d_tag
.endswith(('SZ', 'ENT')):
441 parsed
= '%i (bytes)' % tag
['d_val']
442 elif tag
.entry
.d_tag
== 'DT_FLAGS':
443 parsed
= describe_dt_flags(tag
.entry
.d_val
)
444 elif tag
.entry
.d_tag
== 'DT_FLAGS_1':
445 parsed
= 'Flags: %s' % describe_dt_flags_1(tag
.entry
.d_val
)
446 elif tag
.entry
.d_tag
.endswith(('NUM', 'COUNT')):
447 parsed
= '%i' % tag
['d_val']
448 elif tag
.entry
.d_tag
== 'DT_PLTREL':
449 s
= describe_dyn_tag(tag
.entry
.d_val
)
450 if s
.startswith('DT_'):
453 elif tag
.entry
.d_tag
== 'DT_MIPS_FLAGS':
454 parsed
= describe_rh_flags(tag
.entry
.d_val
)
455 elif tag
.entry
.d_tag
in ('DT_MIPS_SYMTABNO',
456 'DT_MIPS_LOCAL_GOTNO'):
457 parsed
= str(tag
.entry
.d_val
)
459 parsed
= '%#x' % tag
['d_val']
461 self
._emitline
(" %s %-*s %s" % (
462 self
._format
_hex
(ENUM_D_TAG
.get(tag
.entry
.d_tag
, tag
.entry
.d_tag
),
463 fullhex
=True, lead0x
=True),
465 '(%s)' % (tag
.entry
.d_tag
[3:],),
467 if not has_dynamic_sections
:
468 self
._emitline
("\nThere is no dynamic section in this file.")
470 def display_notes(self
):
471 """ Display the notes contained in the file
473 for section
in self
.elffile
.iter_sections():
474 if isinstance(section
, NoteSection
):
475 for note
in section
.iter_notes():
476 self
._emitline
("\nDisplaying notes found in: {}".format(
478 self
._emitline
(' Owner Data size Description')
479 self
._emitline
(' %s %s\t%s' % (
480 note
['n_name'].ljust(20),
481 self
._format
_hex
(note
['n_descsz'], fieldsize
=8),
482 describe_note(note
)))
484 def display_relocations(self
):
485 """ Display the relocations contained in the file
487 has_relocation_sections
= False
488 for section
in self
.elffile
.iter_sections():
489 if not isinstance(section
, RelocationSection
):
492 has_relocation_sections
= True
493 self
._emitline
("\nRelocation section '%.128s' at offset %s contains %s entries:" % (
495 self
._format
_hex
(section
['sh_offset']),
496 section
.num_relocations()))
497 if section
.is_RELA():
498 self
._emitline
(" Offset Info Type Sym. Value Sym. Name + Addend")
500 self
._emitline
(" Offset Info Type Sym.Value Sym. Name")
502 # The symbol table section pointed to in sh_link
503 symtable
= self
.elffile
.get_section(section
['sh_link'])
505 for rel
in section
.iter_relocations():
506 hexwidth
= 8 if self
.elffile
.elfclass
== 32 else 12
507 self
._emit
('%s %s %-17.17s' % (
508 self
._format
_hex
(rel
['r_offset'],
509 fieldsize
=hexwidth
, lead0x
=False),
510 self
._format
_hex
(rel
['r_info'],
511 fieldsize
=hexwidth
, lead0x
=False),
513 rel
['r_info_type'], self
.elffile
)))
515 if rel
['r_info_sym'] == 0:
516 if section
.is_RELA():
517 fieldsize
= 8 if self
.elffile
.elfclass
== 32 else 16
518 addend
= self
._format
_hex
(rel
['r_addend'], lead0x
=False)
519 self
._emit
(' %s %s' % (' ' * fieldsize
, addend
))
523 symbol
= symtable
.get_symbol(rel
['r_info_sym'])
524 # Some symbols have zero 'st_name', so instead what's used
525 # is the name of the section they point at. Truncate symbol
526 # names (excluding version info) to 22 chars, similarly to
528 if symbol
['st_name'] == 0:
529 symsec
= self
.elffile
.get_section(symbol
['st_shndx'])
530 symbol_name
= symsec
.name
533 symbol_name
= symbol
.name
534 version
= self
._symbol
_version
(rel
['r_info_sym'])
535 version
= (version
['name']
536 if version
and version
['name'] else '')
537 symbol_name
= '%.22s' % symbol_name
539 symbol_name
+= '@' + version
541 self
._emit
(' %s %s' % (
544 fullhex
=True, lead0x
=False),
546 if section
.is_RELA():
547 self
._emit
(' %s %x' % (
548 '+' if rel
['r_addend'] >= 0 else '-',
549 abs(rel
['r_addend'])))
552 # Emit the two additional relocation types for ELF64 MIPS
554 if (self
.elffile
.elfclass
== 64 and
555 self
.elffile
['e_machine'] == 'EM_MIPS'):
557 rtype
= rel
['r_info_type%s' % i
]
558 self
._emit
(' Type%s: %s' % (
560 describe_reloc_type(rtype
, self
.elffile
)))
563 if not has_relocation_sections
:
564 self
._emitline
('\nThere are no relocations in this file.')
566 def display_version_info(self
):
567 """ Display the version info contained in the file
569 self
._init
_versioninfo
()
571 if not self
._versioninfo
['type']:
572 self
._emitline
("\nNo version information found in this file.")
575 for section
in self
.elffile
.iter_sections():
576 if isinstance(section
, GNUVerSymSection
):
577 self
._print
_version
_section
_header
(
578 section
, 'Version symbols', lead0x
=False)
580 num_symbols
= section
.num_symbols()
582 # Symbol version info are printed four by four entries
583 for idx_by_4
in range(0, num_symbols
, 4):
585 self
._emit
(' %03x:' % idx_by_4
)
587 for idx
in range(idx_by_4
, min(idx_by_4
+ 4, num_symbols
)):
589 symbol_version
= self
._symbol
_version
(idx
)
590 if symbol_version
['index'] == 'VER_NDX_LOCAL':
592 version_name
= '(*local*)'
593 elif symbol_version
['index'] == 'VER_NDX_GLOBAL':
595 version_name
= '(*global*)'
597 version_index
= symbol_version
['index']
598 version_name
= '(%(name)s)' % symbol_version
600 visibility
= 'h' if symbol_version
['hidden'] else ' '
602 self
._emit
('%4x%s%-13s' % (
603 version_index
, visibility
, version_name
))
607 elif isinstance(section
, GNUVerDefSection
):
608 self
._print
_version
_section
_header
(
609 section
, 'Version definition', indent
=2)
612 for verdef
, verdaux_iter
in section
.iter_versions():
613 verdaux
= next(verdaux_iter
)
616 if verdef
['vd_flags']:
617 flags
= describe_ver_flags(verdef
['vd_flags'])
618 # Mimic exactly the readelf output
623 self
._emitline
(' %s: Rev: %i Flags: %s Index: %i'
624 ' Cnt: %i Name: %s' % (
625 self
._format
_hex
(offset
, fieldsize
=6,
627 verdef
['vd_version'], flags
, verdef
['vd_ndx'],
628 verdef
['vd_cnt'], name
))
631 offset
+ verdef
['vd_aux'] + verdaux
['vda_next'])
632 for idx
, verdaux
in enumerate(verdaux_iter
, start
=1):
633 self
._emitline
(' %s: Parent %i: %s' %
634 (self
._format
_hex
(verdaux_offset
, fieldsize
=4),
636 verdaux_offset
+= verdaux
['vda_next']
638 offset
+= verdef
['vd_next']
640 elif isinstance(section
, GNUVerNeedSection
):
641 self
._print
_version
_section
_header
(section
, 'Version needs')
644 for verneed
, verneed_iter
in section
.iter_versions():
646 self
._emitline
(' %s: Version: %i File: %s Cnt: %i' % (
647 self
._format
_hex
(offset
, fieldsize
=6,
649 verneed
['vn_version'], verneed
.name
,
652 vernaux_offset
= offset
+ verneed
['vn_aux']
653 for idx
, vernaux
in enumerate(verneed_iter
, start
=1):
654 if vernaux
['vna_flags']:
655 flags
= describe_ver_flags(vernaux
['vna_flags'])
656 # Mimic exactly the readelf output
662 ' %s: Name: %s Flags: %s Version: %i' % (
663 self
._format
_hex
(vernaux_offset
, fieldsize
=4),
665 vernaux
['vna_other']))
667 vernaux_offset
+= vernaux
['vna_next']
669 offset
+= verneed
['vn_next']
671 def display_arch_specific(self
):
672 """ Display the architecture-specific info contained in the file.
674 if self
.elffile
['e_machine'] == 'EM_ARM':
675 self
._display
_arch
_specific
_arm
()
677 def display_hex_dump(self
, section_spec
):
678 """ Display a hex dump of a section. section_spec is either a section
681 section
= self
._section
_from
_spec
(section_spec
)
683 # readelf prints the warning to stderr. Even though stderrs are not compared
684 # in tests, we comply with that behavior.
685 sys
.stderr
.write('readelf: Warning: Section \'%s\' was not dumped because it does not exist!\n' % (
688 if section
['sh_type'] == 'SHT_NOBITS':
689 self
._emitline
("\nSection '%s' has no data to dump." % (
693 self
._emitline
("\nHex dump of section '%s':" % section
.name
)
694 self
._note
_relocs
_for
_section
(section
)
695 addr
= section
['sh_addr']
696 data
= section
.data()
699 while dataptr
< len(data
):
700 bytesleft
= len(data
) - dataptr
701 # chunks of 16 bytes per line
702 linebytes
= 16 if bytesleft
> 16 else bytesleft
704 self
._emit
(' %s ' % self
._format
_hex
(addr
, fieldsize
=8))
707 self
._emit
('%2.2x' % byte2int(data
[dataptr
+ i
]))
713 for i
in range(linebytes
):
714 c
= data
[dataptr
+ i
: dataptr
+ i
+ 1]
715 if byte2int(c
[0]) >= 32 and byte2int(c
[0]) < 0x7f:
716 self
._emit
(bytes2str(c
))
718 self
._emit
(bytes2str(b
'.'))
726 def display_string_dump(self
, section_spec
):
727 """ Display a strings dump of a section. section_spec is either a
728 section number or a name.
730 section
= self
._section
_from
_spec
(section_spec
)
732 # readelf prints the warning to stderr. Even though stderrs are not compared
733 # in tests, we comply with that behavior.
734 sys
.stderr
.write('readelf.py: Warning: Section \'%s\' was not dumped because it does not exist!\n' % (
737 if section
['sh_type'] == 'SHT_NOBITS':
738 self
._emitline
("\nSection '%s' has no data to dump." % (
742 self
._emitline
("\nString dump of section '%s':" % section
.name
)
745 data
= section
.data()
748 while dataptr
< len(data
):
749 while ( dataptr
< len(data
) and
750 not (32 <= byte2int(data
[dataptr
]) <= 127)):
753 if dataptr
>= len(data
):
757 while endptr
< len(data
) and byte2int(data
[endptr
]) != 0:
761 self
._emitline
(' [%6x] %s' % (
762 dataptr
, bytes2str(data
[dataptr
:endptr
])))
767 self
._emitline
(' No strings found in this section.')
771 def display_debug_dump(self
, dump_what
):
772 """ Dump a DWARF section
774 self
._init
_dwarfinfo
()
775 if self
._dwarfinfo
is None:
778 set_global_machine_arch(self
.elffile
.get_machine_arch())
780 if dump_what
== 'info':
781 self
._dump
_debug
_info
()
782 elif dump_what
== 'decodedline':
783 self
._dump
_debug
_line
_programs
()
784 elif dump_what
== 'frames':
785 self
._dump
_debug
_frames
()
786 elif dump_what
== 'frames-interp':
787 self
._dump
_debug
_frames
_interp
()
788 elif dump_what
== 'aranges':
789 self
._dump
_debug
_aranges
()
790 elif dump_what
in { 'pubtypes', 'pubnames' }:
791 self
._dump
_debug
_namelut
(dump_what
)
792 elif dump_what
== 'loc':
793 self
._dump
_debug
_locations
()
795 self
._emitline
('debug dump not yet supported for "%s"' % dump_what
)
797 def _format_hex(self
, addr
, fieldsize
=None, fullhex
=False, lead0x
=True,
799 """ Format an address into a hexadecimal string.
802 Size of the hexadecimal field (with leading zeros to fit the
803 address into. For example with fieldsize=8, the format will
805 If None, the minimal required field size will be used.
808 If True, override fieldsize to set it to the maximal size
809 needed for the elfclass
812 If True, leading 0x is added
815 If True, override lead0x to emulate the alternate
816 hexadecimal form specified in format string with the #
817 character: only non-zero values are prefixed with 0x.
818 This form is used by readelf.
827 s
= '0x' if lead0x
else ''
829 fieldsize
= 8 if self
.elffile
.elfclass
== 32 else 16
830 if fieldsize
is None:
833 field
= '%' + '0%sx' % fieldsize
834 return s
+ field
% addr
836 def _print_version_section_header(self
, version_section
, name
, lead0x
=True,
838 """ Print a section header of one version related section (versym,
839 verneed or verdef) with some options to accomodate readelf
840 little differences between each header (e.g. indentation
843 if hasattr(version_section
, 'num_versions'):
844 num_entries
= version_section
.num_versions()
846 num_entries
= version_section
.num_symbols()
848 self
._emitline
("\n%s section '%s' contains %s entries:" %
849 (name
, version_section
.name
, num_entries
))
850 self
._emitline
('%sAddr: %s Offset: %s Link: %i (%s)' % (
853 version_section
['sh_addr'], fieldsize
=16, lead0x
=lead0x
),
855 version_section
['sh_offset'], fieldsize
=6, lead0x
=True),
856 version_section
['sh_link'],
857 self
.elffile
.get_section(version_section
['sh_link']).name
861 def _init_versioninfo(self
):
862 """ Search and initialize informations about version related sections
863 and the kind of versioning used (GNU or Solaris).
865 if self
._versioninfo
is not None:
868 self
._versioninfo
= {'versym': None, 'verdef': None,
869 'verneed': None, 'type': None}
871 for section
in self
.elffile
.iter_sections():
872 if isinstance(section
, GNUVerSymSection
):
873 self
._versioninfo
['versym'] = section
874 elif isinstance(section
, GNUVerDefSection
):
875 self
._versioninfo
['verdef'] = section
876 elif isinstance(section
, GNUVerNeedSection
):
877 self
._versioninfo
['verneed'] = section
878 elif isinstance(section
, DynamicSection
):
879 for tag
in section
.iter_tags():
880 if tag
['d_tag'] == 'DT_VERSYM':
881 self
._versioninfo
['type'] = 'GNU'
884 if not self
._versioninfo
['type'] and (
885 self
._versioninfo
['verneed'] or self
._versioninfo
['verdef']):
886 self
._versioninfo
['type'] = 'Solaris'
888 def _symbol_version(self
, nsym
):
889 """ Return a dict containing information on the
890 or None if no version information is available
892 self
._init
_versioninfo
()
894 symbol_version
= dict.fromkeys(('index', 'name', 'filename', 'hidden'))
896 if (not self
._versioninfo
['versym'] or
897 nsym
>= self
._versioninfo
['versym'].num_symbols()):
900 symbol
= self
._versioninfo
['versym'].get_symbol(nsym
)
901 index
= symbol
.entry
['ndx']
902 if not index
in ('VER_NDX_LOCAL', 'VER_NDX_GLOBAL'):
905 if self
._versioninfo
['type'] == 'GNU':
906 # In GNU versioning mode, the highest bit is used to
907 # store whether the symbol is hidden or not
910 symbol_version
['hidden'] = True
912 if (self
._versioninfo
['verdef'] and
913 index
<= self
._versioninfo
['verdef'].num_versions()):
915 self
._versioninfo
['verdef'].get_version(index
)
916 symbol_version
['name'] = next(verdaux_iter
).name
919 self
._versioninfo
['verneed'].get_version(index
)
920 symbol_version
['name'] = vernaux
.name
921 symbol_version
['filename'] = verneed
.name
923 symbol_version
['index'] = index
924 return symbol_version
926 def _section_from_spec(self
, spec
):
927 """ Retrieve a section given a "spec" (either number or name).
928 Return None if no such section exists in the file.
932 if num
< self
.elffile
.num_sections():
933 return self
.elffile
.get_section(num
)
937 # Not a number. Must be a name then
938 return self
.elffile
.get_section_by_name(spec
)
940 def _note_relocs_for_section(self
, section
):
941 """ If there are relocation sections pointing to the givne section,
942 emit a note about it.
944 for relsec
in self
.elffile
.iter_sections():
945 if isinstance(relsec
, RelocationSection
):
946 info_idx
= relsec
['sh_info']
947 if self
.elffile
.get_section(info_idx
) == section
:
948 self
._emitline
(' Note: This section has relocations against it, but these have NOT been applied to this dump.')
951 def _init_dwarfinfo(self
):
952 """ Initialize the DWARF info contained in the file and assign it to
954 Leave self._dwarfinfo at None if no DWARF info was found in the file
956 if self
._dwarfinfo
is not None:
959 if self
.elffile
.has_dwarf_info():
960 self
._dwarfinfo
= self
.elffile
.get_dwarf_info()
962 self
._dwarfinfo
= None
964 def _dump_debug_info(self
):
965 """ Dump the debugging info section.
967 if not self
._dwarfinfo
.has_debug_info
:
969 self
._emitline
('Contents of the %s section:\n' % self
._dwarfinfo
.debug_info_sec
.name
)
971 # Offset of the .debug_info section in the stream
972 section_offset
= self
._dwarfinfo
.debug_info_sec
.global_offset
974 for cu
in self
._dwarfinfo
.iter_CUs():
975 self
._emitline
(' Compilation Unit @ offset %s:' %
976 self
._format
_hex
(cu
.cu_offset
))
977 self
._emitline
(' Length: %s (%s)' % (
978 self
._format
_hex
(cu
['unit_length']),
979 '%s-bit' % cu
.dwarf_format()))
980 self
._emitline
(' Version: %s' % cu
['version']),
981 self
._emitline
(' Abbrev Offset: %s' % (
982 self
._format
_hex
(cu
['debug_abbrev_offset']))),
983 self
._emitline
(' Pointer Size: %s' % cu
['address_size'])
985 # The nesting depth of each DIE within the tree of DIEs must be
986 # displayed. To implement this, a counter is incremented each time
987 # the current DIE has children, and decremented when a null die is
988 # encountered. Due to the way the DIE tree is serialized, this will
989 # correctly reflect the nesting depth
992 current_function
= None
993 for die
in cu
.iter_DIEs():
994 if die
.tag
== 'DW_TAG_subprogram':
995 current_function
= die
996 self
._emitline
(' <%s><%x>: Abbrev Number: %s%s' % (
1000 (' (%s)' % die
.tag
) if not die
.is_null() else ''))
1005 for attr
in itervalues(die
.attributes
):
1007 # Unknown attribute values are passed-through as integers
1008 if isinstance(name
, int):
1009 name
= 'Unknown AT value: %x' % name
1011 attr_desc
= describe_attr_value(attr
, die
, section_offset
)
1013 if 'DW_OP_fbreg' in attr_desc
and current_function
and not 'DW_AT_frame_base' in current_function
.attributes
:
1014 postfix
= ' [without dw_at_frame_base]'
1018 self
._emitline
(' <%x> %-18s: %s%s' % (
1024 if die
.has_children
:
1029 def _dump_debug_line_programs(self
):
1030 """ Dump the (decoded) line programs from .debug_line
1031 The programs are dumped in the order of the CUs they belong to.
1033 if not self
._dwarfinfo
.has_debug_info
:
1035 self
._emitline
('Decoded dump of debug contents of section %s:\n' % self
._dwarfinfo
.debug_line_sec
.name
)
1037 for cu
in self
._dwarfinfo
.iter_CUs():
1038 lineprogram
= self
._dwarfinfo
.line_program_for_CU(cu
)
1040 cu_filename
= bytes2str(lineprogram
['file_entry'][0].name
)
1041 if len(lineprogram
['include_directory']) > 0:
1042 dir_index
= lineprogram
['file_entry'][0].dir_index
1044 dir = lineprogram
['include_directory'][dir_index
- 1]
1047 cu_filename
= '%s/%s' % (bytes2str(dir), cu_filename
)
1049 self
._emitline
('CU: %s:' % cu_filename
)
1050 self
._emitline
('File name Line number Starting address')
1052 # Print each state's file, line and address information. For some
1053 # instructions other output is needed to be compatible with
1055 for entry
in lineprogram
.get_entries():
1058 # Special handling for commands that don't set a new state
1059 if entry
.command
== DW_LNS_set_file
:
1060 file_entry
= lineprogram
['file_entry'][entry
.args
[0] - 1]
1061 if file_entry
.dir_index
== 0:
1063 self
._emitline
('\n./%s:[++]' % (
1064 bytes2str(file_entry
.name
)))
1066 self
._emitline
('\n%s/%s:' % (
1067 bytes2str(lineprogram
['include_directory'][file_entry
.dir_index
- 1]),
1068 bytes2str(file_entry
.name
)))
1069 elif entry
.command
== DW_LNE_define_file
:
1070 self
._emitline
('%s:' % (
1071 bytes2str(lineprogram
['include_directory'][entry
.args
[0].dir_index
])))
1072 elif not state
.end_sequence
:
1073 # readelf doesn't print the state after end_sequence
1074 # instructions. I think it's a bug but to be compatible
1075 # I don't print them too.
1076 if lineprogram
['version'] < 4:
1077 self
._emitline
('%-35s %11d %18s' % (
1078 bytes2str(lineprogram
['file_entry'][state
.file - 1].name
),
1080 '0' if state
.address
== 0 else
1081 self
._format
_hex
(state
.address
)))
1083 self
._emitline
('%-35s %11d %18s[%d]' % (
1084 bytes2str(lineprogram
['file_entry'][state
.file - 1].name
),
1086 '0' if state
.address
== 0 else
1087 self
._format
_hex
(state
.address
),
1089 if entry
.command
== DW_LNS_copy
:
1090 # Another readelf oddity...
1093 def _dump_frames_info(self
, section
, cfi_entries
):
1094 """ Dump the raw call frame info in a section.
1096 `section` is the Section instance that contains the call frame info
1097 while `cfi_entries` must be an iterable that yields the sequence of
1098 CIE or FDE instances.
1100 self
._emitline
('Contents of the %s section:' % section
.name
)
1102 for entry
in cfi_entries
:
1103 if isinstance(entry
, CIE
):
1104 self
._emitline
('\n%08x %s %s CIE' % (
1106 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1107 self
._format
_hex
(entry
['CIE_id'], fieldsize
=8, lead0x
=False)))
1108 self
._emitline
(' Version: %d' % entry
['version'])
1109 self
._emitline
(' Augmentation: "%s"' % bytes2str(entry
['augmentation']))
1110 self
._emitline
(' Code alignment factor: %u' % entry
['code_alignment_factor'])
1111 self
._emitline
(' Data alignment factor: %d' % entry
['data_alignment_factor'])
1112 self
._emitline
(' Return address column: %d' % entry
['return_address_register'])
1113 if entry
.augmentation_bytes
:
1114 self
._emitline
(' Augmentation data: {}'.format(' '.join(
1115 '{:02x}'.format(ord(b
))
1116 for b
in iterbytes(entry
.augmentation_bytes
)
1120 elif isinstance(entry
, FDE
):
1121 self
._emitline
('\n%08x %s %s FDE cie=%08x pc=%s..%s' % (
1123 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1124 self
._format
_hex
(entry
['CIE_pointer'], fieldsize
=8, lead0x
=False),
1126 self
._format
_hex
(entry
['initial_location'], fullhex
=True, lead0x
=False),
1128 entry
['initial_location'] + entry
['address_range'],
1129 fullhex
=True, lead0x
=False)))
1130 if entry
.augmentation_bytes
:
1131 self
._emitline
(' Augmentation data: {}'.format(' '.join(
1132 '{:02x}'.format(ord(b
))
1133 for b
in iterbytes(entry
.augmentation_bytes
)
1136 else: # ZERO terminator
1137 assert isinstance(entry
, ZERO
)
1138 self
._emitline
('\n%08x ZERO terminator' % entry
.offset
)
1141 self
._emit
(describe_CFI_instructions(entry
))
1144 def _dump_debug_frames(self
):
1145 """ Dump the raw frame info from .debug_frame and .eh_frame sections.
1147 if self
._dwarfinfo
.has_EH_CFI():
1148 self
._dump
_frames
_info
(
1149 self
._dwarfinfo
.eh_frame_sec
,
1150 self
._dwarfinfo
.EH_CFI_entries())
1153 if self
._dwarfinfo
.has_CFI():
1154 self
._dump
_frames
_info
(
1155 self
._dwarfinfo
.debug_frame_sec
,
1156 self
._dwarfinfo
.CFI_entries())
1158 def _dump_debug_namelut(self
, what
):
1160 Dump the debug pubnames section.
1162 if what
== 'pubnames':
1163 namelut
= self
._dwarfinfo
.get_pubnames()
1164 section
= self
._dwarfinfo
.debug_pubnames_sec
1166 namelut
= self
._dwarfinfo
.get_pubtypes()
1167 section
= self
._dwarfinfo
.debug_pubtypes_sec
1169 # readelf prints nothing if the section is not present.
1170 if namelut
is None or len(namelut
) == 0:
1173 self
._emitline
('Contents of the %s section:' % section
.name
)
1176 cu_headers
= namelut
.get_cu_headers()
1178 # go over CU-by-CU first and item-by-item next.
1179 for (cu_hdr
, (cu_ofs
, items
)) in izip(cu_headers
, itertools
.groupby(
1180 namelut
.items(), key
= lambda x
: x
[1].cu_ofs
)):
1182 self
._emitline
(' Length: %d' % cu_hdr
.unit_length
)
1183 self
._emitline
(' Version: %d' % cu_hdr
.version
)
1184 self
._emitline
(' Offset into .debug_info section: 0x%x' % cu_hdr
.debug_info_offset
)
1185 self
._emitline
(' Size of area in .debug_info section: %d' % cu_hdr
.debug_info_length
)
1187 self
._emitline
(' Offset Name')
1189 self
._emitline
(' %x %s' % (item
[1].die_ofs
- cu_ofs
, item
[0]))
1192 def _dump_debug_aranges(self
):
1193 """ Dump the aranges table
1195 aranges_table
= self
._dwarfinfo
.get_aranges()
1196 if aranges_table
== None:
1198 # seems redundent, but we need to get the unsorted set of entries to match system readelf
1199 unordered_entries
= aranges_table
._get
_entries
()
1201 if len(unordered_entries
) == 0:
1203 self
._emitline
("Section '.debug_aranges' has no debugging data.")
1206 self
._emitline
('Contents of the %s section:' % self
._dwarfinfo
.debug_aranges_sec
.name
)
1209 for entry
in unordered_entries
:
1210 if prev_offset
!= entry
.info_offset
:
1211 if entry
!= unordered_entries
[0]:
1212 self
._emitline
(' %s %s' % (
1213 self
._format
_hex
(0, fullhex
=True, lead0x
=False),
1214 self
._format
_hex
(0, fullhex
=True, lead0x
=False)))
1215 self
._emitline
(' Length: %d' % (entry
.unit_length
))
1216 self
._emitline
(' Version: %d' % (entry
.version
))
1217 self
._emitline
(' Offset into .debug_info: 0x%x' % (entry
.info_offset
))
1218 self
._emitline
(' Pointer Size: %d' % (entry
.address_size
))
1219 self
._emitline
(' Segment Size: %d' % (entry
.segment_size
))
1221 self
._emitline
(' Address Length')
1222 self
._emitline
(' %s %s' % (
1223 self
._format
_hex
(entry
.begin_addr
, fullhex
=True, lead0x
=False),
1224 self
._format
_hex
(entry
.length
, fullhex
=True, lead0x
=False)))
1225 prev_offset
= entry
.info_offset
1226 self
._emitline
(' %s %s' % (
1227 self
._format
_hex
(0, fullhex
=True, lead0x
=False),
1228 self
._format
_hex
(0, fullhex
=True, lead0x
=False)))
1230 def _dump_frames_interp_info(self
, section
, cfi_entries
):
1231 """ Dump interpreted (decoded) frame information in a section.
1233 `section` is the Section instance that contains the call frame info
1234 while `cfi_entries` must be an iterable that yields the sequence of
1235 CIE or FDE instances.
1237 self
._emitline
('Contents of the %s section:' % section
.name
)
1239 for entry
in cfi_entries
:
1240 if isinstance(entry
, CIE
):
1241 self
._emitline
('\n%08x %s %s CIE "%s" cf=%d df=%d ra=%d' % (
1243 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1244 self
._format
_hex
(entry
['CIE_id'], fieldsize
=8, lead0x
=False),
1245 bytes2str(entry
['augmentation']),
1246 entry
['code_alignment_factor'],
1247 entry
['data_alignment_factor'],
1248 entry
['return_address_register']))
1249 ra_regnum
= entry
['return_address_register']
1251 elif isinstance(entry
, FDE
):
1252 self
._emitline
('\n%08x %s %s FDE cie=%08x pc=%s..%s' % (
1254 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1255 self
._format
_hex
(entry
['CIE_pointer'], fieldsize
=8, lead0x
=False),
1257 self
._format
_hex
(entry
['initial_location'], fullhex
=True, lead0x
=False),
1258 self
._format
_hex
(entry
['initial_location'] + entry
['address_range'],
1259 fullhex
=True, lead0x
=False)))
1260 ra_regnum
= entry
.cie
['return_address_register']
1262 # If the FDE brings adds no unwinding information compared to
1263 # its CIE, omit its table.
1264 if (len(entry
.get_decoded().table
) ==
1265 len(entry
.cie
.get_decoded().table
)):
1268 else: # ZERO terminator
1269 assert isinstance(entry
, ZERO
)
1270 self
._emitline
('\n%08x ZERO terminator' % entry
.offset
)
1274 decoded_table
= entry
.get_decoded()
1275 if len(decoded_table
.table
) == 0:
1278 # Print the heading row for the decoded table
1280 self
._emit
(' ' if entry
.structs
.address_size
== 4 else ' ')
1283 # Look at the registers the decoded table describes.
1284 # We build reg_order here to match readelf's order. In particular,
1285 # registers are sorted by their number, and the register matching
1286 # ra_regnum is always listed last with a special heading.
1287 decoded_table
= entry
.get_decoded()
1288 reg_order
= sorted(ifilter(
1289 lambda r
: r
!= ra_regnum
,
1290 decoded_table
.reg_order
))
1291 if len(decoded_table
.reg_order
):
1293 # Headings for the registers
1294 for regnum
in reg_order
:
1295 self
._emit
('%-6s' % describe_reg_name(regnum
))
1296 self
._emitline
('ra ')
1298 # Now include ra_regnum in reg_order to print its values
1299 # similarly to the other registers.
1300 reg_order
.append(ra_regnum
)
1304 for line
in decoded_table
.table
:
1305 self
._emit
(self
._format
_hex
(
1306 line
['pc'], fullhex
=True, lead0x
=False))
1308 if line
['cfa'] is not None:
1309 s
= describe_CFI_CFA_rule(line
['cfa'])
1312 self
._emit
(' %-9s' % s
)
1314 for regnum
in reg_order
:
1316 s
= describe_CFI_register_rule(line
[regnum
])
1319 self
._emit
('%-6s' % s
)
1323 def _dump_debug_frames_interp(self
):
1324 """ Dump the interpreted (decoded) frame information from .debug_frame
1325 and .eh_framae sections.
1327 if self
._dwarfinfo
.has_EH_CFI():
1328 self
._dump
_frames
_interp
_info
(
1329 self
._dwarfinfo
.eh_frame_sec
,
1330 self
._dwarfinfo
.EH_CFI_entries())
1333 if self
._dwarfinfo
.has_CFI():
1334 self
._dump
_frames
_interp
_info
(
1335 self
._dwarfinfo
.debug_frame_sec
,
1336 self
._dwarfinfo
.CFI_entries())
1338 def _dump_debug_locations(self
):
1339 """ Dump the location lists from .debug_location section
1341 def _get_cu_base(cu
):
1342 top_die
= cu
.get_top_DIE()
1343 attr
= top_die
.attributes
1344 if 'DW_AT_low_pc' in attr
:
1345 return attr
['DW_AT_low_pc'].value
1346 elif 'DW_AT_entry_pc' in attr
:
1347 return attr
['DW_AT_entry_pc'].value
1349 raise ValueError("Can't find the base IP (low_pc) for a CU")
1351 di
= self
._dwarfinfo
1352 loc_lists
= di
.location_lists()
1353 if not loc_lists
: # No locations section - readelf outputs nothing
1356 loc_lists
= list(loc_lists
.iter_location_lists())
1357 if len(loc_lists
) == 0:
1358 # Present but empty locations section - readelf outputs a message
1359 self
._emitline
("\nSection '%s' has no debugging data." % di
.debug_loc_sec
.name
)
1362 # To dump a location list, one needs to know the CU.
1363 # Scroll through DIEs once, list the known location list offsets
1364 cu_map
= dict() # Loc list offset => CU
1365 for cu
in di
.iter_CUs():
1366 for die
in cu
.iter_DIEs():
1367 for key
in die
.attributes
:
1368 attr
= die
.attributes
[key
]
1369 if (LocationParser
.attribute_has_location(attr
, cu
['version']) and
1370 not LocationParser
._attribute
_has
_loc
_expr
(attr
, cu
['version'])):
1371 cu_map
[attr
.value
] = cu
1373 addr_size
= di
.config
.default_address_size
# In bytes, 4 or 8
1374 addr_width
= addr_size
* 2 # In hex digits, 8 or 16
1375 line_template
= " %%08x %%0%dx %%0%dx %%s%%s" % (addr_width
, addr_width
)
1377 self
._emitline
('Contents of the %s section:\n' % di
.debug_loc_sec
.name
)
1378 self
._emitline
(' Offset Begin End Expression')
1379 for loc_list
in loc_lists
:
1380 cu
= cu_map
.get(loc_list
[0].entry_offset
, False)
1382 raise ValueError("Location list can't be tracked to a CU")
1383 base_ip
= _get_cu_base(cu
)
1384 for entry
in loc_list
:
1385 # TODO: support BaseAddressEntry lines
1386 expr
= describe_DWARF_expr(entry
.loc_expr
, cu
.structs
, cu
.cu_offset
)
1387 postfix
= ' (start == end)' if entry
.begin_offset
== entry
.end_offset
else ''
1388 self
._emitline
(line_template
% (
1390 base_ip
+ entry
.begin_offset
,
1391 base_ip
+ entry
.end_offset
,
1394 # Pyelftools doesn't store the terminating entry,
1395 # but readelf emits its offset, so this should too.
1397 last_len
= 2*addr_size
1398 if isinstance(last
, LocationEntry
):
1399 last_len
+= 2 + len(last
.loc_expr
)
1400 self
._emitline
(" %08x <End of list>" % (last
.entry_offset
+ last_len
))
1402 def _display_arch_specific_arm(self
):
1403 """ Display the ARM architecture-specific info contained in the file.
1405 attr_sec
= self
.elffile
.get_section_by_name('.ARM.attributes')
1407 for s
in attr_sec
.iter_subsections():
1408 self
._emitline
("Attribute Section: %s" % s
.header
['vendor_name'])
1409 for ss
in s
.iter_subsubsections():
1410 h_val
= "" if ss
.header
.extra
is None else " ".join("%d" % x
for x
in ss
.header
.extra
)
1411 self
._emitline
(describe_attr_tag_arm(ss
.header
.tag
, h_val
, None))
1413 for attr
in ss
.iter_attributes():
1415 self
._emitline
(describe_attr_tag_arm(attr
.tag
,
1419 def _emit(self
, s
=''):
1420 """ Emit an object to output
1422 self
.output
.write(str(s
))
1424 def _emitline(self
, s
=''):
1425 """ Emit an object to output, followed by a newline
1427 self
.output
.write(str(s
).rstrip() + '\n')
1430 SCRIPT_DESCRIPTION
= 'Display information about the contents of ELF format files'
1431 VERSION_STRING
= '%%(prog)s: based on pyelftools %s' % __version__
1434 def main(stream
=None):
1435 # parse the command-line arguments and invoke ReadElf
1436 argparser
= argparse
.ArgumentParser(
1437 usage
='usage: %(prog)s [options] <elf-file>',
1438 description
=SCRIPT_DESCRIPTION
,
1439 add_help
=False, # -h is a real option of readelf
1441 argparser
.add_argument('file',
1442 nargs
='?', default
=None,
1443 help='ELF file to parse')
1444 argparser
.add_argument('-v', '--version',
1445 action
='version', version
=VERSION_STRING
)
1446 argparser
.add_argument('-d', '--dynamic',
1447 action
='store_true', dest
='show_dynamic_tags',
1448 help='Display the dynamic section')
1449 argparser
.add_argument('-H', '--help',
1450 action
='store_true', dest
='help',
1451 help='Display this information')
1452 argparser
.add_argument('-h', '--file-header',
1453 action
='store_true', dest
='show_file_header',
1454 help='Display the ELF file header')
1455 argparser
.add_argument('-l', '--program-headers', '--segments',
1456 action
='store_true', dest
='show_program_header',
1457 help='Display the program headers')
1458 argparser
.add_argument('-S', '--section-headers', '--sections',
1459 action
='store_true', dest
='show_section_header',
1460 help="Display the sections' headers")
1461 argparser
.add_argument('-e', '--headers',
1462 action
='store_true', dest
='show_all_headers',
1463 help='Equivalent to: -h -l -S')
1464 argparser
.add_argument('-s', '--symbols', '--syms',
1465 action
='store_true', dest
='show_symbols',
1466 help='Display the symbol table')
1467 argparser
.add_argument('-n', '--notes',
1468 action
='store_true', dest
='show_notes',
1469 help='Display the core notes (if present)')
1470 argparser
.add_argument('-r', '--relocs',
1471 action
='store_true', dest
='show_relocs',
1472 help='Display the relocations (if present)')
1473 argparser
.add_argument('-x', '--hex-dump',
1474 action
='store', dest
='show_hex_dump', metavar
='<number|name>',
1475 help='Dump the contents of section <number|name> as bytes')
1476 argparser
.add_argument('-p', '--string-dump',
1477 action
='store', dest
='show_string_dump', metavar
='<number|name>',
1478 help='Dump the contents of section <number|name> as strings')
1479 argparser
.add_argument('-V', '--version-info',
1480 action
='store_true', dest
='show_version_info',
1481 help='Display the version sections (if present)')
1482 argparser
.add_argument('-A', '--arch-specific',
1483 action
='store_true', dest
='show_arch_specific',
1484 help='Display the architecture-specific information (if present)')
1485 argparser
.add_argument('--debug-dump',
1486 action
='store', dest
='debug_dump_what', metavar
='<what>',
1488 'Display the contents of DWARF debug sections. <what> can ' +
1489 'one of {info,decodedline,frames,frames-interp,aranges,pubtypes,pubnames,loc}'))
1490 argparser
.add_argument('--traceback',
1491 action
='store_true', dest
='show_traceback',
1492 help='Dump the Python traceback on ELFError'
1493 ' exceptions from elftools')
1495 args
= argparser
.parse_args()
1497 if args
.help or not args
.file:
1498 argparser
.print_help()
1501 if args
.show_all_headers
:
1502 do_file_header
= do_section_header
= do_program_header
= True
1504 do_file_header
= args
.show_file_header
1505 do_section_header
= args
.show_section_header
1506 do_program_header
= args
.show_program_header
1508 with
open(args
.file, 'rb') as file:
1510 readelf
= ReadElf(file, stream
or sys
.stdout
)
1512 readelf
.display_file_header()
1513 if do_section_header
:
1514 readelf
.display_section_headers(
1515 show_heading
=not do_file_header
)
1516 if do_program_header
:
1517 readelf
.display_program_headers(
1518 show_heading
=not do_file_header
)
1519 if args
.show_dynamic_tags
:
1520 readelf
.display_dynamic_tags()
1521 if args
.show_symbols
:
1522 readelf
.display_symbol_tables()
1524 readelf
.display_notes()
1525 if args
.show_relocs
:
1526 readelf
.display_relocations()
1527 if args
.show_version_info
:
1528 readelf
.display_version_info()
1529 if args
.show_arch_specific
:
1530 readelf
.display_arch_specific()
1531 if args
.show_hex_dump
:
1532 readelf
.display_hex_dump(args
.show_hex_dump
)
1533 if args
.show_string_dump
:
1534 readelf
.display_string_dump(args
.show_string_dump
)
1535 if args
.debug_dump_what
:
1536 readelf
.display_debug_dump(args
.debug_dump_what
)
1537 except ELFError
as ex
:
1539 sys
.stderr
.write('ELF error: %s\n' % ex
)
1540 if args
.show_traceback
:
1541 traceback
.print_exc()
1546 # Run 'main' redirecting its output to readelfout.txt
1547 # Saves profiling information in readelf.profile
1548 PROFFILE
= 'readelf.profile'
1550 cProfile
.run('main(open("readelfout.txt", "w"))', PROFFILE
)
1552 # Dig in some profiling stats
1554 p
= pstats
.Stats(PROFFILE
)
1555 p
.sort_stats('cumulative').print_stats(25)
1558 #-------------------------------------------------------------------------------
1559 if __name__
== '__main__':