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.
954 s
= '0x' if lead0x
else ''
956 fieldsize
= 8 if self
.elffile
.elfclass
== 32 else 16
957 if fieldsize
is None:
960 field
= '%' + '0%sx' % fieldsize
961 return s
+ field
% addr
963 def _print_version_section_header(self
, version_section
, name
, lead0x
=True,
965 """ Print a section header of one version related section (versym,
966 verneed or verdef) with some options to accomodate readelf
967 little differences between each header (e.g. indentation
970 if hasattr(version_section
, 'num_versions'):
971 num_entries
= version_section
.num_versions()
973 num_entries
= version_section
.num_symbols()
975 self
._emitline
("\n%s section '%s' contains %d %s:" % (
976 name
, version_section
.name
, num_entries
,
977 'entry' if num_entries
== 1 else 'entries'))
978 self
._emitline
('%sAddr: %s Offset: %s Link: %i (%s)' % (
981 version_section
['sh_addr'], fieldsize
=16, lead0x
=lead0x
),
983 version_section
['sh_offset'], fieldsize
=6, lead0x
=True),
984 version_section
['sh_link'],
985 self
.elffile
.get_section(version_section
['sh_link']).name
989 def _init_versioninfo(self
):
990 """ Search and initialize informations about version related sections
991 and the kind of versioning used (GNU or Solaris).
993 if self
._versioninfo
is not None:
996 self
._versioninfo
= {'versym': None, 'verdef': None,
997 'verneed': None, 'type': None}
999 for section
in self
.elffile
.iter_sections():
1000 if isinstance(section
, GNUVerSymSection
):
1001 self
._versioninfo
['versym'] = section
1002 elif isinstance(section
, GNUVerDefSection
):
1003 self
._versioninfo
['verdef'] = section
1004 elif isinstance(section
, GNUVerNeedSection
):
1005 self
._versioninfo
['verneed'] = section
1006 elif isinstance(section
, DynamicSection
):
1007 for tag
in section
.iter_tags():
1008 if tag
['d_tag'] == 'DT_VERSYM':
1009 self
._versioninfo
['type'] = 'GNU'
1012 if not self
._versioninfo
['type'] and (
1013 self
._versioninfo
['verneed'] or self
._versioninfo
['verdef']):
1014 self
._versioninfo
['type'] = 'Solaris'
1016 def _symbol_version(self
, nsym
):
1017 """ Return a dict containing information on the
1018 or None if no version information is available
1020 self
._init
_versioninfo
()
1022 symbol_version
= dict.fromkeys(('index', 'name', 'filename', 'hidden'))
1024 if (not self
._versioninfo
['versym'] or
1025 nsym
>= self
._versioninfo
['versym'].num_symbols()):
1028 symbol
= self
._versioninfo
['versym'].get_symbol(nsym
)
1029 index
= symbol
.entry
['ndx']
1030 if not index
in ('VER_NDX_LOCAL', 'VER_NDX_GLOBAL'):
1033 if self
._versioninfo
['type'] == 'GNU':
1034 # In GNU versioning mode, the highest bit is used to
1035 # store whether the symbol is hidden or not
1038 symbol_version
['hidden'] = True
1040 if (self
._versioninfo
['verdef'] and
1041 index
<= self
._versioninfo
['verdef'].num_versions()):
1043 self
._versioninfo
['verdef'].get_version(index
)
1044 symbol_version
['name'] = next(verdaux_iter
).name
1046 verneed
, vernaux
= \
1047 self
._versioninfo
['verneed'].get_version(index
)
1048 symbol_version
['name'] = vernaux
.name
1049 symbol_version
['filename'] = verneed
.name
1051 symbol_version
['index'] = index
1052 return symbol_version
1054 def _section_from_spec(self
, spec
):
1055 """ Retrieve a section given a "spec" (either number or name).
1056 Return None if no such section exists in the file.
1060 if num
< self
.elffile
.num_sections():
1061 return self
.elffile
.get_section(num
)
1065 # Not a number. Must be a name then
1066 return self
.elffile
.get_section_by_name(spec
)
1068 def _get_symbol_shndx(self
, symbol
, symbol_index
, symtab_index
):
1069 """ Get the index into the section header table for the "symbol"
1070 at "symbol_index" located in the symbol table with section index
1073 symbol_shndx
= symbol
['st_shndx']
1074 if symbol_shndx
!= SHN_INDICES
.SHN_XINDEX
:
1077 # Check for or lazily construct index section mapping (symbol table
1078 # index -> corresponding symbol table index section object)
1079 if self
._shndx
_sections
is None:
1080 self
._shndx
_sections
= {sec
.symboltable
: sec
for sec
in self
.elffile
.iter_sections()
1081 if isinstance(sec
, SymbolTableIndexSection
)}
1082 return self
._shndx
_sections
[symtab_index
].get_section_index(symbol_index
)
1084 def _note_relocs_for_section(self
, section
):
1085 """ If there are relocation sections pointing to the givne section,
1086 emit a note about it.
1088 for relsec
in self
.elffile
.iter_sections():
1089 if isinstance(relsec
, RelocationSection
):
1090 info_idx
= relsec
['sh_info']
1091 if self
.elffile
.get_section(info_idx
) == section
:
1092 self
._emitline
(' Note: This section has relocations against it, but these have NOT been applied to this dump.')
1095 def _init_dwarfinfo(self
):
1096 """ Initialize the DWARF info contained in the file and assign it to
1098 Leave self._dwarfinfo at None if no DWARF info was found in the file
1100 if self
._dwarfinfo
is not None:
1103 if self
.elffile
.has_dwarf_info():
1104 self
._dwarfinfo
= self
.elffile
.get_dwarf_info()
1106 self
._dwarfinfo
= None
1108 def _dump_debug_info(self
):
1109 """ Dump the debugging info section.
1111 if not self
._dwarfinfo
.has_debug_info
:
1113 self
._emitline
('Contents of the %s section:\n' % self
._dwarfinfo
.debug_info_sec
.name
)
1115 # Offset of the .debug_info section in the stream
1116 section_offset
= self
._dwarfinfo
.debug_info_sec
.global_offset
1118 for cu
in self
._dwarfinfo
.iter_CUs():
1119 self
._emitline
(' Compilation Unit @ offset %s:' %
1120 self
._format
_hex
(cu
.cu_offset
))
1121 self
._emitline
(' Length: %s (%s)' % (
1122 self
._format
_hex
(cu
['unit_length']),
1123 '%s-bit' % cu
.dwarf_format()))
1124 self
._emitline
(' Version: %s' % cu
['version'])
1125 if cu
['version'] >= 5:
1126 if cu
.header
.get("unit_type", ''):
1127 unit_type
= cu
.header
.unit_type
1128 self
._emitline
(' Unit Type: %s (%d)' % (
1129 unit_type
, ENUM_DW_UT
.get(cu
.header
.unit_type
, 0)))
1130 self
._emitline
(' Abbrev Offset: %s' % (
1131 self
._format
_hex
(cu
['debug_abbrev_offset'])))
1132 self
._emitline
(' Pointer Size: %s' % cu
['address_size'])
1133 if unit_type
in ('DW_UT_skeleton', 'DW_UT_split_compile'):
1134 self
._emitline
(' Dwo id: %s' % cu
['dwo_id'])
1135 elif unit_type
in ('DW_UT_type', 'DW_UT_split_type'):
1136 self
._emitline
(' Signature: 0x%x' % cu
['type_signature'])
1137 self
._emitline
(' Type Offset: 0x%x' % cu
['type_offset'])
1139 self
._emitline
(' Abbrev Offset: %s' % (
1140 self
._format
_hex
(cu
['debug_abbrev_offset']))),
1141 self
._emitline
(' Pointer Size: %s' % cu
['address_size'])
1143 # The nesting depth of each DIE within the tree of DIEs must be
1144 # displayed. To implement this, a counter is incremented each time
1145 # the current DIE has children, and decremented when a null die is
1146 # encountered. Due to the way the DIE tree is serialized, this will
1147 # correctly reflect the nesting depth
1150 current_function
= None
1151 for die
in cu
.iter_DIEs():
1152 if die
.tag
== 'DW_TAG_subprogram':
1153 current_function
= die
1154 self
._emitline
(' <%s><%x>: Abbrev Number: %s%s' % (
1158 (' (%s)' % die
.tag
) if not die
.is_null() else ''))
1163 for attr
in die
.attributes
.values():
1165 # Unknown attribute values are passed-through as integers
1166 if isinstance(name
, int):
1167 name
= 'Unknown AT value: %x' % name
1169 attr_desc
= describe_attr_value(attr
, die
, section_offset
)
1171 if 'DW_OP_fbreg' in attr_desc
and current_function
and not 'DW_AT_frame_base' in current_function
.attributes
:
1172 postfix
= ' [without dw_at_frame_base]'
1176 self
._emitline
(' <%x> %-18s: %s%s' % (
1182 if die
.has_children
:
1187 def _dump_debug_line_programs(self
):
1188 """ Dump the (decoded) line programs from .debug_line
1189 The programs are dumped in the order of the CUs they belong to.
1191 if not self
._dwarfinfo
.has_debug_info
:
1193 self
._emitline
('Contents of the %s section:' % self
._dwarfinfo
.debug_line_sec
.name
)
1195 lineprogram_list
= []
1197 for cu
in self
._dwarfinfo
.iter_CUs():
1198 # Avoid dumping same lineprogram multiple times
1199 lineprogram
= self
._dwarfinfo
.line_program_for_CU(cu
)
1201 if lineprogram
in lineprogram_list
:
1204 lineprogram_list
.append(lineprogram
)
1205 ver5
= lineprogram
.header
.version
>= 5
1207 cu_filename
= bytes2str(lineprogram
['file_entry'][0].name
)
1208 if len(lineprogram
['include_directory']) > 0:
1209 # GNU readelf 2.38 only outputs directory in wide mode
1210 self
._emitline
('%s:' % cu_filename
)
1212 self
._emitline
('CU: %s:' % cu_filename
)
1214 self
._emitline
('File name Line number Starting address Stmt')
1215 # GNU readelf has a View column that we don't try to replicate
1216 # The autotest has logic in place to ignore that
1218 # Print each state's file, line and address information. For some
1219 # instructions other output is needed to be compatible with
1221 for entry
in lineprogram
.get_entries():
1224 # Special handling for commands that don't set a new state
1225 if entry
.command
== DW_LNS_set_file
:
1226 file_entry
= lineprogram
['file_entry'][entry
.args
[0] - 1]
1227 if file_entry
.dir_index
== 0:
1229 self
._emitline
('\n./%s:[++]' % (
1230 bytes2str(file_entry
.name
)))
1232 self
._emitline
('\n%s/%s:' % (
1233 bytes2str(lineprogram
['include_directory'][file_entry
.dir_index
- 1]),
1234 bytes2str(file_entry
.name
)))
1235 elif entry
.command
== DW_LNE_define_file
:
1236 self
._emitline
('%s:' % (
1237 bytes2str(lineprogram
['include_directory'][entry
.args
[0].dir_index
])))
1238 elif lineprogram
['version'] < 4 or self
.elffile
['e_machine'] == 'EM_PPC64':
1239 self
._emitline
('%-35s %11s %18s %s' % (
1240 bytes2str(lineprogram
['file_entry'][state
.file - 1].name
),
1241 state
.line
if not state
.end_sequence
else '-',
1242 '0' if state
.address
== 0 else self
._format
_hex
(state
.address
),
1243 'x' if state
.is_stmt
and not state
.end_sequence
else ''))
1245 # In readelf, on non-VLIW machines there is no op_index postfix after address.
1246 # It used to be unconditional.
1247 self
._emitline
('%-35s %s %18s%s %s' % (
1248 bytes2str(lineprogram
['file_entry'][state
.file - 1].name
),
1249 "%11d" % (state
.line
,) if not state
.end_sequence
else '-',
1250 '0' if state
.address
== 0 else self
._format
_hex
(state
.address
),
1251 '' if lineprogram
.header
.maximum_operations_per_instruction
== 1 else '[%d]' % (state
.op_index
,),
1252 'x' if state
.is_stmt
and not state
.end_sequence
else ''))
1253 if entry
.command
== DW_LNS_copy
:
1254 # Another readelf oddity...
1257 def _dump_frames_info(self
, section
, cfi_entries
):
1258 """ Dump the raw call frame info in a section.
1260 `section` is the Section instance that contains the call frame info
1261 while `cfi_entries` must be an iterable that yields the sequence of
1262 CIE or FDE instances.
1264 self
._emitline
('Contents of the %s section:' % section
.name
)
1266 for entry
in cfi_entries
:
1267 if isinstance(entry
, CIE
):
1268 self
._emitline
('\n%08x %s %s CIE' % (
1270 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1271 self
._format
_hex
(entry
['CIE_id'], fieldsize
=8, lead0x
=False)))
1272 self
._emitline
(' Version: %d' % entry
['version'])
1273 self
._emitline
(' Augmentation: "%s"' % bytes2str(entry
['augmentation']))
1274 self
._emitline
(' Code alignment factor: %u' % entry
['code_alignment_factor'])
1275 self
._emitline
(' Data alignment factor: %d' % entry
['data_alignment_factor'])
1276 self
._emitline
(' Return address column: %d' % entry
['return_address_register'])
1277 if entry
.augmentation_bytes
:
1278 self
._emitline
(' Augmentation data: {}'.format(' '.join(
1279 '{:02x}'.format(ord(b
))
1280 for b
in iterbytes(entry
.augmentation_bytes
)
1284 elif isinstance(entry
, FDE
):
1285 self
._emitline
('\n%08x %s %s FDE cie=%08x pc=%s..%s' % (
1287 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1288 self
._format
_hex
(entry
['CIE_pointer'], fieldsize
=8, lead0x
=False),
1290 self
._format
_hex
(entry
['initial_location'], fullhex
=True, lead0x
=False),
1292 entry
['initial_location'] + entry
['address_range'],
1293 fullhex
=True, lead0x
=False)))
1294 if entry
.augmentation_bytes
:
1295 self
._emitline
(' Augmentation data: {}'.format(' '.join(
1296 '{:02x}'.format(ord(b
))
1297 for b
in iterbytes(entry
.augmentation_bytes
)
1300 else: # ZERO terminator
1301 assert isinstance(entry
, ZERO
)
1302 self
._emitline
('\n%08x ZERO terminator' % entry
.offset
)
1305 self
._emit
(describe_CFI_instructions(entry
))
1308 def _dump_debug_frames(self
):
1309 """ Dump the raw frame info from .debug_frame and .eh_frame sections.
1311 if self
._dwarfinfo
.has_EH_CFI():
1312 self
._dump
_frames
_info
(
1313 self
._dwarfinfo
.eh_frame_sec
,
1314 self
._dwarfinfo
.EH_CFI_entries())
1317 if self
._dwarfinfo
.has_CFI():
1318 self
._dump
_frames
_info
(
1319 self
._dwarfinfo
.debug_frame_sec
,
1320 self
._dwarfinfo
.CFI_entries())
1322 def _dump_debug_namelut(self
, what
):
1324 Dump the debug pubnames section.
1326 if what
== 'pubnames':
1327 namelut
= self
._dwarfinfo
.get_pubnames()
1328 section
= self
._dwarfinfo
.debug_pubnames_sec
1330 namelut
= self
._dwarfinfo
.get_pubtypes()
1331 section
= self
._dwarfinfo
.debug_pubtypes_sec
1333 # readelf prints nothing if the section is not present.
1334 if namelut
is None or len(namelut
) == 0:
1337 self
._emitline
('Contents of the %s section:' % section
.name
)
1340 cu_headers
= namelut
.get_cu_headers()
1342 # go over CU-by-CU first and item-by-item next.
1343 for (cu_hdr
, (cu_ofs
, items
)) in izip(cu_headers
, itertools
.groupby(
1344 namelut
.items(), key
= lambda x
: x
[1].cu_ofs
)):
1346 self
._emitline
(' Length: %d' % cu_hdr
.unit_length
)
1347 self
._emitline
(' Version: %d' % cu_hdr
.version
)
1348 self
._emitline
(' Offset into .debug_info section: 0x%x' % cu_hdr
.debug_info_offset
)
1349 self
._emitline
(' Size of area in .debug_info section: %d' % cu_hdr
.debug_info_length
)
1351 self
._emitline
(' Offset Name')
1353 self
._emitline
(' %x %s' % (item
[1].die_ofs
- cu_ofs
, item
[0]))
1356 def _dump_debug_aranges(self
):
1357 """ Dump the aranges table
1359 aranges_table
= self
._dwarfinfo
.get_aranges()
1360 if aranges_table
== None:
1362 # Seems redundant, but we need to get the unsorted set of entries
1363 # to match system readelf.
1364 # Also, sometimes there are blank sections in aranges, but readelf
1365 # dumps them, so we should too.
1366 unordered_entries
= aranges_table
._get
_entries
(need_empty
=True)
1368 if len(unordered_entries
) == 0:
1370 self
._emitline
("Section '.debug_aranges' has no debugging data.")
1373 self
._emitline
('Contents of the %s section:' % self
._dwarfinfo
.debug_aranges_sec
.name
)
1376 for entry
in unordered_entries
:
1377 if prev_offset
!= entry
.info_offset
:
1378 if entry
!= unordered_entries
[0]:
1379 self
._emitline
(' %s %s' % (
1380 self
._format
_hex
(0, fullhex
=True, lead0x
=False),
1381 self
._format
_hex
(0, fullhex
=True, lead0x
=False)))
1382 self
._emitline
(' Length: %d' % (entry
.unit_length
))
1383 self
._emitline
(' Version: %d' % (entry
.version
))
1384 self
._emitline
(' Offset into .debug_info: 0x%x' % (entry
.info_offset
))
1385 self
._emitline
(' Pointer Size: %d' % (entry
.address_size
))
1386 self
._emitline
(' Segment Size: %d' % (entry
.segment_size
))
1388 self
._emitline
(' Address Length')
1389 if entry
.begin_addr
!= 0 or entry
.length
!= 0:
1390 self
._emitline
(' %s %s' % (
1391 self
._format
_hex
(entry
.begin_addr
, fullhex
=True, lead0x
=False),
1392 self
._format
_hex
(entry
.length
, fullhex
=True, lead0x
=False)))
1393 prev_offset
= entry
.info_offset
1394 self
._emitline
(' %s %s' % (
1395 self
._format
_hex
(0, fullhex
=True, lead0x
=False),
1396 self
._format
_hex
(0, fullhex
=True, lead0x
=False)))
1398 def _dump_frames_interp_info(self
, section
, cfi_entries
):
1399 """ Dump interpreted (decoded) frame information in a section.
1401 `section` is the Section instance that contains the call frame info
1402 while `cfi_entries` must be an iterable that yields the sequence of
1403 CIE or FDE instances.
1405 self
._emitline
('Contents of the %s section:' % section
.name
)
1407 for entry
in cfi_entries
:
1408 if isinstance(entry
, CIE
):
1409 self
._emitline
('\n%08x %s %s CIE "%s" cf=%d df=%d ra=%d' % (
1411 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1412 self
._format
_hex
(entry
['CIE_id'], fieldsize
=8, lead0x
=False),
1413 bytes2str(entry
['augmentation']),
1414 entry
['code_alignment_factor'],
1415 entry
['data_alignment_factor'],
1416 entry
['return_address_register']))
1417 ra_regnum
= entry
['return_address_register']
1419 elif isinstance(entry
, FDE
):
1420 self
._emitline
('\n%08x %s %s FDE cie=%08x pc=%s..%s' % (
1422 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1423 self
._format
_hex
(entry
['CIE_pointer'], fieldsize
=8, lead0x
=False),
1425 self
._format
_hex
(entry
['initial_location'], fullhex
=True, lead0x
=False),
1426 self
._format
_hex
(entry
['initial_location'] + entry
['address_range'],
1427 fullhex
=True, lead0x
=False)))
1428 ra_regnum
= entry
.cie
['return_address_register']
1430 # If the FDE brings adds no unwinding information compared to
1431 # its CIE, omit its table.
1432 if (len(entry
.get_decoded().table
) ==
1433 len(entry
.cie
.get_decoded().table
)):
1436 else: # ZERO terminator
1437 assert isinstance(entry
, ZERO
)
1438 self
._emitline
('\n%08x ZERO terminator' % entry
.offset
)
1442 decoded_table
= entry
.get_decoded()
1443 if len(decoded_table
.table
) == 0:
1446 # Print the heading row for the decoded table
1448 self
._emit
(' ' if entry
.structs
.address_size
== 4 else ' ')
1451 # Look at the registers the decoded table describes.
1452 # We build reg_order here to match readelf's order. In particular,
1453 # registers are sorted by their number, and the register matching
1454 # ra_regnum is always listed last with a special heading.
1455 decoded_table
= entry
.get_decoded()
1456 reg_order
= sorted(filter(
1457 lambda r
: r
!= ra_regnum
,
1458 decoded_table
.reg_order
))
1459 if len(decoded_table
.reg_order
):
1461 # Headings for the registers
1462 for regnum
in reg_order
:
1463 self
._emit
('%-6s' % describe_reg_name(regnum
))
1464 self
._emitline
('ra ')
1466 # Now include ra_regnum in reg_order to print its values
1467 # similarly to the other registers.
1468 reg_order
.append(ra_regnum
)
1472 for line
in decoded_table
.table
:
1473 self
._emit
(self
._format
_hex
(
1474 line
['pc'], fullhex
=True, lead0x
=False))
1476 if line
['cfa'] is not None:
1477 s
= describe_CFI_CFA_rule(line
['cfa'])
1480 self
._emit
(' %-9s' % s
)
1482 for regnum
in reg_order
:
1484 s
= describe_CFI_register_rule(line
[regnum
])
1487 self
._emit
('%-6s' % s
)
1491 def _dump_debug_frames_interp(self
):
1492 """ Dump the interpreted (decoded) frame information from .debug_frame
1493 and .eh_frame sections.
1495 if self
._dwarfinfo
.has_EH_CFI():
1496 self
._dump
_frames
_interp
_info
(
1497 self
._dwarfinfo
.eh_frame_sec
,
1498 self
._dwarfinfo
.EH_CFI_entries())
1501 if self
._dwarfinfo
.has_CFI():
1502 self
._dump
_frames
_interp
_info
(
1503 self
._dwarfinfo
.debug_frame_sec
,
1504 self
._dwarfinfo
.CFI_entries())
1506 def _dump_debug_locations(self
):
1507 """ Dump the location lists from .debug_loc/.debug_loclists section
1509 di
= self
._dwarfinfo
1510 loc_lists_sec
= di
.location_lists()
1511 if not loc_lists_sec
: # No locations section - readelf outputs nothing
1514 if isinstance(loc_lists_sec
, LocationListsPair
):
1515 self
._dump
_debug
_locsection
(di
, loc_lists_sec
._loc
)
1516 self
._dump
_debug
_locsection
(di
, loc_lists_sec
._loclists
)
1518 self
._dump
_debug
_locsection
(di
, loc_lists_sec
)
1520 def _dump_debug_locsection(self
, di
, loc_lists_sec
):
1521 """ Dump the location lists from .debug_loc/.debug_loclists section
1523 ver5
= loc_lists_sec
.version
>= 5
1524 section_name
= (di
.debug_loclists_sec
if ver5
else di
.debug_loc_sec
).name
1526 # To dump a location list, one needs to know the CU.
1527 # Scroll through DIEs once, list the known location list offsets.
1528 # Don't need this CU/DIE scan if all entries are absolute or prefixed by base,
1529 # but let's not optimize for that yet.
1530 cu_map
= dict() # Loc list offset => CU
1531 for cu
in di
.iter_CUs():
1532 for die
in cu
.iter_DIEs():
1533 for key
in die
.attributes
:
1534 attr
= die
.attributes
[key
]
1535 if (LocationParser
.attribute_has_location(attr
, cu
['version']) and
1536 LocationParser
._attribute
_has
_loc
_list
(attr
, cu
['version'])):
1537 cu_map
[attr
.value
] = cu
1539 addr_size
= di
.config
.default_address_size
# In bytes, 4 or 8
1540 addr_width
= addr_size
* 2 # In hex digits, 8 or 16
1541 line_template
= " %%08x %%0%dx %%0%dx %%s%%s" % (addr_width
, addr_width
)
1543 loc_lists
= list(loc_lists_sec
.iter_location_lists())
1544 if len(loc_lists
) == 0:
1545 # Present but empty locations section - readelf outputs a message
1546 self
._emitline
("\nSection '%s' has no debugging data." % (section_name
,))
1549 self
._emitline
('Contents of the %s section:\n' % (section_name
,))
1550 self
._emitline
(' Offset Begin End Expression')
1551 for loc_list
in loc_lists
:
1552 self
._dump
_loclist
(loc_list
, line_template
, cu_map
)
1554 def _dump_loclist(self
, loc_list
, line_template
, cu_map
):
1560 for entry
in loc_list
:
1561 if isinstance(entry
, LocationViewPair
):
1562 has_views
= in_views
= True
1563 # The "v" before address is conditional in binutils, haven't figured out how
1564 self
._emitline
(" %08x v%015x v%015x location view pair" % (entry
.entry_offset
, entry
.begin
, entry
.end
))
1570 # Readelf quirk: indexed loclists don't show the real base IP
1574 cu
= cu_map
.get(entry
.entry_offset
, False)
1576 raise ValueError("Location list can't be tracked to a CU")
1578 if isinstance(entry
, LocationEntry
):
1579 if base_ip
is None and not entry
.is_absolute
:
1580 base_ip
= _get_cu_base(cu
)
1582 begin_offset
= (0 if entry
.is_absolute
else base_ip
) + entry
.begin_offset
1583 end_offset
= (0 if entry
.is_absolute
else base_ip
) + entry
.end_offset
1584 expr
= describe_DWARF_expr(entry
.loc_expr
, cu
.structs
, cu
.cu_offset
)
1586 view
= loc_list
[loc_entry_count
]
1587 postfix
= ' (start == end)' if entry
.begin_offset
== entry
.end_offset
and view
.begin
== view
.end
else ''
1588 self
._emitline
(' %08x v%015x v%015x views at %08x for:' %(
1593 self
._emitline
(' %016x %016x %s%s' %(
1598 loc_entry_count
+= 1
1600 postfix
= ' (start == end)' if entry
.begin_offset
== entry
.end_offset
else ''
1601 self
._emitline
(line_template
% (
1607 elif isinstance(entry
, LocBaseAddressEntry
):
1608 base_ip
= entry
.base_address
1609 self
._emitline
(" %08x %016x (base address)" % (entry
.entry_offset
, entry
.base_address
))
1611 # Pyelftools doesn't store the terminating entry,
1612 # but readelf emits its offset, so this should too.
1614 self
._emitline
(" %08x <End of list>" % (last
.entry_offset
+ last
.entry_length
))
1616 def _dump_debug_ranges(self
):
1617 # TODO: GNU readelf format doesn't need entry_length?
1618 di
= self
._dwarfinfo
1619 range_lists_sec
= di
.range_lists()
1620 if not range_lists_sec
: # No ranges section - readelf outputs nothing
1623 if isinstance(range_lists_sec
, RangeListsPair
):
1624 self
._dump
_debug
_rangesection
(di
, range_lists_sec
._ranges
)
1625 self
._dump
_debug
_rangesection
(di
, range_lists_sec
._rnglists
)
1627 self
._dump
_debug
_rangesection
(di
, range_lists_sec
)
1629 def _dump_debug_rangesection(self
, di
, range_lists_sec
):
1630 # In the master branch of binutils, the v5 dump format is way different by now.
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 range_lists
= list(range_lists_sec
.iter_range_lists())
1640 if len(range_lists
) == 0:
1641 # Present but empty locations section - readelf outputs a message
1642 self
._emitline
("\nSection '%s' has no debugging data." % section_name
)
1645 # In order to determine the base address of the range
1646 # We need to know the corresponding CU.
1647 cu_map
= {die
.attributes
['DW_AT_ranges'].value
: cu
# Range list offset => CU
1648 for cu
in di
.iter_CUs()
1649 for die
in cu
.iter_DIEs()
1650 if 'DW_AT_ranges' in die
.attributes
}
1652 self
._emitline
('Contents of the %s section:\n' % section_name
)
1653 self
._emitline
(' Offset Begin End')
1655 for range_list
in range_lists
:
1656 self
._dump
_rangelist
(range_list
, cu_map
, ver5
, line_template
, base_template
)
1658 def _dump_rangelist(self
, range_list
, cu_map
, ver5
, line_template
, base_template
):
1659 # Weird discrepancy in binutils: for DWARFv5 it outputs entry offset,
1660 # for DWARF<=4 list offset.
1661 first
= range_list
[0]
1662 base_ip
= _get_cu_base(cu_map
[first
.entry_offset
])
1663 for entry
in range_list
:
1664 if isinstance(entry
, RangeEntry
):
1665 postfix
= ' (start == end)' if entry
.begin_offset
== entry
.end_offset
else ''
1666 self
._emitline
(line_template
% (
1667 entry
.entry_offset
if ver5
else first
.entry_offset
,
1668 (0 if entry
.is_absolute
else base_ip
) + entry
.begin_offset
,
1669 (0 if entry
.is_absolute
else base_ip
) + entry
.end_offset
,
1671 elif isinstance(entry
,RangeBaseAddressEntry
):
1672 base_ip
= entry
.base_address
1673 self
._emitline
(base_template
% (
1674 entry
.entry_offset
if ver5
else first
.entry_offset
,
1675 entry
.base_address
))
1677 raise NotImplementedError("Unknown object in a range list")
1678 last
= range_list
[-1]
1679 self
._emitline
(' %08x <End of list>' % (last
.entry_offset
+ last
.entry_length
if ver5
else first
.entry_offset
))
1681 def _display_attributes(self
, attr_sec
, descriptor
):
1682 """ Display the attributes contained in the section.
1684 for s
in attr_sec
.iter_subsections():
1685 self
._emitline
("Attribute Section: %s" % s
.header
['vendor_name'])
1686 for ss
in s
.iter_subsubsections():
1687 h_val
= "" if ss
.header
.extra
is None else " ".join("%d" % x
for x
in ss
.header
.extra
)
1688 self
._emitline
(descriptor(ss
.header
.tag
, h_val
, None))
1690 for attr
in ss
.iter_attributes():
1692 self
._emitline
(descriptor(attr
.tag
, attr
.value
, attr
.extra
))
1694 def _display_arch_specific_arm(self
):
1695 """ Display the ARM architecture-specific info contained in the file.
1697 attr_sec
= self
.elffile
.get_section_by_name('.ARM.attributes')
1698 self
._display
_attributes
(attr_sec
, describe_attr_tag_arm
)
1700 def _display_arch_specific_riscv(self
):
1701 """ Display the RISC-V architecture-specific info contained in the file.
1703 attr_sec
= self
.elffile
.get_section_by_name('.riscv.attributes')
1704 self
._display
_attributes
(attr_sec
, describe_attr_tag_riscv
)
1706 def _emit(self
, s
=''):
1707 """ Emit an object to output
1709 self
.output
.write(str(s
))
1711 def _emitline(self
, s
=''):
1712 """ Emit an object to output, followed by a newline
1714 self
.output
.write(str(s
).rstrip() + '\n')
1717 SCRIPT_DESCRIPTION
= 'Display information about the contents of ELF format files'
1718 VERSION_STRING
= '%%(prog)s: based on pyelftools %s' % __version__
1721 def main(stream
=None):
1722 # parse the command-line arguments and invoke ReadElf
1723 argparser
= argparse
.ArgumentParser(
1724 usage
='usage: %(prog)s [options] <elf-file>',
1725 description
=SCRIPT_DESCRIPTION
,
1726 add_help
=False, # -h is a real option of readelf
1728 argparser
.add_argument('file',
1729 nargs
='?', default
=None,
1730 help='ELF file to parse')
1731 argparser
.add_argument('-v', '--version',
1732 action
='version', version
=VERSION_STRING
)
1733 argparser
.add_argument('-d', '--dynamic',
1734 action
='store_true', dest
='show_dynamic_tags',
1735 help='Display the dynamic section')
1736 argparser
.add_argument('-H', '--help',
1737 action
='store_true', dest
='help',
1738 help='Display this information')
1739 argparser
.add_argument('-h', '--file-header',
1740 action
='store_true', dest
='show_file_header',
1741 help='Display the ELF file header')
1742 argparser
.add_argument('-l', '--program-headers', '--segments',
1743 action
='store_true', dest
='show_program_header',
1744 help='Display the program headers')
1745 argparser
.add_argument('-S', '--section-headers', '--sections',
1746 action
='store_true', dest
='show_section_header',
1747 help="Display the sections' headers")
1748 argparser
.add_argument('-e', '--headers',
1749 action
='store_true', dest
='show_all_headers',
1750 help='Equivalent to: -h -l -S')
1751 argparser
.add_argument('-s', '--symbols', '--syms',
1752 action
='store_true', dest
='show_symbols',
1753 help='Display the symbol table')
1754 argparser
.add_argument('-n', '--notes',
1755 action
='store_true', dest
='show_notes',
1756 help='Display the core notes (if present)')
1757 argparser
.add_argument('-r', '--relocs',
1758 action
='store_true', dest
='show_relocs',
1759 help='Display the relocations (if present)')
1760 argparser
.add_argument('-au', '--arm-unwind',
1761 action
='store_true', dest
='show_arm_unwind',
1762 help='Display the armeabi unwind information (if present)')
1763 argparser
.add_argument('-x', '--hex-dump',
1764 action
='store', dest
='show_hex_dump', metavar
='<number|name>',
1765 help='Dump the contents of section <number|name> as bytes')
1766 argparser
.add_argument('-p', '--string-dump',
1767 action
='store', dest
='show_string_dump', metavar
='<number|name>',
1768 help='Dump the contents of section <number|name> as strings')
1769 argparser
.add_argument('-V', '--version-info',
1770 action
='store_true', dest
='show_version_info',
1771 help='Display the version sections (if present)')
1772 argparser
.add_argument('-A', '--arch-specific',
1773 action
='store_true', dest
='show_arch_specific',
1774 help='Display the architecture-specific information (if present)')
1775 argparser
.add_argument('--debug-dump',
1776 action
='store', dest
='debug_dump_what', metavar
='<what>',
1778 'Display the contents of DWARF debug sections. <what> can ' +
1779 'one of {info,decodedline,frames,frames-interp,aranges,pubtypes,pubnames,loc,Ranges}'))
1780 argparser
.add_argument('--traceback',
1781 action
='store_true', dest
='show_traceback',
1782 help='Dump the Python traceback on ELFError'
1783 ' exceptions from elftools')
1785 args
= argparser
.parse_args()
1787 if args
.help or not args
.file:
1788 argparser
.print_help()
1791 if args
.show_all_headers
:
1792 do_file_header
= do_section_header
= do_program_header
= True
1794 do_file_header
= args
.show_file_header
1795 do_section_header
= args
.show_section_header
1796 do_program_header
= args
.show_program_header
1798 with
open(args
.file, 'rb') as file:
1800 readelf
= ReadElf(file, stream
or sys
.stdout
)
1802 readelf
.display_file_header()
1803 if do_section_header
:
1804 readelf
.display_section_headers(
1805 show_heading
=not do_file_header
)
1806 if do_program_header
:
1807 readelf
.display_program_headers(
1808 show_heading
=not do_file_header
)
1809 if args
.show_dynamic_tags
:
1810 readelf
.display_dynamic_tags()
1811 if args
.show_symbols
:
1812 readelf
.display_symbol_tables()
1814 readelf
.display_notes()
1815 if args
.show_relocs
:
1816 readelf
.display_relocations()
1817 if args
.show_arm_unwind
:
1818 readelf
.display_arm_unwind()
1819 if args
.show_version_info
:
1820 readelf
.display_version_info()
1821 if args
.show_arch_specific
:
1822 readelf
.display_arch_specific()
1823 if args
.show_hex_dump
:
1824 readelf
.display_hex_dump(args
.show_hex_dump
)
1825 if args
.show_string_dump
:
1826 readelf
.display_string_dump(args
.show_string_dump
)
1827 if args
.debug_dump_what
:
1828 readelf
.display_debug_dump(args
.debug_dump_what
)
1829 except ELFError
as ex
:
1831 sys
.stderr
.write('ELF error: %s\n' % ex
)
1832 if args
.show_traceback
:
1833 traceback
.print_exc()
1838 # Run 'main' redirecting its output to readelfout.txt
1839 # Saves profiling information in readelf.profile
1840 PROFFILE
= 'readelf.profile'
1842 cProfile
.run('main(open("readelfout.txt", "w"))', PROFFILE
)
1844 # Dig in some profiling stats
1846 p
= pstats
.Stats(PROFFILE
)
1847 p
.sort_stats('cumulative').print_stats(25)
1850 #-------------------------------------------------------------------------------
1851 if __name__
== '__main__':