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
.utils
import bytes2str
, iterbytes
30 from elftools
.elf
.elffile
import ELFFile
31 from elftools
.elf
.dynamic
import DynamicSection
, DynamicSegment
32 from elftools
.elf
.enums
import ENUM_D_TAG
33 from elftools
.elf
.segments
import InterpSegment
34 from elftools
.elf
.sections
import (
35 NoteSection
, SymbolTableSection
, SymbolTableIndexSection
37 from elftools
.elf
.gnuversions
import (
38 GNUVerSymSection
, GNUVerDefSection
,
41 from elftools
.elf
.relocation
import RelocationSection
42 from elftools
.elf
.descriptions
import (
43 describe_ei_class
, describe_ei_data
, describe_ei_version
,
44 describe_ei_osabi
, describe_e_type
, describe_e_machine
,
45 describe_e_version_numeric
, describe_p_type
, describe_p_flags
,
46 describe_rh_flags
, describe_sh_type
, describe_sh_flags
,
47 describe_symbol_type
, describe_symbol_bind
, describe_symbol_visibility
,
48 describe_symbol_shndx
, describe_reloc_type
, describe_dyn_tag
,
49 describe_dt_flags
, describe_dt_flags_1
, describe_ver_flags
, describe_note
,
50 describe_attr_tag_arm
, describe_attr_tag_riscv
, describe_symbol_other
52 from elftools
.elf
.constants
import E_FLAGS
53 from elftools
.elf
.constants
import E_FLAGS_MASKS
54 from elftools
.elf
.constants
import SH_FLAGS
55 from elftools
.elf
.constants
import SHN_INDICES
56 from elftools
.dwarf
.dwarfinfo
import DWARFInfo
57 from elftools
.dwarf
.descriptions
import (
58 describe_reg_name
, describe_attr_value
, set_global_machine_arch
,
59 describe_CFI_instructions
, describe_CFI_register_rule
,
60 describe_CFI_CFA_rule
, describe_DWARF_expr
62 from elftools
.dwarf
.constants
import (
63 DW_LNS_copy
, DW_LNS_set_file
, DW_LNE_define_file
)
64 from elftools
.dwarf
.locationlists
import LocationParser
, LocationEntry
, LocationViewPair
, BaseAddressEntry
as LocBaseAddressEntry
, LocationListsPair
65 from elftools
.dwarf
.ranges
import RangeEntry
, BaseAddressEntry
as RangeBaseAddressEntry
, RangeListsPair
66 from elftools
.dwarf
.callframe
import CIE
, FDE
, ZERO
67 from elftools
.ehabi
.ehabiinfo
import CorruptEHABIEntry
, CannotUnwindEHABIEntry
, GenericEHABIEntry
68 from elftools
.dwarf
.enums
import ENUM_DW_UT
71 top_die
= cu
.get_top_DIE()
72 attr
= top_die
.attributes
73 if 'DW_AT_low_pc' in attr
:
74 return attr
['DW_AT_low_pc'].value
75 elif 'DW_AT_entry_pc' in attr
:
76 return attr
['DW_AT_entry_pc'].value
77 elif 'DW_AT_ranges' in attr
:
78 # Rare case but happens: rangelist in the top DIE.
79 # If there is a base or at least one absolute entry,
80 # this will give us the base IP for the CU.
81 rl
= cu
.dwarfinfo
.range_lists().get_range_list_at_offset(attr
['DW_AT_ranges'].value
, cu
)
84 if isinstance(r
, RangeBaseAddressEntry
):
86 elif isinstance(r
, RangeEntry
) and r
.is_absolute
:
90 if ip
is not None and (base_ip
is None or ip
< base_ip
):
93 raise ValueError("Can't find the base IP (low_pc) for a CU")
96 raise ValueError("Can't find the base IP (low_pc) for a CU")
98 class ReadElf(object):
99 """ display_* methods are used to emit output into the output stream
101 def __init__(self
, file, output
):
103 stream object with the ELF file to read
106 output stream to write to
108 self
.elffile
= ELFFile(file)
111 # Lazily initialized if a debug dump is requested
112 self
._dwarfinfo
= None
114 self
._versioninfo
= None
116 self
._shndx
_sections
= None
118 def display_file_header(self
):
119 """ Display the ELF file header
121 self
._emitline
('ELF Header:')
122 self
._emit
(' Magic: ')
123 self
._emit
(' '.join('%2.2x' % b
124 for b
in self
.elffile
.e_ident_raw
))
126 header
= self
.elffile
.header
127 e_ident
= header
['e_ident']
128 self
._emitline
(' Class: %s' %
129 describe_ei_class(e_ident
['EI_CLASS']))
130 self
._emitline
(' Data: %s' %
131 describe_ei_data(e_ident
['EI_DATA']))
132 self
._emitline
(' Version: %s' %
133 describe_ei_version(e_ident
['EI_VERSION']))
134 self
._emitline
(' OS/ABI: %s' %
135 describe_ei_osabi(e_ident
['EI_OSABI']))
136 self
._emitline
(' ABI Version: %d' %
137 e_ident
['EI_ABIVERSION'])
138 self
._emitline
(' Type: %s' %
139 describe_e_type(header
['e_type'], self
.elffile
))
140 self
._emitline
(' Machine: %s' %
141 describe_e_machine(header
['e_machine']))
142 self
._emitline
(' Version: %s' %
143 describe_e_version_numeric(header
['e_version']))
144 self
._emitline
(' Entry point address: %s' %
145 self
._format
_hex
(header
['e_entry']))
146 self
._emit
(' Start of program headers: %s' %
148 self
._emitline
(' (bytes into file)')
149 self
._emit
(' Start of section headers: %s' %
151 self
._emitline
(' (bytes into file)')
152 self
._emitline
(' Flags: %s%s' %
153 (self
._format
_hex
(header
['e_flags']),
154 self
.decode_flags(header
['e_flags'])))
155 self
._emitline
(' Size of this header: %s (bytes)' %
157 self
._emitline
(' Size of program headers: %s (bytes)' %
158 header
['e_phentsize'])
159 self
._emitline
(' Number of program headers: %s' %
161 self
._emitline
(' Size of section headers: %s (bytes)' %
162 header
['e_shentsize'])
163 self
._emit
(' Number of section headers: %s' %
165 if header
['e_shnum'] == 0 and self
.elffile
.num_sections() != 0:
166 self
._emitline
(' (%d)' % self
.elffile
.num_sections())
169 self
._emit
(' Section header string table index: %s' %
170 header
['e_shstrndx'])
171 if header
['e_shstrndx'] == SHN_INDICES
.SHN_XINDEX
:
172 self
._emitline
(' (%d)' % self
.elffile
.get_shstrndx())
176 def decode_flags(self
, flags
):
178 if self
.elffile
['e_machine'] == "EM_ARM":
179 eabi
= flags
& E_FLAGS
.EF_ARM_EABIMASK
180 flags
&= ~E_FLAGS
.EF_ARM_EABIMASK
182 if flags
& E_FLAGS
.EF_ARM_RELEXEC
:
183 description
+= ', relocatable executabl'
184 flags
&= ~E_FLAGS
.EF_ARM_RELEXEC
186 if eabi
== E_FLAGS
.EF_ARM_EABI_VER5
:
187 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
188 description
+= ', Version5 EABI'
189 if flags
& E_FLAGS
.EF_ARM_ABI_FLOAT_SOFT
:
190 description
+= ", soft-float ABI"
191 elif flags
& E_FLAGS
.EF_ARM_ABI_FLOAT_HARD
:
192 description
+= ", hard-float ABI"
194 if flags
& E_FLAGS
.EF_ARM_BE8
:
195 description
+= ", BE8"
196 elif flags
& E_FLAGS
.EF_ARM_LE8
:
197 description
+= ", LE8"
199 if flags
& ~EF_ARM_KNOWN_FLAGS
:
200 description
+= ', <unknown>'
202 description
+= ', <unrecognized EABI>'
204 elif self
.elffile
['e_machine'] == 'EM_PPC64':
205 if flags
& E_FLAGS
.EF_PPC64_ABI_V2
:
206 description
+= ', abiv2'
208 elif self
.elffile
['e_machine'] == "EM_MIPS":
209 if flags
& E_FLAGS
.EF_MIPS_NOREORDER
:
210 description
+= ", noreorder"
211 if flags
& E_FLAGS
.EF_MIPS_PIC
:
212 description
+= ", pic"
213 if flags
& E_FLAGS
.EF_MIPS_CPIC
:
214 description
+= ", cpic"
215 if (flags
& E_FLAGS
.EF_MIPS_ABI2
):
216 description
+= ", abi2"
217 if (flags
& E_FLAGS
.EF_MIPS_32BITMODE
):
218 description
+= ", 32bitmode"
219 if (flags
& E_FLAGS_MASKS
.EFM_MIPS_ABI_O32
):
220 description
+= ", o32"
221 elif (flags
& E_FLAGS_MASKS
.EFM_MIPS_ABI_O64
):
222 description
+= ", o64"
223 elif (flags
& E_FLAGS_MASKS
.EFM_MIPS_ABI_EABI32
):
224 description
+= ", eabi32"
225 elif (flags
& E_FLAGS_MASKS
.EFM_MIPS_ABI_EABI64
):
226 description
+= ", eabi64"
227 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_1
:
228 description
+= ", mips1"
229 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_2
:
230 description
+= ", mips2"
231 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_3
:
232 description
+= ", mips3"
233 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_4
:
234 description
+= ", mips4"
235 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_5
:
236 description
+= ", mips5"
237 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_32R2
:
238 description
+= ", mips32r2"
239 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_64R2
:
240 description
+= ", mips64r2"
241 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_32
:
242 description
+= ", mips32"
243 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_64
:
244 description
+= ", mips64"
246 elif self
.elffile
['e_machine'] == "EM_RISCV":
247 if flags
& E_FLAGS
.EF_RISCV_RVC
:
248 description
+= ", RVC"
249 if (flags
& E_FLAGS
.EF_RISCV_RVE
):
250 description
+= ", RVE"
251 if (flags
& E_FLAGS
.EF_RISCV_TSO
):
252 description
+= ", TSO"
253 if (flags
& E_FLAGS
.EF_RISCV_FLOAT_ABI
) == E_FLAGS
.EF_RISCV_FLOAT_ABI_SOFT
:
254 description
+= ", soft-float ABI"
255 if (flags
& E_FLAGS
.EF_RISCV_FLOAT_ABI
) == E_FLAGS
.EF_RISCV_FLOAT_ABI_SINGLE
:
256 description
+= ", single-float ABI"
257 if (flags
& E_FLAGS
.EF_RISCV_FLOAT_ABI
) == E_FLAGS
.EF_RISCV_FLOAT_ABI_DOUBLE
:
258 description
+= ", double-float ABI"
259 if (flags
& E_FLAGS
.EF_RISCV_FLOAT_ABI
) == E_FLAGS
.EF_RISCV_FLOAT_ABI_QUAD
:
260 description
+= ", quad-float ABI"
262 elif self
.elffile
['e_machine'] == "EM_LOONGARCH":
263 if (flags
& E_FLAGS
.EF_LOONGARCH_FLOAT_ABI
) == E_FLAGS
.EF_LOONGARCH_FLOAT_ABI_SOFT
:
264 description
+= ", SOFT-FLOAT"
265 if (flags
& E_FLAGS
.EF_LOONGARCH_FLOAT_ABI
) == E_FLAGS
.EF_LOONGARCH_FLOAT_ABI_SINGLE
:
266 description
+= ", SINGLE-FLOAT"
267 if (flags
& E_FLAGS
.EF_LOONGARCH_FLOAT_ABI
) == E_FLAGS
.EF_LOONGARCH_FLOAT_ABI_DOUBLE
:
268 description
+= ", DOUBLE-FLOAT"
269 if (flags
& E_FLAGS
.EF_LOONGARCH_ABI
) == E_FLAGS
.EF_LOONGARCH_ABI_V0
:
270 description
+= ", OBJ-v0"
271 if (flags
& E_FLAGS
.EF_LOONGARCH_ABI
) == E_FLAGS
.EF_LOONGARCH_ABI_V1
:
272 description
+= ", OBJ-v1"
276 def display_program_headers(self
, show_heading
=True):
277 """ Display the ELF program headers.
278 If show_heading is True, displays the heading for this information
279 (Elf file type is...)
282 if self
.elffile
.num_segments() == 0:
283 self
._emitline
('There are no program headers in this file.')
286 elfheader
= self
.elffile
.header
288 self
._emitline
('Elf file type is %s' %
289 describe_e_type(elfheader
['e_type'], self
.elffile
))
290 self
._emitline
('Entry point is %s' %
291 self
._format
_hex
(elfheader
['e_entry']))
292 # readelf weirness - why isn't e_phoff printed as hex? (for section
294 self
._emitline
('There are %s program headers, starting at offset %s' % (
295 self
.elffile
.num_segments(), elfheader
['e_phoff']))
298 self
._emitline
('Program Headers:')
300 # Now comes the table of program headers with their attributes. Note
301 # that due to different formatting constraints of 32-bit and 64-bit
302 # addresses, there are some conditions on elfclass here.
304 # First comes the table heading
306 if self
.elffile
.elfclass
== 32:
307 self
._emitline
(' Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align')
309 self
._emitline
(' Type Offset VirtAddr PhysAddr')
310 self
._emitline
(' FileSiz MemSiz Flags Align')
314 for segment
in self
.elffile
.iter_segments():
315 self
._emit
(' %-14s ' % describe_p_type(segment
['p_type']))
317 if self
.elffile
.elfclass
== 32:
318 self
._emitline
('%s %s %s %s %s %-3s %s' % (
319 self
._format
_hex
(segment
['p_offset'], fieldsize
=6),
320 self
._format
_hex
(segment
['p_vaddr'], fullhex
=True),
321 self
._format
_hex
(segment
['p_paddr'], fullhex
=True),
322 self
._format
_hex
(segment
['p_filesz'], fieldsize
=5),
323 self
._format
_hex
(segment
['p_memsz'], fieldsize
=5),
324 describe_p_flags(segment
['p_flags']),
325 self
._format
_hex
(segment
['p_align'])))
327 self
._emitline
('%s %s %s' % (
328 self
._format
_hex
(segment
['p_offset'], fullhex
=True),
329 self
._format
_hex
(segment
['p_vaddr'], fullhex
=True),
330 self
._format
_hex
(segment
['p_paddr'], fullhex
=True)))
331 self
._emitline
(' %s %s %-3s %s' % (
332 self
._format
_hex
(segment
['p_filesz'], fullhex
=True),
333 self
._format
_hex
(segment
['p_memsz'], fullhex
=True),
334 describe_p_flags(segment
['p_flags']),
335 # lead0x set to False for p_align, to mimic readelf.
336 # No idea why the difference from 32-bit mode :-|
337 self
._format
_hex
(segment
['p_align'], lead0x
=False)))
339 if isinstance(segment
, InterpSegment
):
340 self
._emitline
(' [Requesting program interpreter: %s]' %
341 segment
.get_interp_name())
343 # Sections to segments mapping
345 if self
.elffile
.num_sections() == 0:
346 # No sections? We're done
349 self
._emitline
('\n Section to Segment mapping:')
350 self
._emitline
(' Segment Sections...')
352 for nseg
, segment
in enumerate(self
.elffile
.iter_segments()):
353 self
._emit
(' %2.2d ' % nseg
)
355 for section
in self
.elffile
.iter_sections():
356 if ( not section
.is_null() and
357 not ((section
['sh_flags'] & SH_FLAGS
.SHF_TLS
) != 0 and
358 section
['sh_type'] == 'SHT_NOBITS' and
359 segment
['p_type'] != 'PT_TLS') and
360 segment
.section_in_segment(section
)):
361 self
._emit
('%s ' % section
.name
)
365 def display_section_headers(self
, show_heading
=True):
366 """ Display the ELF section headers
368 elfheader
= self
.elffile
.header
370 self
._emitline
('There are %s section headers, starting at offset %s' % (
371 elfheader
['e_shnum'], self
._format
_hex
(elfheader
['e_shoff'])))
373 if self
.elffile
.num_sections() == 0:
374 self
._emitline
('There are no sections in this file.')
377 self
._emitline
('\nSection Header%s:' % (
378 's' if self
.elffile
.num_sections() > 1 else ''))
380 # Different formatting constraints of 32-bit and 64-bit addresses
382 if self
.elffile
.elfclass
== 32:
383 self
._emitline
(' [Nr] Name Type Addr Off Size ES Flg Lk Inf Al')
385 self
._emitline
(' [Nr] Name Type Address Offset')
386 self
._emitline
(' Size EntSize Flags Link Info Align')
390 for nsec
, section
in enumerate(self
.elffile
.iter_sections()):
391 self
._emit
(' [%2u] %-17.17s %-15.15s ' % (
392 nsec
, section
.name
, describe_sh_type(section
['sh_type'])))
394 if self
.elffile
.elfclass
== 32:
395 self
._emitline
('%s %s %s %s %3s %2s %3s %2s' % (
396 self
._format
_hex
(section
['sh_addr'], fieldsize
=8, lead0x
=False),
397 self
._format
_hex
(section
['sh_offset'], fieldsize
=6, lead0x
=False),
398 self
._format
_hex
(section
['sh_size'], fieldsize
=6, lead0x
=False),
399 self
._format
_hex
(section
['sh_entsize'], fieldsize
=2, lead0x
=False),
400 describe_sh_flags(section
['sh_flags']),
401 section
['sh_link'], section
['sh_info'],
402 section
['sh_addralign']))
404 self
._emitline
(' %s %s' % (
405 self
._format
_hex
(section
['sh_addr'], fullhex
=True, lead0x
=False),
406 self
._format
_hex
(section
['sh_offset'],
407 fieldsize
=16 if section
['sh_offset'] > 0xffffffff else 8,
409 self
._emitline
(' %s %s %3s %2s %3s %s' % (
410 self
._format
_hex
(section
['sh_size'], fullhex
=True, lead0x
=False),
411 self
._format
_hex
(section
['sh_entsize'], fullhex
=True, lead0x
=False),
412 describe_sh_flags(section
['sh_flags']),
413 section
['sh_link'], section
['sh_info'],
414 section
['sh_addralign']))
416 self
._emitline
('Key to Flags:')
417 self
._emitline
(' W (write), A (alloc), X (execute), M (merge),'
418 ' S (strings), I (info),')
419 self
._emitline
(' L (link order), O (extra OS processing required),'
420 ' G (group), T (TLS),')
421 self
._emitline
(' C (compressed), x (unknown), o (OS specific),'
424 if self
.elffile
['e_machine'] == 'EM_ARM':
425 self
._emit
('y (purecode), ')
426 self
._emitline
('p (processor specific)')
428 def display_symbol_tables(self
):
429 """ Display the symbol tables contained in the file
431 self
._init
_versioninfo
()
433 symbol_tables
= [(idx
, s
) for idx
, s
in enumerate(self
.elffile
.iter_sections())
434 if isinstance(s
, SymbolTableSection
)]
436 if not symbol_tables
and self
.elffile
.num_sections() == 0:
438 self
._emitline
('Dynamic symbol information is not available for'
439 ' displaying symbols.')
441 for section_index
, section
in symbol_tables
:
442 if not isinstance(section
, SymbolTableSection
):
445 if section
['sh_entsize'] == 0:
446 self
._emitline
("\nSymbol table '%s' has a sh_entsize of zero!" % (
450 self
._emitline
("\nSymbol table '%s' contains %d %s:" % (
452 section
.num_symbols(),
453 'entry' if section
.num_symbols() == 1 else 'entries'))
455 if self
.elffile
.elfclass
== 32:
456 self
._emitline
(' Num: Value Size Type Bind Vis Ndx Name')
458 self
._emitline
(' Num: Value Size Type Bind Vis Ndx Name')
460 for nsym
, symbol
in enumerate(section
.iter_symbols()):
462 # readelf doesn't display version info for Solaris versioning
463 if (section
['sh_type'] == 'SHT_DYNSYM' and
464 self
._versioninfo
['type'] == 'GNU'):
465 version
= self
._symbol
_version
(nsym
)
466 if (version
['name'] != symbol
.name
and
467 version
['index'] not in ('VER_NDX_LOCAL',
469 if version
['filename']:
471 version_info
= '@%(name)s (%(index)i)' % version
474 if version
['hidden']:
475 version_info
= '@%(name)s' % version
477 version_info
= '@@%(name)s' % version
479 symbol_name
= symbol
.name
480 # Print section names for STT_SECTION symbols as readelf does
481 if (symbol
['st_info']['type'] == 'STT_SECTION'
482 and symbol
['st_shndx'] < self
.elffile
.num_sections()
483 and symbol
['st_name'] == 0):
484 symbol_name
= self
.elffile
.get_section(symbol
['st_shndx']).name
486 # symbol names are truncated to 25 chars, similarly to readelf
487 self
._emitline
('%6d: %s %s %-7s %-6s %-7s %4s %.25s%s' % (
490 symbol
['st_value'], fullhex
=True, lead0x
=False),
491 "%5d" % symbol
['st_size'] if symbol
['st_size'] < 100000 else hex(symbol
['st_size']),
492 describe_symbol_type(symbol
['st_info']['type']),
493 describe_symbol_bind(symbol
['st_info']['bind']),
494 describe_symbol_other(symbol
['st_other']),
495 describe_symbol_shndx(self
._get
_symbol
_shndx
(symbol
,
501 def display_dynamic_tags(self
):
502 """ Display the dynamic tags contained in the file
504 has_dynamic_sections
= False
505 for section
in self
.elffile
.iter_sections():
506 if not isinstance(section
, DynamicSection
):
509 has_dynamic_sections
= True
510 self
._emitline
("\nDynamic section at offset %s contains %d %s:" % (
511 self
._format
_hex
(section
['sh_offset']),
513 'entry' if section
.num_tags() == 1 else 'entries'))
514 self
._emitline
(" Tag Type Name/Value")
516 padding
= 20 + (8 if self
.elffile
.elfclass
== 32 else 0)
517 for tag
in section
.iter_tags():
518 if tag
.entry
.d_tag
== 'DT_NEEDED':
519 parsed
= 'Shared library: [%s]' % tag
.needed
520 elif tag
.entry
.d_tag
== 'DT_RPATH':
521 parsed
= 'Library rpath: [%s]' % tag
.rpath
522 elif tag
.entry
.d_tag
== 'DT_RUNPATH':
523 parsed
= 'Library runpath: [%s]' % tag
.runpath
524 elif tag
.entry
.d_tag
== 'DT_SONAME':
525 parsed
= 'Library soname: [%s]' % tag
.soname
526 elif tag
.entry
.d_tag
.endswith(('SZ', 'ENT')):
527 parsed
= '%i (bytes)' % tag
['d_val']
528 elif tag
.entry
.d_tag
== 'DT_FLAGS':
529 parsed
= describe_dt_flags(tag
.entry
.d_val
)
530 elif tag
.entry
.d_tag
== 'DT_FLAGS_1':
531 parsed
= 'Flags: %s' % describe_dt_flags_1(tag
.entry
.d_val
)
532 elif tag
.entry
.d_tag
.endswith(('NUM', 'COUNT')):
533 parsed
= '%i' % tag
['d_val']
534 elif tag
.entry
.d_tag
== 'DT_PLTREL':
535 s
= describe_dyn_tag(tag
.entry
.d_val
)
536 if s
.startswith('DT_'):
539 elif tag
.entry
.d_tag
== 'DT_MIPS_FLAGS':
540 parsed
= describe_rh_flags(tag
.entry
.d_val
)
541 elif tag
.entry
.d_tag
in ('DT_MIPS_SYMTABNO',
542 'DT_MIPS_LOCAL_GOTNO'):
543 parsed
= str(tag
.entry
.d_val
)
545 parsed
= '%#x' % tag
['d_val']
547 self
._emitline
(" %s %-*s %s" % (
548 self
._format
_hex
(ENUM_D_TAG
.get(tag
.entry
.d_tag
, tag
.entry
.d_tag
),
549 fullhex
=True, lead0x
=True),
551 '(%s)' % (tag
.entry
.d_tag
[3:],),
553 if not has_dynamic_sections
:
554 self
._emitline
("\nThere is no dynamic section in this file.")
556 def display_notes(self
):
557 """ Display the notes contained in the file
559 for section
in self
.elffile
.iter_sections():
560 if isinstance(section
, NoteSection
):
561 for note
in section
.iter_notes():
562 self
._emitline
("\nDisplaying notes found in: {}".format(
564 self
._emitline
(' Owner Data size Description')
565 self
._emitline
(' %s %s\t%s' % (
566 note
['n_name'].ljust(20),
567 self
._format
_hex
(note
['n_descsz'], fieldsize
=8),
568 describe_note(note
)))
570 def display_relocations(self
):
571 """ Display the relocations contained in the file
573 has_relocation_sections
= False
574 for section
in self
.elffile
.iter_sections():
575 if not isinstance(section
, RelocationSection
):
578 has_relocation_sections
= True
579 self
._emitline
("\nRelocation section '%.128s' at offset %s contains %d %s:" % (
581 self
._format
_hex
(section
['sh_offset']),
582 section
.num_relocations(),
583 'entry' if section
.num_relocations() == 1 else 'entries'))
584 if section
.is_RELA():
585 self
._emitline
(" Offset Info Type Sym. Value Sym. Name + Addend")
587 self
._emitline
(" Offset Info Type Sym.Value Sym. Name")
589 # The symbol table section pointed to in sh_link
590 symtable
= self
.elffile
.get_section(section
['sh_link'])
592 for rel
in section
.iter_relocations():
593 hexwidth
= 8 if self
.elffile
.elfclass
== 32 else 12
594 self
._emit
('%s %s %-17.17s' % (
595 self
._format
_hex
(rel
['r_offset'],
596 fieldsize
=hexwidth
, lead0x
=False),
597 self
._format
_hex
(rel
['r_info'],
598 fieldsize
=hexwidth
, lead0x
=False),
600 rel
['r_info_type'], self
.elffile
)))
602 if rel
['r_info_sym'] == 0:
603 if section
.is_RELA():
604 fieldsize
= 8 if self
.elffile
.elfclass
== 32 else 16
605 addend
= self
._format
_hex
(rel
['r_addend'], lead0x
=False)
606 self
._emit
(' %s %s' % (' ' * fieldsize
, addend
))
610 symbol
= symtable
.get_symbol(rel
['r_info_sym'])
611 # Some symbols have zero 'st_name', so instead what's used
612 # is the name of the section they point at. Truncate symbol
613 # names (excluding version info) to 22 chars, similarly to
615 if symbol
['st_name'] == 0:
616 symsecidx
= self
._get
_symbol
_shndx
(symbol
,
619 symsec
= self
.elffile
.get_section(symsecidx
)
620 symbol_name
= symsec
.name
623 symbol_name
= symbol
.name
624 version
= self
._symbol
_version
(rel
['r_info_sym'])
625 version
= (version
['name']
626 if version
and version
['name'] else '')
627 symbol_name
= '%.22s' % symbol_name
629 symbol_name
+= '@' + version
631 self
._emit
(' %s %s' % (
634 fullhex
=True, lead0x
=False),
636 if section
.is_RELA():
637 self
._emit
(' %s %x' % (
638 '+' if rel
['r_addend'] >= 0 else '-',
639 abs(rel
['r_addend'])))
642 # Emit the two additional relocation types for ELF64 MIPS
644 if (self
.elffile
.elfclass
== 64 and
645 self
.elffile
['e_machine'] == 'EM_MIPS'):
647 rtype
= rel
['r_info_type%s' % i
]
648 self
._emit
(' Type%s: %s' % (
650 describe_reloc_type(rtype
, self
.elffile
)))
653 if not has_relocation_sections
:
654 self
._emitline
('\nThere are no relocations in this file.')
656 def display_arm_unwind(self
):
657 if not self
.elffile
.has_ehabi_info():
658 self
._emitline
('There are no .ARM.idx sections in this file.')
660 for ehabi_info
in self
.elffile
.get_ehabi_infos():
661 # Unwind section '.ARM.exidx' at offset 0x203e8 contains 1009 entries:
662 self
._emitline
("\nUnwind section '%s' at offset 0x%x contains %d %s" % (
663 ehabi_info
.section_name(),
664 ehabi_info
.section_offset(),
665 ehabi_info
.num_entry(),
666 'entry' if ehabi_info
.num_entry() == 1 else 'entries'))
668 for i
in range(ehabi_info
.num_entry()):
669 entry
= ehabi_info
.get_entry(i
)
671 self
._emitline
("Entry %d:" % i
)
672 if isinstance(entry
, CorruptEHABIEntry
):
673 self
._emitline
(" [corrupt] %s" % entry
.reason
)
675 self
._emit
(" Function offset 0x%x: " % entry
.function_offset
)
676 if isinstance(entry
, CannotUnwindEHABIEntry
):
677 self
._emitline
("[cantunwind]")
679 elif entry
.eh_table_offset
:
680 self
._emitline
("@0x%x" % entry
.eh_table_offset
)
682 self
._emitline
("Compact (inline)")
683 if isinstance(entry
, GenericEHABIEntry
):
684 self
._emitline
(" Personality: 0x%x" % entry
.personality
)
686 self
._emitline
(" Compact model index: %d" % entry
.personality
)
687 for mnemonic_item
in entry
.mnmemonic_array():
689 self
._emitline
(mnemonic_item
)
691 def display_version_info(self
):
692 """ Display the version info contained in the file
694 self
._init
_versioninfo
()
696 if not self
._versioninfo
['type']:
697 self
._emitline
("\nNo version information found in this file.")
700 for section
in self
.elffile
.iter_sections():
701 if isinstance(section
, GNUVerSymSection
):
702 self
._print
_version
_section
_header
(section
, 'Version symbols')
703 num_symbols
= section
.num_symbols()
705 # Symbol version info are printed four by four entries
706 for idx_by_4
in range(0, num_symbols
, 4):
708 self
._emit
(' %03x:' % idx_by_4
)
710 for idx
in range(idx_by_4
, min(idx_by_4
+ 4, num_symbols
)):
712 symbol_version
= self
._symbol
_version
(idx
)
713 if symbol_version
['index'] == 'VER_NDX_LOCAL':
715 version_name
= '(*local*)'
716 elif symbol_version
['index'] == 'VER_NDX_GLOBAL':
718 version_name
= '(*global*)'
720 version_index
= symbol_version
['index']
721 version_name
= '(%(name)s)' % symbol_version
723 visibility
= 'h' if symbol_version
['hidden'] else ' '
725 self
._emit
('%4x%s%-13s' % (
726 version_index
, visibility
, version_name
))
730 elif isinstance(section
, GNUVerDefSection
):
731 self
._print
_version
_section
_header
(
732 section
, 'Version definition', indent
=2)
735 for verdef
, verdaux_iter
in section
.iter_versions():
736 verdaux
= next(verdaux_iter
)
739 if verdef
['vd_flags']:
740 flags
= describe_ver_flags(verdef
['vd_flags'])
741 # Mimic exactly the readelf output
746 self
._emitline
(' %s: Rev: %i Flags: %s Index: %i'
747 ' Cnt: %i Name: %s' % (
748 self
._format
_hex
(offset
, fieldsize
=6,
750 verdef
['vd_version'], flags
, verdef
['vd_ndx'],
751 verdef
['vd_cnt'], name
))
754 offset
+ verdef
['vd_aux'] + verdaux
['vda_next'])
755 for idx
, verdaux
in enumerate(verdaux_iter
, start
=1):
756 self
._emitline
(' %s: Parent %i: %s' %
757 (self
._format
_hex
(verdaux_offset
, fieldsize
=4),
759 verdaux_offset
+= verdaux
['vda_next']
761 offset
+= verdef
['vd_next']
763 elif isinstance(section
, GNUVerNeedSection
):
764 self
._print
_version
_section
_header
(section
, 'Version needs')
767 for verneed
, verneed_iter
in section
.iter_versions():
769 self
._emitline
(' %s: Version: %i File: %s Cnt: %i' % (
770 self
._format
_hex
(offset
, fieldsize
=6,
772 verneed
['vn_version'], verneed
.name
,
775 vernaux_offset
= offset
+ verneed
['vn_aux']
776 for idx
, vernaux
in enumerate(verneed_iter
, start
=1):
777 if vernaux
['vna_flags']:
778 flags
= describe_ver_flags(vernaux
['vna_flags'])
779 # Mimic exactly the readelf output
785 ' %s: Name: %s Flags: %s Version: %i' % (
786 self
._format
_hex
(vernaux_offset
, fieldsize
=4),
788 vernaux
['vna_other']))
790 vernaux_offset
+= vernaux
['vna_next']
792 offset
+= verneed
['vn_next']
794 def display_arch_specific(self
):
795 """ Display the architecture-specific info contained in the file.
797 if self
.elffile
['e_machine'] == 'EM_ARM':
798 self
._display
_arch
_specific
_arm
()
799 elif self
.elffile
['e_machine'] == 'EM_RISCV':
800 self
._display
_arch
_specific
_riscv
()
802 def display_hex_dump(self
, section_spec
):
803 """ Display a hex dump of a section. section_spec is either a section
806 section
= self
._section
_from
_spec
(section_spec
)
808 # readelf prints the warning to stderr. Even though stderrs are not compared
809 # in tests, we comply with that behavior.
810 sys
.stderr
.write('readelf: Warning: Section \'%s\' was not dumped because it does not exist!\n' % (
813 if section
['sh_type'] == 'SHT_NOBITS':
814 self
._emitline
("\nSection '%s' has no data to dump." % (
818 self
._emitline
("\nHex dump of section '%s':" % section
.name
)
819 self
._note
_relocs
_for
_section
(section
)
820 addr
= section
['sh_addr']
821 data
= section
.data()
824 while dataptr
< len(data
):
825 bytesleft
= len(data
) - dataptr
826 # chunks of 16 bytes per line
827 linebytes
= 16 if bytesleft
> 16 else bytesleft
829 self
._emit
(' %s ' % self
._format
_hex
(addr
, fieldsize
=8))
832 self
._emit
('%2.2x' % data
[dataptr
+ i
])
838 for i
in range(linebytes
):
839 c
= data
[dataptr
+ i
: dataptr
+ i
+ 1]
840 if c
[0] >= 32 and c
[0] < 0x7f:
841 self
._emit
(bytes2str(c
))
843 self
._emit
(bytes2str(b
'.'))
851 def display_string_dump(self
, section_spec
):
852 """ Display a strings dump of a section. section_spec is either a
853 section number or a name.
855 section
= self
._section
_from
_spec
(section_spec
)
857 # readelf prints the warning to stderr. Even though stderrs are not compared
858 # in tests, we comply with that behavior.
859 sys
.stderr
.write('readelf.py: Warning: Section \'%s\' was not dumped because it does not exist!\n' % (
862 if section
['sh_type'] == 'SHT_NOBITS':
863 self
._emitline
("\nSection '%s' has no data to dump." % (
867 self
._emitline
("\nString dump of section '%s':" % section
.name
)
870 data
= section
.data()
873 while dataptr
< len(data
):
874 while ( dataptr
< len(data
) and
875 not (32 <= data
[dataptr
] <= 127)):
878 if dataptr
>= len(data
):
882 while endptr
< len(data
) and data
[endptr
] != 0:
886 self
._emitline
(' [%6x] %s' % (
887 dataptr
, bytes2str(data
[dataptr
:endptr
])))
892 self
._emitline
(' No strings found in this section.')
896 def display_debug_dump(self
, dump_what
):
897 """ Dump a DWARF section
899 self
._init
_dwarfinfo
()
900 if self
._dwarfinfo
is None:
903 set_global_machine_arch(self
.elffile
.get_machine_arch())
905 if dump_what
== 'info':
906 self
._dump
_debug
_info
()
907 elif dump_what
== 'decodedline':
908 self
._dump
_debug
_line
_programs
()
909 elif dump_what
== 'frames':
910 self
._dump
_debug
_frames
()
911 elif dump_what
== 'frames-interp':
912 self
._dump
_debug
_frames
_interp
()
913 elif dump_what
== 'aranges':
914 self
._dump
_debug
_aranges
()
915 elif dump_what
in { 'pubtypes', 'pubnames' }:
916 self
._dump
_debug
_namelut
(dump_what
)
917 elif dump_what
== 'loc':
918 self
._dump
_debug
_locations
()
919 elif dump_what
== 'Ranges':
920 self
._dump
_debug
_ranges
()
922 self
._emitline
('debug dump not yet supported for "%s"' % dump_what
)
924 def _format_hex(self
, addr
, fieldsize
=None, fullhex
=False, lead0x
=True,
926 """ Format an address into a hexadecimal string.
929 Size of the hexadecimal field (with leading zeros to fit the
930 address into. For example with fieldsize=8, the format will
932 If None, the minimal required field size will be used.
935 If True, override fieldsize to set it to the maximal size
936 needed for the elfclass
939 If True, leading 0x is added
942 If True, override lead0x to emulate the alternate
943 hexadecimal form specified in format string with the #
944 character: only non-zero values are prefixed with 0x.
945 This form is used by readelf.
952 if fieldsize
is not None:
955 s
= '0x' if lead0x
else ''
957 fieldsize
= 8 if self
.elffile
.elfclass
== 32 else 16
958 if fieldsize
is None:
961 field
= '%' + '0%sx' % fieldsize
962 return s
+ field
% addr
964 def _print_version_section_header(self
, version_section
, name
, lead0x
=True,
966 """ Print a section header of one version related section (versym,
967 verneed or verdef) with some options to accomodate readelf
968 little differences between each header (e.g. indentation
971 if hasattr(version_section
, 'num_versions'):
972 num_entries
= version_section
.num_versions()
974 num_entries
= version_section
.num_symbols()
976 self
._emitline
("\n%s section '%s' contains %d %s:" % (
977 name
, version_section
.name
, num_entries
,
978 'entry' if num_entries
== 1 else 'entries'))
979 self
._emitline
('%sAddr: %s Offset: %s Link: %i (%s)' % (
982 version_section
['sh_addr'], fieldsize
=16, lead0x
=lead0x
),
984 version_section
['sh_offset'], fieldsize
=8, lead0x
=True),
985 version_section
['sh_link'],
986 self
.elffile
.get_section(version_section
['sh_link']).name
990 def _init_versioninfo(self
):
991 """ Search and initialize informations about version related sections
992 and the kind of versioning used (GNU or Solaris).
994 if self
._versioninfo
is not None:
997 self
._versioninfo
= {'versym': None, 'verdef': None,
998 'verneed': None, 'type': None}
1000 for section
in self
.elffile
.iter_sections():
1001 if isinstance(section
, GNUVerSymSection
):
1002 self
._versioninfo
['versym'] = section
1003 elif isinstance(section
, GNUVerDefSection
):
1004 self
._versioninfo
['verdef'] = section
1005 elif isinstance(section
, GNUVerNeedSection
):
1006 self
._versioninfo
['verneed'] = section
1007 elif isinstance(section
, DynamicSection
):
1008 for tag
in section
.iter_tags():
1009 if tag
['d_tag'] == 'DT_VERSYM':
1010 self
._versioninfo
['type'] = 'GNU'
1013 if not self
._versioninfo
['type'] and (
1014 self
._versioninfo
['verneed'] or self
._versioninfo
['verdef']):
1015 self
._versioninfo
['type'] = 'Solaris'
1017 def _symbol_version(self
, nsym
):
1018 """ Return a dict containing information on the
1019 or None if no version information is available
1021 self
._init
_versioninfo
()
1023 symbol_version
= dict.fromkeys(('index', 'name', 'filename', 'hidden'))
1025 if (not self
._versioninfo
['versym'] or
1026 nsym
>= self
._versioninfo
['versym'].num_symbols()):
1029 symbol
= self
._versioninfo
['versym'].get_symbol(nsym
)
1030 index
= symbol
.entry
['ndx']
1031 if not index
in ('VER_NDX_LOCAL', 'VER_NDX_GLOBAL'):
1034 if self
._versioninfo
['type'] == 'GNU':
1035 # In GNU versioning mode, the highest bit is used to
1036 # store whether the symbol is hidden or not
1039 symbol_version
['hidden'] = True
1041 if (self
._versioninfo
['verdef'] and
1042 index
<= self
._versioninfo
['verdef'].num_versions()):
1044 self
._versioninfo
['verdef'].get_version(index
)
1045 symbol_version
['name'] = next(verdaux_iter
).name
1047 verneed
, vernaux
= \
1048 self
._versioninfo
['verneed'].get_version(index
)
1049 symbol_version
['name'] = vernaux
.name
1050 symbol_version
['filename'] = verneed
.name
1052 symbol_version
['index'] = index
1053 return symbol_version
1055 def _section_from_spec(self
, spec
):
1056 """ Retrieve a section given a "spec" (either number or name).
1057 Return None if no such section exists in the file.
1061 if num
< self
.elffile
.num_sections():
1062 return self
.elffile
.get_section(num
)
1066 # Not a number. Must be a name then
1067 return self
.elffile
.get_section_by_name(spec
)
1069 def _get_symbol_shndx(self
, symbol
, symbol_index
, symtab_index
):
1070 """ Get the index into the section header table for the "symbol"
1071 at "symbol_index" located in the symbol table with section index
1074 symbol_shndx
= symbol
['st_shndx']
1075 if symbol_shndx
!= SHN_INDICES
.SHN_XINDEX
:
1078 # Check for or lazily construct index section mapping (symbol table
1079 # index -> corresponding symbol table index section object)
1080 if self
._shndx
_sections
is None:
1081 self
._shndx
_sections
= {sec
.symboltable
: sec
for sec
in self
.elffile
.iter_sections()
1082 if isinstance(sec
, SymbolTableIndexSection
)}
1083 return self
._shndx
_sections
[symtab_index
].get_section_index(symbol_index
)
1085 def _note_relocs_for_section(self
, section
):
1086 """ If there are relocation sections pointing to the givne section,
1087 emit a note about it.
1089 for relsec
in self
.elffile
.iter_sections():
1090 if isinstance(relsec
, RelocationSection
):
1091 info_idx
= relsec
['sh_info']
1092 if self
.elffile
.get_section(info_idx
) == section
:
1093 self
._emitline
(' Note: This section has relocations against it, but these have NOT been applied to this dump.')
1096 def _init_dwarfinfo(self
):
1097 """ Initialize the DWARF info contained in the file and assign it to
1099 Leave self._dwarfinfo at None if no DWARF info was found in the file
1101 if self
._dwarfinfo
is not None:
1104 if self
.elffile
.has_dwarf_info():
1105 self
._dwarfinfo
= self
.elffile
.get_dwarf_info()
1107 self
._dwarfinfo
= None
1109 def _dump_debug_info(self
):
1110 """ Dump the debugging info section.
1112 if not self
._dwarfinfo
.has_debug_info
:
1114 self
._emitline
('Contents of the %s section:\n' % self
._dwarfinfo
.debug_info_sec
.name
)
1116 # Offset of the .debug_info section in the stream
1117 section_offset
= self
._dwarfinfo
.debug_info_sec
.global_offset
1119 for cu
in self
._dwarfinfo
.iter_CUs():
1120 self
._emitline
(' Compilation Unit @ offset %s:' %
1121 self
._format
_hex
(cu
.cu_offset
, alternate
=True))
1122 self
._emitline
(' Length: %s (%s)' % (
1123 self
._format
_hex
(cu
['unit_length']),
1124 '%s-bit' % cu
.dwarf_format()))
1125 self
._emitline
(' Version: %s' % cu
['version'])
1126 if cu
['version'] >= 5:
1127 if cu
.header
.get("unit_type", ''):
1128 unit_type
= cu
.header
.unit_type
1129 self
._emitline
(' Unit Type: %s (%d)' % (
1130 unit_type
, ENUM_DW_UT
.get(cu
.header
.unit_type
, 0)))
1131 self
._emitline
(' Abbrev Offset: %s' % (
1132 self
._format
_hex
(cu
['debug_abbrev_offset'], alternate
=True)))
1133 self
._emitline
(' Pointer Size: %s' % cu
['address_size'])
1134 if unit_type
in ('DW_UT_skeleton', 'DW_UT_split_compile'):
1135 self
._emitline
(' Dwo id: %s' % cu
['dwo_id'])
1136 elif unit_type
in ('DW_UT_type', 'DW_UT_split_type'):
1137 self
._emitline
(' Signature: 0x%x' % cu
['type_signature'])
1138 self
._emitline
(' Type Offset: 0x%x' % cu
['type_offset'])
1140 self
._emitline
(' Abbrev Offset: %s' % (
1141 self
._format
_hex
(cu
['debug_abbrev_offset'], alternate
=True))),
1142 self
._emitline
(' Pointer Size: %s' % cu
['address_size'])
1144 # The nesting depth of each DIE within the tree of DIEs must be
1145 # displayed. To implement this, a counter is incremented each time
1146 # the current DIE has children, and decremented when a null die is
1147 # encountered. Due to the way the DIE tree is serialized, this will
1148 # correctly reflect the nesting depth
1151 current_function
= None
1152 for die
in cu
.iter_DIEs():
1153 if die
.tag
== 'DW_TAG_subprogram':
1154 current_function
= die
1155 self
._emitline
(' <%s><%x>: Abbrev Number: %s%s' % (
1159 (' (%s)' % die
.tag
) if not die
.is_null() else ''))
1164 for attr
in die
.attributes
.values():
1166 # Unknown attribute values are passed-through as integers
1167 if isinstance(name
, int):
1168 name
= 'Unknown AT value: %x' % name
1170 attr_desc
= describe_attr_value(attr
, die
, section_offset
)
1172 if 'DW_OP_fbreg' in attr_desc
and current_function
and not 'DW_AT_frame_base' in current_function
.attributes
:
1173 postfix
= ' [without dw_at_frame_base]'
1177 self
._emitline
(' <%x> %-18s: %s%s' % (
1183 if die
.has_children
:
1188 def _dump_debug_line_programs(self
):
1189 """ Dump the (decoded) line programs from .debug_line
1190 The programs are dumped in the order of the CUs they belong to.
1192 if not self
._dwarfinfo
.has_debug_info
:
1194 self
._emitline
('Contents of the %s section:' % self
._dwarfinfo
.debug_line_sec
.name
)
1196 lineprogram_list
= []
1198 for cu
in self
._dwarfinfo
.iter_CUs():
1199 # Avoid dumping same lineprogram multiple times
1200 lineprogram
= self
._dwarfinfo
.line_program_for_CU(cu
)
1202 if lineprogram
in lineprogram_list
:
1205 lineprogram_list
.append(lineprogram
)
1206 ver5
= lineprogram
.header
.version
>= 5
1208 cu_filename
= bytes2str(lineprogram
['file_entry'][0].name
)
1209 if len(lineprogram
['include_directory']) > 0:
1210 # GNU readelf 2.38 only outputs directory in wide mode
1211 self
._emitline
('%s:' % cu_filename
)
1213 self
._emitline
('CU: %s:' % cu_filename
)
1215 self
._emitline
('File name Line number Starting address Stmt')
1216 # GNU readelf has a View column that we don't try to replicate
1217 # The autotest has logic in place to ignore that
1219 # Print each state's file, line and address information. For some
1220 # instructions other output is needed to be compatible with
1222 for entry
in lineprogram
.get_entries():
1225 # Special handling for commands that don't set a new state
1226 if entry
.command
== DW_LNS_set_file
:
1227 file_entry
= lineprogram
['file_entry'][entry
.args
[0] - 1]
1228 if file_entry
.dir_index
== 0:
1230 self
._emitline
('\n./%s:[++]' % (
1231 bytes2str(file_entry
.name
)))
1233 self
._emitline
('\n%s/%s:' % (
1234 bytes2str(lineprogram
['include_directory'][file_entry
.dir_index
- 1]),
1235 bytes2str(file_entry
.name
)))
1236 elif entry
.command
== DW_LNE_define_file
:
1237 self
._emitline
('%s:' % (
1238 bytes2str(lineprogram
['include_directory'][entry
.args
[0].dir_index
])))
1239 elif lineprogram
['version'] < 4 or self
.elffile
['e_machine'] == 'EM_PPC64':
1240 self
._emitline
('%-35s %11s %18s %s' % (
1241 bytes2str(lineprogram
['file_entry'][state
.file - 1].name
),
1242 state
.line
if not state
.end_sequence
else '-',
1243 '0' if state
.address
== 0 else self
._format
_hex
(state
.address
),
1244 'x' if state
.is_stmt
and not state
.end_sequence
else ''))
1246 # In readelf, on non-VLIW machines there is no op_index postfix after address.
1247 # It used to be unconditional.
1248 self
._emitline
('%-35s %s %18s%s %s' % (
1249 bytes2str(lineprogram
['file_entry'][state
.file - 1].name
),
1250 "%11d" % (state
.line
,) if not state
.end_sequence
else '-',
1251 '0' if state
.address
== 0 else self
._format
_hex
(state
.address
),
1252 '' if lineprogram
.header
.maximum_operations_per_instruction
== 1 else '[%d]' % (state
.op_index
,),
1253 'x' if state
.is_stmt
and not state
.end_sequence
else ''))
1254 if entry
.command
== DW_LNS_copy
:
1255 # Another readelf oddity...
1258 def _dump_frames_info(self
, section
, cfi_entries
):
1259 """ Dump the raw call frame info in a section.
1261 `section` is the Section instance that contains the call frame info
1262 while `cfi_entries` must be an iterable that yields the sequence of
1263 CIE or FDE instances.
1265 self
._emitline
('Contents of the %s section:' % section
.name
)
1267 for entry
in cfi_entries
:
1268 if isinstance(entry
, CIE
):
1269 self
._emitline
('\n%08x %s %s CIE' % (
1271 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1272 self
._format
_hex
(entry
['CIE_id'], fieldsize
=8, lead0x
=False)))
1273 self
._emitline
(' Version: %d' % entry
['version'])
1274 self
._emitline
(' Augmentation: "%s"' % bytes2str(entry
['augmentation']))
1275 self
._emitline
(' Code alignment factor: %u' % entry
['code_alignment_factor'])
1276 self
._emitline
(' Data alignment factor: %d' % entry
['data_alignment_factor'])
1277 self
._emitline
(' Return address column: %d' % entry
['return_address_register'])
1278 if entry
.augmentation_bytes
:
1279 self
._emitline
(' Augmentation data: {}'.format(' '.join(
1280 '{:02x}'.format(ord(b
))
1281 for b
in iterbytes(entry
.augmentation_bytes
)
1285 elif isinstance(entry
, FDE
):
1286 self
._emitline
('\n%08x %s %s FDE cie=%08x pc=%s..%s' % (
1288 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1289 self
._format
_hex
(entry
['CIE_pointer'], fieldsize
=8, lead0x
=False),
1291 self
._format
_hex
(entry
['initial_location'], fullhex
=True, lead0x
=False),
1293 entry
['initial_location'] + entry
['address_range'],
1294 fullhex
=True, lead0x
=False)))
1295 if entry
.augmentation_bytes
:
1296 self
._emitline
(' Augmentation data: {}'.format(' '.join(
1297 '{:02x}'.format(ord(b
))
1298 for b
in iterbytes(entry
.augmentation_bytes
)
1301 else: # ZERO terminator
1302 assert isinstance(entry
, ZERO
)
1303 self
._emitline
('\n%08x ZERO terminator' % entry
.offset
)
1306 self
._emit
(describe_CFI_instructions(entry
))
1309 def _dump_debug_frames(self
):
1310 """ Dump the raw frame info from .debug_frame and .eh_frame sections.
1312 if self
._dwarfinfo
.has_EH_CFI():
1313 self
._dump
_frames
_info
(
1314 self
._dwarfinfo
.eh_frame_sec
,
1315 self
._dwarfinfo
.EH_CFI_entries())
1318 if self
._dwarfinfo
.has_CFI():
1319 self
._dump
_frames
_info
(
1320 self
._dwarfinfo
.debug_frame_sec
,
1321 self
._dwarfinfo
.CFI_entries())
1323 def _dump_debug_namelut(self
, what
):
1325 Dump the debug pubnames section.
1327 if what
== 'pubnames':
1328 namelut
= self
._dwarfinfo
.get_pubnames()
1329 section
= self
._dwarfinfo
.debug_pubnames_sec
1331 namelut
= self
._dwarfinfo
.get_pubtypes()
1332 section
= self
._dwarfinfo
.debug_pubtypes_sec
1334 # readelf prints nothing if the section is not present.
1335 if namelut
is None or len(namelut
) == 0:
1338 self
._emitline
('Contents of the %s section:' % section
.name
)
1341 cu_headers
= namelut
.get_cu_headers()
1343 # go over CU-by-CU first and item-by-item next.
1344 for (cu_hdr
, (cu_ofs
, items
)) in izip(cu_headers
, itertools
.groupby(
1345 namelut
.items(), key
= lambda x
: x
[1].cu_ofs
)):
1347 self
._emitline
(' Length: %d' % cu_hdr
.unit_length
)
1348 self
._emitline
(' Version: %d' % cu_hdr
.version
)
1349 self
._emitline
(' Offset into .debug_info section: 0x%x' % cu_hdr
.debug_info_offset
)
1350 self
._emitline
(' Size of area in .debug_info section: %d' % cu_hdr
.debug_info_length
)
1352 self
._emitline
(' Offset Name')
1354 self
._emitline
(' %x %s' % (item
[1].die_ofs
- cu_ofs
, item
[0]))
1357 def _dump_debug_aranges(self
):
1358 """ Dump the aranges table
1360 aranges_table
= self
._dwarfinfo
.get_aranges()
1361 if aranges_table
== None:
1363 # Seems redundant, but we need to get the unsorted set of entries
1364 # to match system readelf.
1365 # Also, sometimes there are blank sections in aranges, but readelf
1366 # dumps them, so we should too.
1367 unordered_entries
= aranges_table
._get
_entries
(need_empty
=True)
1369 if len(unordered_entries
) == 0:
1371 self
._emitline
("Section '.debug_aranges' has no debugging data.")
1374 self
._emitline
('Contents of the %s section:' % self
._dwarfinfo
.debug_aranges_sec
.name
)
1377 for entry
in unordered_entries
:
1378 if prev_offset
!= entry
.info_offset
:
1379 if entry
!= unordered_entries
[0]:
1380 self
._emitline
(' %s %s' % (
1381 self
._format
_hex
(0, fullhex
=True, lead0x
=False),
1382 self
._format
_hex
(0, fullhex
=True, lead0x
=False)))
1383 self
._emitline
(' Length: %d' % (entry
.unit_length
))
1384 self
._emitline
(' Version: %d' % (entry
.version
))
1385 self
._emitline
(' Offset into .debug_info: 0x%x' % (entry
.info_offset
))
1386 self
._emitline
(' Pointer Size: %d' % (entry
.address_size
))
1387 self
._emitline
(' Segment Size: %d' % (entry
.segment_size
))
1389 self
._emitline
(' Address Length')
1390 if entry
.begin_addr
!= 0 or entry
.length
!= 0:
1391 self
._emitline
(' %s %s' % (
1392 self
._format
_hex
(entry
.begin_addr
, fullhex
=True, lead0x
=False),
1393 self
._format
_hex
(entry
.length
, fullhex
=True, lead0x
=False)))
1394 prev_offset
= entry
.info_offset
1395 self
._emitline
(' %s %s' % (
1396 self
._format
_hex
(0, fullhex
=True, lead0x
=False),
1397 self
._format
_hex
(0, fullhex
=True, lead0x
=False)))
1399 def _dump_frames_interp_info(self
, section
, cfi_entries
):
1400 """ Dump interpreted (decoded) frame information in a section.
1402 `section` is the Section instance that contains the call frame info
1403 while `cfi_entries` must be an iterable that yields the sequence of
1404 CIE or FDE instances.
1406 self
._emitline
('Contents of the %s section:' % section
.name
)
1408 for entry
in cfi_entries
:
1409 if isinstance(entry
, CIE
):
1410 self
._emitline
('\n%08x %s %s CIE "%s" cf=%d df=%d ra=%d' % (
1412 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1413 self
._format
_hex
(entry
['CIE_id'], fieldsize
=8, lead0x
=False),
1414 bytes2str(entry
['augmentation']),
1415 entry
['code_alignment_factor'],
1416 entry
['data_alignment_factor'],
1417 entry
['return_address_register']))
1418 ra_regnum
= entry
['return_address_register']
1420 elif isinstance(entry
, FDE
):
1421 self
._emitline
('\n%08x %s %s FDE cie=%08x pc=%s..%s' % (
1423 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1424 self
._format
_hex
(entry
['CIE_pointer'], fieldsize
=8, lead0x
=False),
1426 self
._format
_hex
(entry
['initial_location'], fullhex
=True, lead0x
=False),
1427 self
._format
_hex
(entry
['initial_location'] + entry
['address_range'],
1428 fullhex
=True, lead0x
=False)))
1429 ra_regnum
= entry
.cie
['return_address_register']
1431 # If the FDE brings adds no unwinding information compared to
1432 # its CIE, omit its table.
1433 if (len(entry
.get_decoded().table
) ==
1434 len(entry
.cie
.get_decoded().table
)):
1437 else: # ZERO terminator
1438 assert isinstance(entry
, ZERO
)
1439 self
._emitline
('\n%08x ZERO terminator' % entry
.offset
)
1443 decoded_table
= entry
.get_decoded()
1444 if len(decoded_table
.table
) == 0:
1447 # Print the heading row for the decoded table
1449 self
._emit
(' ' if entry
.structs
.address_size
== 4 else ' ')
1452 # Look at the registers the decoded table describes.
1453 # We build reg_order here to match readelf's order. In particular,
1454 # registers are sorted by their number, and the register matching
1455 # ra_regnum is always listed last with a special heading.
1456 decoded_table
= entry
.get_decoded()
1457 reg_order
= sorted(filter(
1458 lambda r
: r
!= ra_regnum
,
1459 decoded_table
.reg_order
))
1460 if len(decoded_table
.reg_order
):
1462 # Headings for the registers
1463 for regnum
in reg_order
:
1464 self
._emit
('%-6s' % describe_reg_name(regnum
))
1465 self
._emitline
('ra ')
1467 # Now include ra_regnum in reg_order to print its values
1468 # similarly to the other registers.
1469 reg_order
.append(ra_regnum
)
1473 for line
in decoded_table
.table
:
1474 self
._emit
(self
._format
_hex
(
1475 line
['pc'], fullhex
=True, lead0x
=False))
1477 if line
['cfa'] is not None:
1478 s
= describe_CFI_CFA_rule(line
['cfa'])
1481 self
._emit
(' %-9s' % s
)
1483 for regnum
in reg_order
:
1485 s
= describe_CFI_register_rule(line
[regnum
])
1488 self
._emit
('%-6s' % s
)
1492 def _dump_debug_frames_interp(self
):
1493 """ Dump the interpreted (decoded) frame information from .debug_frame
1494 and .eh_frame sections.
1496 if self
._dwarfinfo
.has_EH_CFI():
1497 self
._dump
_frames
_interp
_info
(
1498 self
._dwarfinfo
.eh_frame_sec
,
1499 self
._dwarfinfo
.EH_CFI_entries())
1502 if self
._dwarfinfo
.has_CFI():
1503 self
._dump
_frames
_interp
_info
(
1504 self
._dwarfinfo
.debug_frame_sec
,
1505 self
._dwarfinfo
.CFI_entries())
1507 def _dump_debug_locations(self
):
1508 """ Dump the location lists from .debug_loc/.debug_loclists section
1510 di
= self
._dwarfinfo
1511 loc_lists_sec
= di
.location_lists()
1512 if not loc_lists_sec
: # No locations section - readelf outputs nothing
1515 if isinstance(loc_lists_sec
, LocationListsPair
):
1516 self
._dump
_debug
_locsection
(di
, loc_lists_sec
._loc
)
1517 self
._dump
_debug
_locsection
(di
, loc_lists_sec
._loclists
)
1519 self
._dump
_debug
_locsection
(di
, loc_lists_sec
)
1521 def _dump_debug_locsection(self
, di
, loc_lists_sec
):
1522 """ Dump the location lists from .debug_loc/.debug_loclists section
1524 ver5
= loc_lists_sec
.version
>= 5
1525 section_name
= (di
.debug_loclists_sec
if ver5
else di
.debug_loc_sec
).name
1527 # To dump a location list, one needs to know the CU.
1528 # Scroll through DIEs once, list the known location list offsets.
1529 # Don't need this CU/DIE scan if all entries are absolute or prefixed by base,
1530 # but let's not optimize for that yet.
1531 cu_map
= dict() # Loc list offset => CU
1532 for cu
in di
.iter_CUs():
1533 for die
in cu
.iter_DIEs():
1534 for key
in die
.attributes
:
1535 attr
= die
.attributes
[key
]
1536 if (LocationParser
.attribute_has_location(attr
, cu
['version']) and
1537 LocationParser
._attribute
_has
_loc
_list
(attr
, cu
['version'])):
1538 cu_map
[attr
.value
] = cu
1540 addr_size
= di
.config
.default_address_size
# In bytes, 4 or 8
1541 addr_width
= addr_size
* 2 # In hex digits, 8 or 16
1542 line_template
= " %%08x %%0%dx %%0%dx %%s%%s" % (addr_width
, addr_width
)
1544 loc_lists
= list(loc_lists_sec
.iter_location_lists())
1545 if len(loc_lists
) == 0:
1546 # Present but empty locations section - readelf outputs a message
1547 self
._emitline
("\nSection '%s' has no debugging data." % (section_name
,))
1550 self
._emitline
('Contents of the %s section:\n' % (section_name
,))
1551 self
._emitline
(' Offset Begin End Expression')
1552 for loc_list
in loc_lists
:
1553 self
._dump
_loclist
(loc_list
, line_template
, cu_map
)
1555 def _dump_loclist(self
, loc_list
, line_template
, cu_map
):
1561 for entry
in loc_list
:
1562 if isinstance(entry
, LocationViewPair
):
1563 has_views
= in_views
= True
1564 # The "v" before address is conditional in binutils, haven't figured out how
1565 self
._emitline
(" %08x v%015x v%015x location view pair" % (entry
.entry_offset
, entry
.begin
, entry
.end
))
1571 # Readelf quirk: indexed loclists don't show the real base IP
1575 cu
= cu_map
.get(entry
.entry_offset
, False)
1577 raise ValueError("Location list can't be tracked to a CU")
1579 if isinstance(entry
, LocationEntry
):
1580 if base_ip
is None and not entry
.is_absolute
:
1581 base_ip
= _get_cu_base(cu
)
1583 begin_offset
= (0 if entry
.is_absolute
else base_ip
) + entry
.begin_offset
1584 end_offset
= (0 if entry
.is_absolute
else base_ip
) + entry
.end_offset
1585 expr
= describe_DWARF_expr(entry
.loc_expr
, cu
.structs
, cu
.cu_offset
)
1587 view
= loc_list
[loc_entry_count
]
1588 postfix
= ' (start == end)' if entry
.begin_offset
== entry
.end_offset
and view
.begin
== view
.end
else ''
1589 self
._emitline
(' %08x v%015x v%015x views at %08x for:' %(
1594 self
._emitline
(' %016x %016x %s%s' %(
1599 loc_entry_count
+= 1
1601 postfix
= ' (start == end)' if entry
.begin_offset
== entry
.end_offset
else ''
1602 self
._emitline
(line_template
% (
1608 elif isinstance(entry
, LocBaseAddressEntry
):
1609 base_ip
= entry
.base_address
1610 self
._emitline
(" %08x %016x (base address)" % (entry
.entry_offset
, entry
.base_address
))
1612 # Pyelftools doesn't store the terminating entry,
1613 # but readelf emits its offset, so this should too.
1615 self
._emitline
(" %08x <End of list>" % (last
.entry_offset
+ last
.entry_length
))
1617 def _dump_debug_ranges(self
):
1618 # TODO: GNU readelf format doesn't need entry_length?
1619 di
= self
._dwarfinfo
1620 range_lists_sec
= di
.range_lists()
1621 if not range_lists_sec
: # No ranges section - readelf outputs nothing
1624 if isinstance(range_lists_sec
, RangeListsPair
):
1625 self
._dump
_debug
_rangesection
(di
, range_lists_sec
._ranges
)
1626 self
._dump
_debug
_rangesection
(di
, range_lists_sec
._rnglists
)
1628 self
._dump
_debug
_rangesection
(di
, range_lists_sec
)
1630 def _dump_debug_rangesection(self
, di
, range_lists_sec
):
1631 # Last amended to match readelf 2.41
1632 ver5
= range_lists_sec
.version
>= 5
1633 section_name
= (di
.debug_rnglists_sec
if ver5
else di
.debug_ranges_sec
).name
1634 addr_size
= di
.config
.default_address_size
# In bytes, 4 or 8
1635 addr_width
= addr_size
* 2 # In hex digits, 8 or 16
1636 line_template
= " %%08x %%0%dx %%0%dx %%s" % (addr_width
, addr_width
)
1637 base_template
= " %%08x %%0%dx (base address)" % (addr_width
)
1639 # In order to determine the base address of the range
1640 # We need to know the corresponding CU.
1641 cu_map
= {die
.attributes
['DW_AT_ranges'].value
: cu
# Range list offset => CU
1642 for cu
in di
.iter_CUs()
1643 for die
in cu
.iter_DIEs()
1644 if 'DW_AT_ranges' in die
.attributes
}
1646 if ver5
: # Dump by CUs - unsure at this point what does readelf do, ranges dump is buggy in 2.41
1647 self
._emitline
('Contents of the %s section:\n\n\n' % section_name
)
1648 for cu
in range_lists_sec
.iter_CUs():
1649 self
._emitline
(' Table at Offset: %s:' % self
._format
_hex
(cu
.cu_offset
, alternate
=True))
1650 self
._emitline
(' Length: %s' % self
._format
_hex
(cu
.unit_length
, alternate
=True))
1651 self
._emitline
(' DWARF version: %d' % cu
.version
)
1652 self
._emitline
(' Address size: %d' % cu
.address_size
)
1653 self
._emitline
(' Segment size: %d' % cu
.segment_selector_size
)
1654 self
._emitline
(' Offset entries: %d\n' % cu
.offset_count
)
1655 # Is the offset table dumped too?
1656 for (i
, range_list
) in enumerate(range_lists_sec
.iter_CU_range_lists_ex(cu
)):
1657 list_offset
= range_list
[0].entry_offset
1658 range_list
= list(range_lists_sec
.translate_v5_entry(entry
, cu_map
[list_offset
]) for entry
in range_list
)
1659 self
._emitline
(' Offset: %s, Index: %d' % (self
._format
_hex
(list_offset
, alternate
=True), i
))
1660 self
._emitline
(' Offset Begin End')
1661 self
._dump
_rangelist
(range_list
, cu_map
, ver5
, line_template
, base_template
)
1662 else: # Dump by DIE reference offset
1663 range_lists
= list(range_lists_sec
.iter_range_lists())
1664 if len(range_lists
) == 0:
1665 # Present but empty ranges section - readelf outputs a message
1666 self
._emitline
("\nSection '%s' has no debugging data." % section_name
)
1669 self
._emitline
('Contents of the %s section:\n\n\n' % section_name
)
1670 self
._emitline
(' Offset Begin End')
1672 for range_list
in range_lists
:
1673 if len(range_list
) == 0: # working around a bogus behavior in readelf 2.41
1674 # No entries means no offset. Dirty hack: peek the stream position
1675 range_list_offset
= range_lists_sec
.stream
.tell() - self
._dwarfinfo
.config
.default_address_size
*2
1676 self
._emitline
(' %08x <End of list>' % (range_list_offset
))
1678 self
._dump
_rangelist
(range_list
, cu_map
, ver5
, line_template
, base_template
)
1680 def _dump_rangelist(self
, range_list
, cu_map
, ver5
, line_template
, base_template
):
1681 # Weird discrepancy in binutils: for DWARFv5 it outputs entry offset,
1682 # for DWARF<=4 list offset.
1683 first
= range_list
[0]
1684 base_ip
= _get_cu_base(cu_map
[first
.entry_offset
])
1685 for entry
in range_list
:
1686 if isinstance(entry
, RangeEntry
):
1687 postfix
= ' (start == end)' if entry
.begin_offset
== entry
.end_offset
else ''
1688 self
._emitline
(line_template
% (
1689 entry
.entry_offset
if ver5
else first
.entry_offset
,
1690 (0 if entry
.is_absolute
else base_ip
) + entry
.begin_offset
,
1691 (0 if entry
.is_absolute
else base_ip
) + entry
.end_offset
,
1693 elif isinstance(entry
,RangeBaseAddressEntry
):
1694 base_ip
= entry
.base_address
1695 self
._emitline
(base_template
% (
1696 entry
.entry_offset
if ver5
else first
.entry_offset
,
1697 entry
.base_address
))
1699 raise NotImplementedError("Unknown object in a range list")
1700 last
= range_list
[-1]
1701 self
._emitline
(' %08x <End of list>' % (last
.entry_offset
+ last
.entry_length
if ver5
else first
.entry_offset
))
1703 def _display_attributes(self
, attr_sec
, descriptor
):
1704 """ Display the attributes contained in the section.
1706 for s
in attr_sec
.iter_subsections():
1707 self
._emitline
("Attribute Section: %s" % s
.header
['vendor_name'])
1708 for ss
in s
.iter_subsubsections():
1709 h_val
= "" if ss
.header
.extra
is None else " ".join("%d" % x
for x
in ss
.header
.extra
)
1710 self
._emitline
(descriptor(ss
.header
.tag
, h_val
, None))
1712 for attr
in ss
.iter_attributes():
1714 self
._emitline
(descriptor(attr
.tag
, attr
.value
, attr
.extra
))
1716 def _display_arch_specific_arm(self
):
1717 """ Display the ARM architecture-specific info contained in the file.
1719 attr_sec
= self
.elffile
.get_section_by_name('.ARM.attributes')
1720 self
._display
_attributes
(attr_sec
, describe_attr_tag_arm
)
1722 def _display_arch_specific_riscv(self
):
1723 """ Display the RISC-V architecture-specific info contained in the file.
1725 attr_sec
= self
.elffile
.get_section_by_name('.riscv.attributes')
1726 self
._display
_attributes
(attr_sec
, describe_attr_tag_riscv
)
1728 def _emit(self
, s
=''):
1729 """ Emit an object to output
1731 self
.output
.write(str(s
))
1733 def _emitline(self
, s
=''):
1734 """ Emit an object to output, followed by a newline
1736 self
.output
.write(str(s
).rstrip() + '\n')
1739 SCRIPT_DESCRIPTION
= 'Display information about the contents of ELF format files'
1740 VERSION_STRING
= '%%(prog)s: based on pyelftools %s' % __version__
1743 def main(stream
=None):
1744 # parse the command-line arguments and invoke ReadElf
1745 argparser
= argparse
.ArgumentParser(
1746 usage
='usage: %(prog)s [options] <elf-file>',
1747 description
=SCRIPT_DESCRIPTION
,
1748 add_help
=False, # -h is a real option of readelf
1750 argparser
.add_argument('file',
1751 nargs
='?', default
=None,
1752 help='ELF file to parse')
1753 argparser
.add_argument('-v', '--version',
1754 action
='version', version
=VERSION_STRING
)
1755 argparser
.add_argument('-d', '--dynamic',
1756 action
='store_true', dest
='show_dynamic_tags',
1757 help='Display the dynamic section')
1758 argparser
.add_argument('-H', '--help',
1759 action
='store_true', dest
='help',
1760 help='Display this information')
1761 argparser
.add_argument('-h', '--file-header',
1762 action
='store_true', dest
='show_file_header',
1763 help='Display the ELF file header')
1764 argparser
.add_argument('-l', '--program-headers', '--segments',
1765 action
='store_true', dest
='show_program_header',
1766 help='Display the program headers')
1767 argparser
.add_argument('-S', '--section-headers', '--sections',
1768 action
='store_true', dest
='show_section_header',
1769 help="Display the sections' headers")
1770 argparser
.add_argument('-e', '--headers',
1771 action
='store_true', dest
='show_all_headers',
1772 help='Equivalent to: -h -l -S')
1773 argparser
.add_argument('-s', '--symbols', '--syms',
1774 action
='store_true', dest
='show_symbols',
1775 help='Display the symbol table')
1776 argparser
.add_argument('-n', '--notes',
1777 action
='store_true', dest
='show_notes',
1778 help='Display the core notes (if present)')
1779 argparser
.add_argument('-r', '--relocs',
1780 action
='store_true', dest
='show_relocs',
1781 help='Display the relocations (if present)')
1782 argparser
.add_argument('-au', '--arm-unwind',
1783 action
='store_true', dest
='show_arm_unwind',
1784 help='Display the armeabi unwind information (if present)')
1785 argparser
.add_argument('-x', '--hex-dump',
1786 action
='store', dest
='show_hex_dump', metavar
='<number|name>',
1787 help='Dump the contents of section <number|name> as bytes')
1788 argparser
.add_argument('-p', '--string-dump',
1789 action
='store', dest
='show_string_dump', metavar
='<number|name>',
1790 help='Dump the contents of section <number|name> as strings')
1791 argparser
.add_argument('-V', '--version-info',
1792 action
='store_true', dest
='show_version_info',
1793 help='Display the version sections (if present)')
1794 argparser
.add_argument('-A', '--arch-specific',
1795 action
='store_true', dest
='show_arch_specific',
1796 help='Display the architecture-specific information (if present)')
1797 argparser
.add_argument('--debug-dump',
1798 action
='store', dest
='debug_dump_what', metavar
='<what>',
1800 'Display the contents of DWARF debug sections. <what> can ' +
1801 'one of {info,decodedline,frames,frames-interp,aranges,pubtypes,pubnames,loc,Ranges}'))
1802 argparser
.add_argument('--traceback',
1803 action
='store_true', dest
='show_traceback',
1804 help='Dump the Python traceback on ELFError'
1805 ' exceptions from elftools')
1807 args
= argparser
.parse_args()
1809 if args
.help or not args
.file:
1810 argparser
.print_help()
1813 if args
.show_all_headers
:
1814 do_file_header
= do_section_header
= do_program_header
= True
1816 do_file_header
= args
.show_file_header
1817 do_section_header
= args
.show_section_header
1818 do_program_header
= args
.show_program_header
1820 with
open(args
.file, 'rb') as file:
1822 readelf
= ReadElf(file, stream
or sys
.stdout
)
1824 readelf
.display_file_header()
1825 if do_section_header
:
1826 readelf
.display_section_headers(
1827 show_heading
=not do_file_header
)
1828 if do_program_header
:
1829 readelf
.display_program_headers(
1830 show_heading
=not do_file_header
)
1831 if args
.show_dynamic_tags
:
1832 readelf
.display_dynamic_tags()
1833 if args
.show_symbols
:
1834 readelf
.display_symbol_tables()
1836 readelf
.display_notes()
1837 if args
.show_relocs
:
1838 readelf
.display_relocations()
1839 if args
.show_arm_unwind
:
1840 readelf
.display_arm_unwind()
1841 if args
.show_version_info
:
1842 readelf
.display_version_info()
1843 if args
.show_arch_specific
:
1844 readelf
.display_arch_specific()
1845 if args
.show_hex_dump
:
1846 readelf
.display_hex_dump(args
.show_hex_dump
)
1847 if args
.show_string_dump
:
1848 readelf
.display_string_dump(args
.show_string_dump
)
1849 if args
.debug_dump_what
:
1850 readelf
.display_debug_dump(args
.debug_dump_what
)
1851 except ELFError
as ex
:
1853 sys
.stderr
.write('ELF error: %s\n' % ex
)
1854 if args
.show_traceback
:
1855 traceback
.print_exc()
1860 # Run 'main' redirecting its output to readelfout.txt
1861 # Saves profiling information in readelf.profile
1862 PROFFILE
= 'readelf.profile'
1864 cProfile
.run('main(open("readelfout.txt", "w"))', PROFFILE
)
1866 # Dig in some profiling stats
1868 p
= pstats
.Stats(PROFFILE
)
1869 p
.sort_stats('cumulative').print_stats(25)
1872 #-------------------------------------------------------------------------------
1873 if __name__
== '__main__':