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 #-------------------------------------------------------------------------------
16 # Note: zip has different behaviour between Python 2.x and 3.x.
17 # - Using izip ensures compatibility.
19 from itertools
import izip
23 # For running from development directory. It should take precedence over the
24 # installed pyelftools.
25 sys
.path
.insert(0, '.')
28 from elftools
import __version__
29 from elftools
.common
.exceptions
import ELFError
30 from elftools
.common
.utils
import bytes2str
, iterbytes
31 from elftools
.elf
.elffile
import ELFFile
32 from elftools
.elf
.dynamic
import DynamicSection
, DynamicSegment
33 from elftools
.elf
.enums
import ENUM_D_TAG
34 from elftools
.elf
.segments
import InterpSegment
35 from elftools
.elf
.sections
import (
36 NoteSection
, SymbolTableSection
, SymbolTableIndexSection
38 from elftools
.elf
.gnuversions
import (
39 GNUVerSymSection
, GNUVerDefSection
,
42 from elftools
.elf
.relocation
import RelocationSection
43 from elftools
.elf
.descriptions
import (
44 describe_ei_class
, describe_ei_data
, describe_ei_version
,
45 describe_ei_osabi
, describe_e_type
, describe_e_machine
,
46 describe_e_version_numeric
, describe_p_type
, describe_p_flags
,
47 describe_rh_flags
, describe_sh_type
, describe_sh_flags
,
48 describe_symbol_type
, describe_symbol_bind
, describe_symbol_visibility
,
49 describe_symbol_shndx
, describe_reloc_type
, describe_dyn_tag
,
50 describe_dt_flags
, describe_dt_flags_1
, describe_ver_flags
, describe_note
,
51 describe_attr_tag_arm
, describe_attr_tag_riscv
, describe_symbol_other
53 from elftools
.elf
.constants
import E_FLAGS
54 from elftools
.elf
.constants
import E_FLAGS_MASKS
55 from elftools
.elf
.constants
import SH_FLAGS
56 from elftools
.elf
.constants
import SHN_INDICES
57 from elftools
.dwarf
.dwarfinfo
import DWARFInfo
58 from elftools
.dwarf
.descriptions
import (
59 describe_reg_name
, describe_attr_value
, set_global_machine_arch
,
60 describe_CFI_instructions
, describe_CFI_register_rule
,
61 describe_CFI_CFA_rule
, describe_DWARF_expr
63 from elftools
.dwarf
.constants
import (
64 DW_LNS_copy
, DW_LNS_set_file
, DW_LNE_define_file
)
65 from elftools
.dwarf
.locationlists
import LocationParser
, LocationEntry
, LocationViewPair
, BaseAddressEntry
as LocBaseAddressEntry
, LocationListsPair
66 from elftools
.dwarf
.ranges
import RangeEntry
, BaseAddressEntry
as RangeBaseAddressEntry
, RangeListsPair
67 from elftools
.dwarf
.callframe
import CIE
, FDE
, ZERO
68 from elftools
.ehabi
.ehabiinfo
import CorruptEHABIEntry
, CannotUnwindEHABIEntry
, GenericEHABIEntry
69 from elftools
.dwarf
.enums
import ENUM_DW_UT
72 top_die
= cu
.get_top_DIE()
73 attr
= top_die
.attributes
74 if 'DW_AT_low_pc' in attr
:
75 return attr
['DW_AT_low_pc'].value
76 elif 'DW_AT_entry_pc' in attr
:
77 return attr
['DW_AT_entry_pc'].value
78 elif 'DW_AT_ranges' in attr
:
79 # Rare case but happens: rangelist in the top DIE.
80 # If there is a base or at least one absolute entry,
81 # this will give us the base IP for the CU.
82 rl
= cu
.dwarfinfo
.range_lists().get_range_list_at_offset(attr
['DW_AT_ranges'].value
, cu
)
85 if isinstance(r
, RangeBaseAddressEntry
):
87 elif isinstance(r
, RangeEntry
) and r
.is_absolute
:
91 if ip
is not None and (base_ip
is None or ip
< base_ip
):
94 raise ValueError("Can't find the base IP (low_pc) for a CU")
97 raise ValueError("Can't find the base IP (low_pc) for a CU")
99 # Matcher for all control characters, for transforming them into "^X" form when
100 # formatting symbol names for display.
101 _CONTROL_CHAR_RE
= re
.compile(r
'[\x01-\x1f]')
103 def _format_symbol_name(s
):
104 return _CONTROL_CHAR_RE
.sub(lambda match
: '^' + chr(0x40 + ord(match
[0])), s
)
106 class ReadElf(object):
107 """ display_* methods are used to emit output into the output stream
109 def __init__(self
, file, output
):
111 stream object with the ELF file to read
114 output stream to write to
116 self
.elffile
= ELFFile(file)
119 # Lazily initialized if a debug dump is requested
120 self
._dwarfinfo
= None
122 self
._versioninfo
= None
124 self
._shndx
_sections
= None
126 def display_file_header(self
):
127 """ Display the ELF file header
129 self
._emitline
('ELF Header:')
130 self
._emit
(' Magic: ')
131 self
._emit
(' '.join('%2.2x' % b
132 for b
in self
.elffile
.e_ident_raw
))
134 header
= self
.elffile
.header
135 e_ident
= header
['e_ident']
136 self
._emitline
(' Class: %s' %
137 describe_ei_class(e_ident
['EI_CLASS']))
138 self
._emitline
(' Data: %s' %
139 describe_ei_data(e_ident
['EI_DATA']))
140 self
._emitline
(' Version: %s' %
141 describe_ei_version(e_ident
['EI_VERSION']))
142 self
._emitline
(' OS/ABI: %s' %
143 describe_ei_osabi(e_ident
['EI_OSABI']))
144 self
._emitline
(' ABI Version: %d' %
145 e_ident
['EI_ABIVERSION'])
146 self
._emitline
(' Type: %s' %
147 describe_e_type(header
['e_type'], self
.elffile
))
148 self
._emitline
(' Machine: %s' %
149 describe_e_machine(header
['e_machine']))
150 self
._emitline
(' Version: %s' %
151 describe_e_version_numeric(header
['e_version']))
152 self
._emitline
(' Entry point address: %s' %
153 self
._format
_hex
(header
['e_entry']))
154 self
._emit
(' Start of program headers: %s' %
156 self
._emitline
(' (bytes into file)')
157 self
._emit
(' Start of section headers: %s' %
159 self
._emitline
(' (bytes into file)')
160 self
._emitline
(' Flags: %s%s' %
161 (self
._format
_hex
(header
['e_flags']),
162 self
.decode_flags(header
['e_flags'])))
163 self
._emitline
(' Size of this header: %s (bytes)' %
165 self
._emitline
(' Size of program headers: %s (bytes)' %
166 header
['e_phentsize'])
167 self
._emitline
(' Number of program headers: %s' %
169 self
._emitline
(' Size of section headers: %s (bytes)' %
170 header
['e_shentsize'])
171 self
._emit
(' Number of section headers: %s' %
173 if header
['e_shnum'] == 0 and self
.elffile
.num_sections() != 0:
174 self
._emitline
(' (%d)' % self
.elffile
.num_sections())
177 self
._emit
(' Section header string table index: %s' %
178 header
['e_shstrndx'])
179 if header
['e_shstrndx'] == SHN_INDICES
.SHN_XINDEX
:
180 self
._emitline
(' (%d)' % self
.elffile
.get_shstrndx())
184 def decode_flags(self
, flags
):
186 if self
.elffile
['e_machine'] == "EM_ARM":
187 eabi
= flags
& E_FLAGS
.EF_ARM_EABIMASK
188 flags
&= ~E_FLAGS
.EF_ARM_EABIMASK
190 if flags
& E_FLAGS
.EF_ARM_RELEXEC
:
191 description
+= ', relocatable executabl'
192 flags
&= ~E_FLAGS
.EF_ARM_RELEXEC
194 if eabi
== E_FLAGS
.EF_ARM_EABI_VER5
:
195 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
196 description
+= ', Version5 EABI'
197 if flags
& E_FLAGS
.EF_ARM_ABI_FLOAT_SOFT
:
198 description
+= ", soft-float ABI"
199 elif flags
& E_FLAGS
.EF_ARM_ABI_FLOAT_HARD
:
200 description
+= ", hard-float ABI"
202 if flags
& E_FLAGS
.EF_ARM_BE8
:
203 description
+= ", BE8"
204 elif flags
& E_FLAGS
.EF_ARM_LE8
:
205 description
+= ", LE8"
207 if flags
& ~EF_ARM_KNOWN_FLAGS
:
208 description
+= ', <unknown>'
210 description
+= ', <unrecognized EABI>'
212 elif self
.elffile
['e_machine'] == 'EM_PPC64':
213 if flags
& E_FLAGS
.EF_PPC64_ABI_V2
:
214 description
+= ', abiv2'
216 elif self
.elffile
['e_machine'] == "EM_MIPS":
217 if flags
& E_FLAGS
.EF_MIPS_NOREORDER
:
218 description
+= ", noreorder"
219 if flags
& E_FLAGS
.EF_MIPS_PIC
:
220 description
+= ", pic"
221 if flags
& E_FLAGS
.EF_MIPS_CPIC
:
222 description
+= ", cpic"
223 if (flags
& E_FLAGS
.EF_MIPS_ABI2
):
224 description
+= ", abi2"
225 if (flags
& E_FLAGS
.EF_MIPS_32BITMODE
):
226 description
+= ", 32bitmode"
227 if (flags
& E_FLAGS_MASKS
.EFM_MIPS_ABI_O32
):
228 description
+= ", o32"
229 elif (flags
& E_FLAGS_MASKS
.EFM_MIPS_ABI_O64
):
230 description
+= ", o64"
231 elif (flags
& E_FLAGS_MASKS
.EFM_MIPS_ABI_EABI32
):
232 description
+= ", eabi32"
233 elif (flags
& E_FLAGS_MASKS
.EFM_MIPS_ABI_EABI64
):
234 description
+= ", eabi64"
235 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_1
:
236 description
+= ", mips1"
237 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_2
:
238 description
+= ", mips2"
239 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_3
:
240 description
+= ", mips3"
241 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_4
:
242 description
+= ", mips4"
243 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_5
:
244 description
+= ", mips5"
245 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_32R2
:
246 description
+= ", mips32r2"
247 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_64R2
:
248 description
+= ", mips64r2"
249 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_32
:
250 description
+= ", mips32"
251 if (flags
& E_FLAGS
.EF_MIPS_ARCH
) == E_FLAGS
.EF_MIPS_ARCH_64
:
252 description
+= ", mips64"
254 elif self
.elffile
['e_machine'] == "EM_RISCV":
255 if flags
& E_FLAGS
.EF_RISCV_RVC
:
256 description
+= ", RVC"
257 if (flags
& E_FLAGS
.EF_RISCV_RVE
):
258 description
+= ", RVE"
259 if (flags
& E_FLAGS
.EF_RISCV_TSO
):
260 description
+= ", TSO"
261 if (flags
& E_FLAGS
.EF_RISCV_FLOAT_ABI
) == E_FLAGS
.EF_RISCV_FLOAT_ABI_SOFT
:
262 description
+= ", soft-float ABI"
263 if (flags
& E_FLAGS
.EF_RISCV_FLOAT_ABI
) == E_FLAGS
.EF_RISCV_FLOAT_ABI_SINGLE
:
264 description
+= ", single-float ABI"
265 if (flags
& E_FLAGS
.EF_RISCV_FLOAT_ABI
) == E_FLAGS
.EF_RISCV_FLOAT_ABI_DOUBLE
:
266 description
+= ", double-float ABI"
267 if (flags
& E_FLAGS
.EF_RISCV_FLOAT_ABI
) == E_FLAGS
.EF_RISCV_FLOAT_ABI_QUAD
:
268 description
+= ", quad-float ABI"
270 elif self
.elffile
['e_machine'] == "EM_LOONGARCH":
271 if (flags
& E_FLAGS
.EF_LOONGARCH_ABI_MODIFIER_MASK
) == E_FLAGS
.EF_LOONGARCH_ABI_SOFT_FLOAT
:
272 description
+= ", SOFT-FLOAT"
273 if (flags
& E_FLAGS
.EF_LOONGARCH_ABI_MODIFIER_MASK
) == E_FLAGS
.EF_LOONGARCH_ABI_SINGLE_FLOAT
:
274 description
+= ", SINGLE-FLOAT"
275 if (flags
& E_FLAGS
.EF_LOONGARCH_ABI_MODIFIER_MASK
) == E_FLAGS
.EF_LOONGARCH_ABI_DOUBLE_FLOAT
:
276 description
+= ", DOUBLE-FLOAT"
277 if (flags
& E_FLAGS
.EF_LOONGARCH_OBJABI_MASK
) == E_FLAGS
.EF_LOONGARCH_OBJABI_V0
:
278 description
+= ", OBJ-v0"
279 if (flags
& E_FLAGS
.EF_LOONGARCH_OBJABI_MASK
) == E_FLAGS
.EF_LOONGARCH_OBJABI_V1
:
280 description
+= ", OBJ-v1"
284 def display_program_headers(self
, show_heading
=True):
285 """ Display the ELF program headers.
286 If show_heading is True, displays the heading for this information
287 (Elf file type is...)
290 if self
.elffile
.num_segments() == 0:
291 self
._emitline
('There are no program headers in this file.')
294 elfheader
= self
.elffile
.header
296 self
._emitline
('Elf file type is %s' %
297 describe_e_type(elfheader
['e_type'], self
.elffile
))
298 self
._emitline
('Entry point is %s' %
299 self
._format
_hex
(elfheader
['e_entry']))
300 # readelf weirness - why isn't e_phoff printed as hex? (for section
302 self
._emitline
('There are %s program headers, starting at offset %s' % (
303 self
.elffile
.num_segments(), elfheader
['e_phoff']))
306 self
._emitline
('Program Headers:')
308 # Now comes the table of program headers with their attributes. Note
309 # that due to different formatting constraints of 32-bit and 64-bit
310 # addresses, there are some conditions on elfclass here.
312 # First comes the table heading
314 if self
.elffile
.elfclass
== 32:
315 self
._emitline
(' Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align')
317 self
._emitline
(' Type Offset VirtAddr PhysAddr')
318 self
._emitline
(' FileSiz MemSiz Flags Align')
322 for segment
in self
.elffile
.iter_segments():
323 self
._emit
(' %-14s ' % describe_p_type(segment
['p_type']))
325 if self
.elffile
.elfclass
== 32:
326 self
._emitline
('%s %s %s %s %s %-3s %s' % (
327 self
._format
_hex
(segment
['p_offset'], fieldsize
=6),
328 self
._format
_hex
(segment
['p_vaddr'], fullhex
=True),
329 self
._format
_hex
(segment
['p_paddr'], fullhex
=True),
330 self
._format
_hex
(segment
['p_filesz'], fieldsize
=5),
331 self
._format
_hex
(segment
['p_memsz'], fieldsize
=5),
332 describe_p_flags(segment
['p_flags']),
333 self
._format
_hex
(segment
['p_align'])))
335 self
._emitline
('%s %s %s' % (
336 self
._format
_hex
(segment
['p_offset'], fullhex
=True),
337 self
._format
_hex
(segment
['p_vaddr'], fullhex
=True),
338 self
._format
_hex
(segment
['p_paddr'], fullhex
=True)))
339 self
._emitline
(' %s %s %-3s %s' % (
340 self
._format
_hex
(segment
['p_filesz'], fullhex
=True),
341 self
._format
_hex
(segment
['p_memsz'], fullhex
=True),
342 describe_p_flags(segment
['p_flags']),
343 # lead0x set to False for p_align, to mimic readelf.
344 # No idea why the difference from 32-bit mode :-|
345 self
._format
_hex
(segment
['p_align'], lead0x
=False)))
347 if isinstance(segment
, InterpSegment
):
348 self
._emitline
(' [Requesting program interpreter: %s]' %
349 segment
.get_interp_name())
351 # Sections to segments mapping
353 if self
.elffile
.num_sections() == 0:
354 # No sections? We're done
357 self
._emitline
('\n Section to Segment mapping:')
358 self
._emitline
(' Segment Sections...')
360 for nseg
, segment
in enumerate(self
.elffile
.iter_segments()):
361 self
._emit
(' %2.2d ' % nseg
)
363 for section
in self
.elffile
.iter_sections():
364 if ( not section
.is_null() and
365 not ((section
['sh_flags'] & SH_FLAGS
.SHF_TLS
) != 0 and
366 section
['sh_type'] == 'SHT_NOBITS' and
367 segment
['p_type'] != 'PT_TLS') and
368 segment
.section_in_segment(section
)):
369 self
._emit
('%s ' % section
.name
)
373 def display_section_headers(self
, show_heading
=True):
374 """ Display the ELF section headers
376 elfheader
= self
.elffile
.header
378 self
._emitline
('There are %s section headers, starting at offset %s' % (
379 elfheader
['e_shnum'], self
._format
_hex
(elfheader
['e_shoff'])))
381 if self
.elffile
.num_sections() == 0:
382 self
._emitline
('There are no sections in this file.')
385 self
._emitline
('\nSection Header%s:' % (
386 's' if self
.elffile
.num_sections() > 1 else ''))
388 # Different formatting constraints of 32-bit and 64-bit addresses
390 if self
.elffile
.elfclass
== 32:
391 self
._emitline
(' [Nr] Name Type Addr Off Size ES Flg Lk Inf Al')
393 self
._emitline
(' [Nr] Name Type Address Offset')
394 self
._emitline
(' Size EntSize Flags Link Info Align')
398 for nsec
, section
in enumerate(self
.elffile
.iter_sections()):
399 self
._emit
(' [%2u] %-17.17s %-15.15s ' % (
400 nsec
, section
.name
, describe_sh_type(section
['sh_type'])))
402 if self
.elffile
.elfclass
== 32:
403 self
._emitline
('%s %s %s %s %3s %2s %3s %2s' % (
404 self
._format
_hex
(section
['sh_addr'], fieldsize
=8, lead0x
=False),
405 self
._format
_hex
(section
['sh_offset'], fieldsize
=6, lead0x
=False),
406 self
._format
_hex
(section
['sh_size'], fieldsize
=6, lead0x
=False),
407 self
._format
_hex
(section
['sh_entsize'], fieldsize
=2, lead0x
=False),
408 describe_sh_flags(section
['sh_flags']),
409 section
['sh_link'], section
['sh_info'],
410 section
['sh_addralign']))
412 self
._emitline
(' %s %s' % (
413 self
._format
_hex
(section
['sh_addr'], fullhex
=True, lead0x
=False),
414 self
._format
_hex
(section
['sh_offset'],
415 fieldsize
=16 if section
['sh_offset'] > 0xffffffff else 8,
417 self
._emitline
(' %s %s %3s %2s %3s %s' % (
418 self
._format
_hex
(section
['sh_size'], fullhex
=True, lead0x
=False),
419 self
._format
_hex
(section
['sh_entsize'], fullhex
=True, lead0x
=False),
420 describe_sh_flags(section
['sh_flags']),
421 section
['sh_link'], section
['sh_info'],
422 section
['sh_addralign']))
424 self
._emitline
('Key to Flags:')
425 self
._emitline
(' W (write), A (alloc), X (execute), M (merge),'
426 ' S (strings), I (info),')
427 self
._emitline
(' L (link order), O (extra OS processing required),'
428 ' G (group), T (TLS),')
429 self
._emitline
(' C (compressed), x (unknown), o (OS specific),'
432 if self
.elffile
['e_machine'] == 'EM_ARM':
433 self
._emit
('y (purecode), ')
434 self
._emitline
('p (processor specific)')
436 def display_symbol_tables(self
):
437 """ Display the symbol tables contained in the file
439 self
._init
_versioninfo
()
441 symbol_tables
= [(idx
, s
) for idx
, s
in enumerate(self
.elffile
.iter_sections())
442 if isinstance(s
, SymbolTableSection
)]
444 if not symbol_tables
and self
.elffile
.num_sections() == 0:
446 self
._emitline
('Dynamic symbol information is not available for'
447 ' displaying symbols.')
449 for section_index
, section
in symbol_tables
:
450 if not isinstance(section
, SymbolTableSection
):
453 if section
['sh_entsize'] == 0:
454 self
._emitline
("\nSymbol table '%s' has a sh_entsize of zero!" % (
458 self
._emitline
("\nSymbol table '%s' contains %d %s:" % (
460 section
.num_symbols(),
461 'entry' if section
.num_symbols() == 1 else 'entries'))
463 if self
.elffile
.elfclass
== 32:
464 self
._emitline
(' Num: Value Size Type Bind Vis Ndx Name')
466 self
._emitline
(' Num: Value Size Type Bind Vis Ndx Name')
468 for nsym
, symbol
in enumerate(section
.iter_symbols()):
470 # readelf doesn't display version info for Solaris versioning
471 if (section
['sh_type'] == 'SHT_DYNSYM' and
472 self
._versioninfo
['type'] == 'GNU'):
473 version
= self
._symbol
_version
(nsym
)
474 if (version
['name'] != symbol
.name
and
475 version
['index'] not in ('VER_NDX_LOCAL',
477 if version
['filename']:
479 version_info
= '@%(name)s (%(index)i)' % version
482 if version
['hidden']:
483 version_info
= '@%(name)s' % version
485 version_info
= '@@%(name)s' % version
487 symbol_name
= symbol
.name
488 # Print section names for STT_SECTION symbols as readelf does
489 if (symbol
['st_info']['type'] == 'STT_SECTION'
490 and symbol
['st_shndx'] < self
.elffile
.num_sections()
491 and symbol
['st_name'] == 0):
492 symbol_name
= self
.elffile
.get_section(symbol
['st_shndx']).name
494 # symbol names are truncated to 25 chars, similarly to readelf
495 self
._emitline
('%6d: %s %s %-7s %-6s %-7s %4s %.25s%s' % (
498 symbol
['st_value'], fullhex
=True, lead0x
=False),
499 "%5d" % symbol
['st_size'] if symbol
['st_size'] < 100000 else hex(symbol
['st_size']),
500 describe_symbol_type(symbol
['st_info']['type']),
501 describe_symbol_bind(symbol
['st_info']['bind']),
502 describe_symbol_other(symbol
['st_other']),
503 describe_symbol_shndx(self
._get
_symbol
_shndx
(symbol
,
506 _format_symbol_name(symbol_name
),
509 def display_dynamic_tags(self
):
510 """ Display the dynamic tags contained in the file
512 has_dynamic_sections
= False
513 for section
in self
.elffile
.iter_sections():
514 if not isinstance(section
, DynamicSection
):
517 has_dynamic_sections
= True
518 self
._emitline
("\nDynamic section at offset %s contains %d %s:" % (
519 self
._format
_hex
(section
['sh_offset']),
521 'entry' if section
.num_tags() == 1 else 'entries'))
522 self
._emitline
(" Tag Type Name/Value")
524 padding
= 20 + (8 if self
.elffile
.elfclass
== 32 else 0)
525 for tag
in section
.iter_tags():
526 if tag
.entry
.d_tag
== 'DT_NEEDED':
527 parsed
= 'Shared library: [%s]' % tag
.needed
528 elif tag
.entry
.d_tag
== 'DT_RPATH':
529 parsed
= 'Library rpath: [%s]' % tag
.rpath
530 elif tag
.entry
.d_tag
== 'DT_RUNPATH':
531 parsed
= 'Library runpath: [%s]' % tag
.runpath
532 elif tag
.entry
.d_tag
== 'DT_SONAME':
533 parsed
= 'Library soname: [%s]' % tag
.soname
534 elif tag
.entry
.d_tag
.endswith(('SZ', 'ENT')):
535 parsed
= '%i (bytes)' % tag
['d_val']
536 elif tag
.entry
.d_tag
== 'DT_FLAGS':
537 parsed
= describe_dt_flags(tag
.entry
.d_val
)
538 elif tag
.entry
.d_tag
== 'DT_FLAGS_1':
539 parsed
= 'Flags: %s' % describe_dt_flags_1(tag
.entry
.d_val
)
540 elif tag
.entry
.d_tag
.endswith(('NUM', 'COUNT')):
541 parsed
= '%i' % tag
['d_val']
542 elif tag
.entry
.d_tag
== 'DT_PLTREL':
543 s
= describe_dyn_tag(tag
.entry
.d_val
)
544 if s
.startswith('DT_'):
547 elif tag
.entry
.d_tag
== 'DT_MIPS_FLAGS':
548 parsed
= describe_rh_flags(tag
.entry
.d_val
)
549 elif tag
.entry
.d_tag
in ('DT_MIPS_SYMTABNO',
550 'DT_MIPS_LOCAL_GOTNO'):
551 parsed
= str(tag
.entry
.d_val
)
553 parsed
= '%#x' % tag
['d_val']
555 self
._emitline
(" %s %-*s %s" % (
556 self
._format
_hex
(ENUM_D_TAG
.get(tag
.entry
.d_tag
, tag
.entry
.d_tag
),
557 fullhex
=True, lead0x
=True),
559 '(%s)' % (tag
.entry
.d_tag
[3:],),
561 if not has_dynamic_sections
:
562 self
._emitline
("\nThere is no dynamic section in this file.")
564 def display_notes(self
):
565 """ Display the notes contained in the file
567 for section
in self
.elffile
.iter_sections():
568 if isinstance(section
, NoteSection
):
569 for note
in section
.iter_notes():
570 self
._emitline
("\nDisplaying notes found in: {}".format(
572 self
._emitline
(' Owner Data size Description')
573 self
._emitline
(' %s %s\t%s' % (
574 note
['n_name'].ljust(20),
575 self
._format
_hex
(note
['n_descsz'], fieldsize
=8),
576 describe_note(note
)))
578 def display_relocations(self
):
579 """ Display the relocations contained in the file
581 has_relocation_sections
= False
582 for section
in self
.elffile
.iter_sections():
583 if not isinstance(section
, RelocationSection
):
586 has_relocation_sections
= True
587 self
._emitline
("\nRelocation section '%.128s' at offset %s contains %d %s:" % (
589 self
._format
_hex
(section
['sh_offset']),
590 section
.num_relocations(),
591 'entry' if section
.num_relocations() == 1 else 'entries'))
592 if section
.is_RELA():
593 self
._emitline
(" Offset Info Type Sym. Value Sym. Name + Addend")
595 self
._emitline
(" Offset Info Type Sym.Value Sym. Name")
597 # The symbol table section pointed to in sh_link
598 symtable
= self
.elffile
.get_section(section
['sh_link'])
600 for rel
in section
.iter_relocations():
601 hexwidth
= 8 if self
.elffile
.elfclass
== 32 else 12
602 self
._emit
('%s %s %-17.17s' % (
603 self
._format
_hex
(rel
['r_offset'],
604 fieldsize
=hexwidth
, lead0x
=False),
605 self
._format
_hex
(rel
['r_info'],
606 fieldsize
=hexwidth
, lead0x
=False),
608 rel
['r_info_type'], self
.elffile
)))
610 if rel
['r_info_sym'] == 0:
611 if section
.is_RELA():
612 fieldsize
= 8 if self
.elffile
.elfclass
== 32 else 16
613 addend
= self
._format
_hex
(rel
['r_addend'], lead0x
=False)
614 self
._emit
(' %s %s' % (' ' * fieldsize
, addend
))
618 symbol
= symtable
.get_symbol(rel
['r_info_sym'])
619 # Some symbols have zero 'st_name', so instead what's used
620 # is the name of the section they point at. Truncate symbol
621 # names (excluding version info) to 22 chars, similarly to
623 if symbol
['st_name'] == 0:
624 symsecidx
= self
._get
_symbol
_shndx
(symbol
,
627 symsec
= self
.elffile
.get_section(symsecidx
)
628 symbol_name
= symsec
.name
631 symbol_name
= symbol
.name
632 version
= self
._symbol
_version
(rel
['r_info_sym'])
633 version
= (version
['name']
634 if version
and version
['name'] else '')
635 symbol_name
= '%.22s' % symbol_name
637 symbol_name
+= '@' + version
639 self
._emit
(' %s %s' % (
642 fullhex
=True, lead0x
=False),
643 _format_symbol_name(symbol_name
)))
644 if section
.is_RELA():
645 self
._emit
(' %s %x' % (
646 '+' if rel
['r_addend'] >= 0 else '-',
647 abs(rel
['r_addend'])))
650 # Emit the two additional relocation types for ELF64 MIPS
652 if (self
.elffile
.elfclass
== 64 and
653 self
.elffile
['e_machine'] == 'EM_MIPS'):
655 rtype
= rel
['r_info_type%s' % i
]
656 self
._emit
(' Type%s: %s' % (
658 describe_reloc_type(rtype
, self
.elffile
)))
661 if not has_relocation_sections
:
662 self
._emitline
('\nThere are no relocations in this file.')
664 def display_arm_unwind(self
):
665 if not self
.elffile
.has_ehabi_info():
666 self
._emitline
('There are no .ARM.idx sections in this file.')
668 for ehabi_info
in self
.elffile
.get_ehabi_infos():
669 # Unwind section '.ARM.exidx' at offset 0x203e8 contains 1009 entries:
670 self
._emitline
("\nUnwind section '%s' at offset 0x%x contains %d %s" % (
671 ehabi_info
.section_name(),
672 ehabi_info
.section_offset(),
673 ehabi_info
.num_entry(),
674 'entry' if ehabi_info
.num_entry() == 1 else 'entries'))
676 for i
in range(ehabi_info
.num_entry()):
677 entry
= ehabi_info
.get_entry(i
)
679 self
._emitline
("Entry %d:" % i
)
680 if isinstance(entry
, CorruptEHABIEntry
):
681 self
._emitline
(" [corrupt] %s" % entry
.reason
)
683 self
._emit
(" Function offset 0x%x: " % entry
.function_offset
)
684 if isinstance(entry
, CannotUnwindEHABIEntry
):
685 self
._emitline
("[cantunwind]")
687 elif entry
.eh_table_offset
:
688 self
._emitline
("@0x%x" % entry
.eh_table_offset
)
690 self
._emitline
("Compact (inline)")
691 if isinstance(entry
, GenericEHABIEntry
):
692 self
._emitline
(" Personality: 0x%x" % entry
.personality
)
694 self
._emitline
(" Compact model index: %d" % entry
.personality
)
695 for mnemonic_item
in entry
.mnmemonic_array():
697 self
._emitline
(mnemonic_item
)
699 def display_version_info(self
):
700 """ Display the version info contained in the file
702 self
._init
_versioninfo
()
704 if not self
._versioninfo
['type']:
705 self
._emitline
("\nNo version information found in this file.")
708 for section
in self
.elffile
.iter_sections():
709 if isinstance(section
, GNUVerSymSection
):
710 self
._print
_version
_section
_header
(section
, 'Version symbols')
711 num_symbols
= section
.num_symbols()
713 # Symbol version info are printed four by four entries
714 for idx_by_4
in range(0, num_symbols
, 4):
716 self
._emit
(' %03x:' % idx_by_4
)
718 for idx
in range(idx_by_4
, min(idx_by_4
+ 4, num_symbols
)):
720 symbol_version
= self
._symbol
_version
(idx
)
721 if symbol_version
['index'] == 'VER_NDX_LOCAL':
723 version_name
= '(*local*)'
724 elif symbol_version
['index'] == 'VER_NDX_GLOBAL':
726 version_name
= '(*global*)'
728 version_index
= symbol_version
['index']
729 version_name
= '(%(name)s)' % symbol_version
731 visibility
= 'h' if symbol_version
['hidden'] else ' '
733 self
._emit
('%4x%s%-13s' % (
734 version_index
, visibility
, version_name
))
738 elif isinstance(section
, GNUVerDefSection
):
739 self
._print
_version
_section
_header
(
740 section
, 'Version definition', indent
=2)
743 for verdef
, verdaux_iter
in section
.iter_versions():
744 verdaux
= next(verdaux_iter
)
747 if verdef
['vd_flags']:
748 flags
= describe_ver_flags(verdef
['vd_flags'])
749 # Mimic exactly the readelf output
754 self
._emitline
(' %s: Rev: %i Flags: %s Index: %i'
755 ' Cnt: %i Name: %s' % (
756 self
._format
_hex
(offset
, fieldsize
=6,
758 verdef
['vd_version'], flags
, verdef
['vd_ndx'],
759 verdef
['vd_cnt'], name
))
762 offset
+ verdef
['vd_aux'] + verdaux
['vda_next'])
763 for idx
, verdaux
in enumerate(verdaux_iter
, start
=1):
764 self
._emitline
(' %s: Parent %i: %s' %
765 (self
._format
_hex
(verdaux_offset
, fieldsize
=4),
767 verdaux_offset
+= verdaux
['vda_next']
769 offset
+= verdef
['vd_next']
771 elif isinstance(section
, GNUVerNeedSection
):
772 self
._print
_version
_section
_header
(section
, 'Version needs')
775 for verneed
, verneed_iter
in section
.iter_versions():
777 self
._emitline
(' %s: Version: %i File: %s Cnt: %i' % (
778 self
._format
_hex
(offset
, fieldsize
=6,
780 verneed
['vn_version'], verneed
.name
,
783 vernaux_offset
= offset
+ verneed
['vn_aux']
784 for idx
, vernaux
in enumerate(verneed_iter
, start
=1):
785 if vernaux
['vna_flags']:
786 flags
= describe_ver_flags(vernaux
['vna_flags'])
787 # Mimic exactly the readelf output
793 ' %s: Name: %s Flags: %s Version: %i' % (
794 self
._format
_hex
(vernaux_offset
, fieldsize
=4),
796 vernaux
['vna_other']))
798 vernaux_offset
+= vernaux
['vna_next']
800 offset
+= verneed
['vn_next']
802 def display_arch_specific(self
):
803 """ Display the architecture-specific info contained in the file.
805 if self
.elffile
['e_machine'] == 'EM_ARM':
806 self
._display
_arch
_specific
_arm
()
807 elif self
.elffile
['e_machine'] == 'EM_RISCV':
808 self
._display
_arch
_specific
_riscv
()
810 def display_hex_dump(self
, section_spec
):
811 """ Display a hex dump of a section. section_spec is either a section
814 section
= self
._section
_from
_spec
(section_spec
)
816 # readelf prints the warning to stderr. Even though stderrs are not compared
817 # in tests, we comply with that behavior.
818 sys
.stderr
.write('readelf: Warning: Section \'%s\' was not dumped because it does not exist!\n' % (
821 if section
['sh_type'] == 'SHT_NOBITS':
822 self
._emitline
("\nSection '%s' has no data to dump." % (
826 self
._emitline
("\nHex dump of section '%s':" % section
.name
)
827 self
._note
_relocs
_for
_section
(section
)
828 addr
= section
['sh_addr']
829 data
= section
.data()
832 while dataptr
< len(data
):
833 bytesleft
= len(data
) - dataptr
834 # chunks of 16 bytes per line
835 linebytes
= 16 if bytesleft
> 16 else bytesleft
837 self
._emit
(' %s ' % self
._format
_hex
(addr
, fieldsize
=8))
840 self
._emit
('%2.2x' % data
[dataptr
+ i
])
846 for i
in range(linebytes
):
847 c
= data
[dataptr
+ i
: dataptr
+ i
+ 1]
848 if c
[0] >= 32 and c
[0] < 0x7f:
849 self
._emit
(bytes2str(c
))
851 self
._emit
(bytes2str(b
'.'))
859 def display_string_dump(self
, section_spec
):
860 """ Display a strings dump of a section. section_spec is either a
861 section number or a name.
863 section
= self
._section
_from
_spec
(section_spec
)
865 # readelf prints the warning to stderr. Even though stderrs are not compared
866 # in tests, we comply with that behavior.
867 sys
.stderr
.write('readelf.py: Warning: Section \'%s\' was not dumped because it does not exist!\n' % (
870 if section
['sh_type'] == 'SHT_NOBITS':
871 self
._emitline
("\nSection '%s' has no data to dump." % (
875 self
._emitline
("\nString dump of section '%s':" % section
.name
)
878 data
= section
.data()
881 while dataptr
< len(data
):
882 while ( dataptr
< len(data
) and
883 not (32 <= data
[dataptr
] <= 127)):
886 if dataptr
>= len(data
):
890 while endptr
< len(data
) and data
[endptr
] != 0:
894 self
._emitline
(' [%6x] %s' % (
895 dataptr
, bytes2str(data
[dataptr
:endptr
])))
900 self
._emitline
(' No strings found in this section.')
904 def display_debug_dump(self
, dump_what
):
905 """ Dump a DWARF section
907 self
._init
_dwarfinfo
()
908 if self
._dwarfinfo
is None:
911 set_global_machine_arch(self
.elffile
.get_machine_arch())
913 if dump_what
== 'info':
914 self
._dump
_debug
_info
()
915 elif dump_what
== 'decodedline':
916 self
._dump
_debug
_line
_programs
()
917 elif dump_what
== 'frames':
918 self
._dump
_debug
_frames
()
919 elif dump_what
== 'frames-interp':
920 self
._dump
_debug
_frames
_interp
()
921 elif dump_what
== 'aranges':
922 self
._dump
_debug
_aranges
()
923 elif dump_what
in { 'pubtypes', 'pubnames' }:
924 self
._dump
_debug
_namelut
(dump_what
)
925 elif dump_what
== 'loc':
926 self
._dump
_debug
_locations
()
927 elif dump_what
== 'Ranges':
928 self
._dump
_debug
_ranges
()
930 self
._emitline
('debug dump not yet supported for "%s"' % dump_what
)
932 def _format_hex(self
, addr
, fieldsize
=None, fullhex
=False, lead0x
=True,
934 """ Format an address into a hexadecimal string.
937 Size of the hexadecimal field (with leading zeros to fit the
938 address into. For example with fieldsize=8, the format will
940 If None, the minimal required field size will be used.
943 If True, override fieldsize to set it to the maximal size
944 needed for the elfclass
947 If True, leading 0x is added
950 If True, override lead0x to emulate the alternate
951 hexadecimal form specified in format string with the #
952 character: only non-zero values are prefixed with 0x.
953 This form is used by readelf.
960 if fieldsize
is not None:
963 s
= '0x' if lead0x
else ''
965 fieldsize
= 8 if self
.elffile
.elfclass
== 32 else 16
966 if fieldsize
is None:
969 field
= '%' + '0%sx' % fieldsize
970 return s
+ field
% addr
972 def _print_version_section_header(self
, version_section
, name
, lead0x
=True,
974 """ Print a section header of one version related section (versym,
975 verneed or verdef) with some options to accomodate readelf
976 little differences between each header (e.g. indentation
979 if hasattr(version_section
, 'num_versions'):
980 num_entries
= version_section
.num_versions()
982 num_entries
= version_section
.num_symbols()
984 self
._emitline
("\n%s section '%s' contains %d %s:" % (
985 name
, version_section
.name
, num_entries
,
986 'entry' if num_entries
== 1 else 'entries'))
987 self
._emitline
('%sAddr: %s Offset: %s Link: %i (%s)' % (
990 version_section
['sh_addr'], fieldsize
=16, lead0x
=lead0x
),
992 version_section
['sh_offset'], fieldsize
=8, lead0x
=True),
993 version_section
['sh_link'],
994 self
.elffile
.get_section(version_section
['sh_link']).name
998 def _init_versioninfo(self
):
999 """ Search and initialize informations about version related sections
1000 and the kind of versioning used (GNU or Solaris).
1002 if self
._versioninfo
is not None:
1005 self
._versioninfo
= {'versym': None, 'verdef': None,
1006 'verneed': None, 'type': None}
1008 for section
in self
.elffile
.iter_sections():
1009 if isinstance(section
, GNUVerSymSection
):
1010 self
._versioninfo
['versym'] = section
1011 elif isinstance(section
, GNUVerDefSection
):
1012 self
._versioninfo
['verdef'] = section
1013 elif isinstance(section
, GNUVerNeedSection
):
1014 self
._versioninfo
['verneed'] = section
1015 elif isinstance(section
, DynamicSection
):
1016 for tag
in section
.iter_tags():
1017 if tag
['d_tag'] == 'DT_VERSYM':
1018 self
._versioninfo
['type'] = 'GNU'
1021 if not self
._versioninfo
['type'] and (
1022 self
._versioninfo
['verneed'] or self
._versioninfo
['verdef']):
1023 self
._versioninfo
['type'] = 'Solaris'
1025 def _symbol_version(self
, nsym
):
1026 """ Return a dict containing information on the
1027 or None if no version information is available
1029 self
._init
_versioninfo
()
1031 symbol_version
= dict.fromkeys(('index', 'name', 'filename', 'hidden'))
1033 if (not self
._versioninfo
['versym'] or
1034 nsym
>= self
._versioninfo
['versym'].num_symbols()):
1037 symbol
= self
._versioninfo
['versym'].get_symbol(nsym
)
1038 index
= symbol
.entry
['ndx']
1039 if not index
in ('VER_NDX_LOCAL', 'VER_NDX_GLOBAL'):
1042 if self
._versioninfo
['type'] == 'GNU':
1043 # In GNU versioning mode, the highest bit is used to
1044 # store whether the symbol is hidden or not
1047 symbol_version
['hidden'] = True
1049 if (self
._versioninfo
['verdef'] and
1050 index
<= self
._versioninfo
['verdef'].num_versions()):
1052 self
._versioninfo
['verdef'].get_version(index
)
1053 symbol_version
['name'] = next(verdaux_iter
).name
1055 verneed
, vernaux
= \
1056 self
._versioninfo
['verneed'].get_version(index
)
1057 symbol_version
['name'] = vernaux
.name
1058 symbol_version
['filename'] = verneed
.name
1060 symbol_version
['index'] = index
1061 return symbol_version
1063 def _section_from_spec(self
, spec
):
1064 """ Retrieve a section given a "spec" (either number or name).
1065 Return None if no such section exists in the file.
1069 if num
< self
.elffile
.num_sections():
1070 return self
.elffile
.get_section(num
)
1074 # Not a number. Must be a name then
1075 return self
.elffile
.get_section_by_name(spec
)
1077 def _get_symbol_shndx(self
, symbol
, symbol_index
, symtab_index
):
1078 """ Get the index into the section header table for the "symbol"
1079 at "symbol_index" located in the symbol table with section index
1082 symbol_shndx
= symbol
['st_shndx']
1083 if symbol_shndx
!= SHN_INDICES
.SHN_XINDEX
:
1086 # Check for or lazily construct index section mapping (symbol table
1087 # index -> corresponding symbol table index section object)
1088 if self
._shndx
_sections
is None:
1089 self
._shndx
_sections
= {sec
.symboltable
: sec
for sec
in self
.elffile
.iter_sections()
1090 if isinstance(sec
, SymbolTableIndexSection
)}
1091 return self
._shndx
_sections
[symtab_index
].get_section_index(symbol_index
)
1093 def _note_relocs_for_section(self
, section
):
1094 """ If there are relocation sections pointing to the givne section,
1095 emit a note about it.
1097 for relsec
in self
.elffile
.iter_sections():
1098 if isinstance(relsec
, RelocationSection
):
1099 info_idx
= relsec
['sh_info']
1100 if self
.elffile
.get_section(info_idx
) == section
:
1101 self
._emitline
(' Note: This section has relocations against it, but these have NOT been applied to this dump.')
1104 def _init_dwarfinfo(self
):
1105 """ Initialize the DWARF info contained in the file and assign it to
1107 Leave self._dwarfinfo at None if no DWARF info was found in the file
1109 if self
._dwarfinfo
is not None:
1112 if self
.elffile
.has_dwarf_info():
1113 self
._dwarfinfo
= self
.elffile
.get_dwarf_info()
1115 self
._dwarfinfo
= None
1117 def _dump_debug_info(self
):
1118 """ Dump the debugging info section.
1120 if not self
._dwarfinfo
.has_debug_info
:
1122 self
._emitline
('Contents of the %s section:\n' % self
._dwarfinfo
.debug_info_sec
.name
)
1124 # Offset of the .debug_info section in the stream
1125 section_offset
= self
._dwarfinfo
.debug_info_sec
.global_offset
1127 for cu
in self
._dwarfinfo
.iter_CUs():
1128 self
._emitline
(' Compilation Unit @ offset %s:' %
1129 self
._format
_hex
(cu
.cu_offset
, alternate
=True))
1130 self
._emitline
(' Length: %s (%s)' % (
1131 self
._format
_hex
(cu
['unit_length']),
1132 '%s-bit' % cu
.dwarf_format()))
1133 self
._emitline
(' Version: %s' % cu
['version'])
1134 if cu
['version'] >= 5:
1135 if cu
.header
.get("unit_type", ''):
1136 unit_type
= cu
.header
.unit_type
1137 self
._emitline
(' Unit Type: %s (%d)' % (
1138 unit_type
, ENUM_DW_UT
.get(cu
.header
.unit_type
, 0)))
1139 self
._emitline
(' Abbrev Offset: %s' % (
1140 self
._format
_hex
(cu
['debug_abbrev_offset'], alternate
=True)))
1141 self
._emitline
(' Pointer Size: %s' % cu
['address_size'])
1142 if unit_type
in ('DW_UT_skeleton', 'DW_UT_split_compile'):
1143 self
._emitline
(' Dwo id: %s' % cu
['dwo_id'])
1144 elif unit_type
in ('DW_UT_type', 'DW_UT_split_type'):
1145 self
._emitline
(' Signature: 0x%x' % cu
['type_signature'])
1146 self
._emitline
(' Type Offset: 0x%x' % cu
['type_offset'])
1148 self
._emitline
(' Abbrev Offset: %s' % (
1149 self
._format
_hex
(cu
['debug_abbrev_offset'], alternate
=True))),
1150 self
._emitline
(' Pointer Size: %s' % cu
['address_size'])
1152 # The nesting depth of each DIE within the tree of DIEs must be
1153 # displayed. To implement this, a counter is incremented each time
1154 # the current DIE has children, and decremented when a null die is
1155 # encountered. Due to the way the DIE tree is serialized, this will
1156 # correctly reflect the nesting depth
1159 current_function
= None
1160 for die
in cu
.iter_DIEs():
1161 if die
.tag
== 'DW_TAG_subprogram':
1162 current_function
= die
1163 self
._emitline
(' <%s><%x>: Abbrev Number: %s%s' % (
1167 (' (%s)' % die
.tag
) if not die
.is_null() else ''))
1172 for attr
in die
.attributes
.values():
1174 # Unknown attribute values are passed-through as integers
1175 if isinstance(name
, int):
1176 name
= 'Unknown AT value: %x' % name
1178 attr_desc
= describe_attr_value(attr
, die
, section_offset
)
1180 if 'DW_OP_fbreg' in attr_desc
and current_function
and not 'DW_AT_frame_base' in current_function
.attributes
:
1181 postfix
= ' [without dw_at_frame_base]'
1185 self
._emitline
(' <%x> %-18s: %s%s' % (
1191 if die
.has_children
:
1196 def _dump_debug_line_programs(self
):
1197 """ Dump the (decoded) line programs from .debug_line
1198 The programs are dumped in the order of the CUs they belong to.
1200 if not self
._dwarfinfo
.has_debug_info
:
1202 self
._emitline
('Contents of the %s section:' % self
._dwarfinfo
.debug_line_sec
.name
)
1204 lineprogram_list
= []
1206 for cu
in self
._dwarfinfo
.iter_CUs():
1207 # Avoid dumping same lineprogram multiple times
1208 lineprogram
= self
._dwarfinfo
.line_program_for_CU(cu
)
1210 if lineprogram
in lineprogram_list
:
1213 lineprogram_list
.append(lineprogram
)
1214 ver5
= lineprogram
.header
.version
>= 5
1216 cu_filename
= bytes2str(lineprogram
['file_entry'][0].name
)
1217 if len(lineprogram
['include_directory']) > 0:
1218 # GNU readelf 2.38 only outputs directory in wide mode
1219 self
._emitline
('%s:' % cu_filename
)
1221 self
._emitline
('CU: %s:' % cu_filename
)
1223 self
._emitline
('File name Line number Starting address Stmt')
1224 # GNU readelf has a View column that we don't try to replicate
1225 # The autotest has logic in place to ignore that
1227 # Print each state's file, line and address information. For some
1228 # instructions other output is needed to be compatible with
1230 for entry
in lineprogram
.get_entries():
1233 # Special handling for commands that don't set a new state
1234 if entry
.command
== DW_LNS_set_file
:
1235 file_entry
= lineprogram
['file_entry'][entry
.args
[0] - 1]
1236 if file_entry
.dir_index
== 0:
1238 self
._emitline
('\n./%s:[++]' % (
1239 bytes2str(file_entry
.name
)))
1241 self
._emitline
('\n%s/%s:' % (
1242 bytes2str(lineprogram
['include_directory'][file_entry
.dir_index
- 1]),
1243 bytes2str(file_entry
.name
)))
1244 elif entry
.command
== DW_LNE_define_file
:
1245 self
._emitline
('%s:' % (
1246 bytes2str(lineprogram
['include_directory'][entry
.args
[0].dir_index
])))
1247 elif lineprogram
['version'] < 4 or self
.elffile
['e_machine'] == 'EM_PPC64':
1248 self
._emitline
('%-35s %11s %18s %s' % (
1249 bytes2str(lineprogram
['file_entry'][state
.file - 1].name
),
1250 state
.line
if not state
.end_sequence
else '-',
1251 '0' if state
.address
== 0 else self
._format
_hex
(state
.address
),
1252 'x' if state
.is_stmt
and not state
.end_sequence
else ''))
1254 # In readelf, on non-VLIW machines there is no op_index postfix after address.
1255 # It used to be unconditional.
1256 self
._emitline
('%-35s %s %18s%s %s' % (
1257 bytes2str(lineprogram
['file_entry'][state
.file - 1].name
),
1258 "%11d" % (state
.line
,) if not state
.end_sequence
else '-',
1259 '0' if state
.address
== 0 else self
._format
_hex
(state
.address
),
1260 '' if lineprogram
.header
.maximum_operations_per_instruction
== 1 else '[%d]' % (state
.op_index
,),
1261 'x' if state
.is_stmt
and not state
.end_sequence
else ''))
1262 if entry
.command
== DW_LNS_copy
:
1263 # Another readelf oddity...
1266 def _dump_frames_info(self
, section
, cfi_entries
):
1267 """ Dump the raw call frame info in a section.
1269 `section` is the Section instance that contains the call frame info
1270 while `cfi_entries` must be an iterable that yields the sequence of
1271 CIE or FDE instances.
1273 self
._emitline
('Contents of the %s section:' % section
.name
)
1275 for entry
in cfi_entries
:
1276 if isinstance(entry
, CIE
):
1277 self
._emitline
('\n%08x %s %s CIE' % (
1279 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1280 self
._format
_hex
(entry
['CIE_id'], fieldsize
=8, lead0x
=False)))
1281 self
._emitline
(' Version: %d' % entry
['version'])
1282 self
._emitline
(' Augmentation: "%s"' % bytes2str(entry
['augmentation']))
1283 self
._emitline
(' Code alignment factor: %u' % entry
['code_alignment_factor'])
1284 self
._emitline
(' Data alignment factor: %d' % entry
['data_alignment_factor'])
1285 self
._emitline
(' Return address column: %d' % entry
['return_address_register'])
1286 if entry
.augmentation_bytes
:
1287 self
._emitline
(' Augmentation data: {}'.format(' '.join(
1288 '{:02x}'.format(ord(b
))
1289 for b
in iterbytes(entry
.augmentation_bytes
)
1293 elif isinstance(entry
, FDE
):
1294 self
._emitline
('\n%08x %s %s FDE cie=%08x pc=%s..%s' % (
1296 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1297 self
._format
_hex
(entry
['CIE_pointer'], fieldsize
=8, lead0x
=False),
1299 self
._format
_hex
(entry
['initial_location'], fullhex
=True, lead0x
=False),
1301 entry
['initial_location'] + entry
['address_range'],
1302 fullhex
=True, lead0x
=False)))
1303 if entry
.augmentation_bytes
:
1304 self
._emitline
(' Augmentation data: {}'.format(' '.join(
1305 '{:02x}'.format(ord(b
))
1306 for b
in iterbytes(entry
.augmentation_bytes
)
1309 else: # ZERO terminator
1310 assert isinstance(entry
, ZERO
)
1311 self
._emitline
('\n%08x ZERO terminator' % entry
.offset
)
1314 self
._emit
(describe_CFI_instructions(entry
))
1317 def _dump_debug_frames(self
):
1318 """ Dump the raw frame info from .debug_frame and .eh_frame sections.
1320 if self
._dwarfinfo
.has_EH_CFI():
1321 self
._dump
_frames
_info
(
1322 self
._dwarfinfo
.eh_frame_sec
,
1323 self
._dwarfinfo
.EH_CFI_entries())
1326 if self
._dwarfinfo
.has_CFI():
1327 self
._dump
_frames
_info
(
1328 self
._dwarfinfo
.debug_frame_sec
,
1329 self
._dwarfinfo
.CFI_entries())
1331 def _dump_debug_namelut(self
, what
):
1333 Dump the debug pubnames section.
1335 if what
== 'pubnames':
1336 namelut
= self
._dwarfinfo
.get_pubnames()
1337 section
= self
._dwarfinfo
.debug_pubnames_sec
1339 namelut
= self
._dwarfinfo
.get_pubtypes()
1340 section
= self
._dwarfinfo
.debug_pubtypes_sec
1342 # readelf prints nothing if the section is not present.
1343 if namelut
is None or len(namelut
) == 0:
1346 self
._emitline
('Contents of the %s section:' % section
.name
)
1349 cu_headers
= namelut
.get_cu_headers()
1351 # go over CU-by-CU first and item-by-item next.
1352 for (cu_hdr
, (cu_ofs
, items
)) in izip(cu_headers
, itertools
.groupby(
1353 namelut
.items(), key
= lambda x
: x
[1].cu_ofs
)):
1355 self
._emitline
(' Length: %d' % cu_hdr
.unit_length
)
1356 self
._emitline
(' Version: %d' % cu_hdr
.version
)
1357 self
._emitline
(' Offset into .debug_info section: 0x%x' % cu_hdr
.debug_info_offset
)
1358 self
._emitline
(' Size of area in .debug_info section: %d' % cu_hdr
.debug_info_length
)
1360 self
._emitline
(' Offset Name')
1362 self
._emitline
(' %x %s' % (item
[1].die_ofs
- cu_ofs
, item
[0]))
1365 def _dump_debug_aranges(self
):
1366 """ Dump the aranges table
1368 aranges_table
= self
._dwarfinfo
.get_aranges()
1369 if aranges_table
== None:
1371 # Seems redundant, but we need to get the unsorted set of entries
1372 # to match system readelf.
1373 # Also, sometimes there are blank sections in aranges, but readelf
1374 # dumps them, so we should too.
1375 unordered_entries
= aranges_table
._get
_entries
(need_empty
=True)
1377 if len(unordered_entries
) == 0:
1379 self
._emitline
("Section '.debug_aranges' has no debugging data.")
1382 self
._emitline
('Contents of the %s section:' % self
._dwarfinfo
.debug_aranges_sec
.name
)
1385 for entry
in unordered_entries
:
1386 if prev_offset
!= entry
.info_offset
:
1387 if entry
!= unordered_entries
[0]:
1388 self
._emitline
(' %s %s' % (
1389 self
._format
_hex
(0, fullhex
=True, lead0x
=False),
1390 self
._format
_hex
(0, fullhex
=True, lead0x
=False)))
1391 self
._emitline
(' Length: %d' % (entry
.unit_length
))
1392 self
._emitline
(' Version: %d' % (entry
.version
))
1393 self
._emitline
(' Offset into .debug_info: 0x%x' % (entry
.info_offset
))
1394 self
._emitline
(' Pointer Size: %d' % (entry
.address_size
))
1395 self
._emitline
(' Segment Size: %d' % (entry
.segment_size
))
1397 self
._emitline
(' Address Length')
1398 if entry
.begin_addr
!= 0 or entry
.length
!= 0:
1399 self
._emitline
(' %s %s' % (
1400 self
._format
_hex
(entry
.begin_addr
, fullhex
=True, lead0x
=False),
1401 self
._format
_hex
(entry
.length
, fullhex
=True, lead0x
=False)))
1402 prev_offset
= entry
.info_offset
1403 self
._emitline
(' %s %s' % (
1404 self
._format
_hex
(0, fullhex
=True, lead0x
=False),
1405 self
._format
_hex
(0, fullhex
=True, lead0x
=False)))
1407 def _dump_frames_interp_info(self
, section
, cfi_entries
):
1408 """ Dump interpreted (decoded) frame information in a section.
1410 `section` is the Section instance that contains the call frame info
1411 while `cfi_entries` must be an iterable that yields the sequence of
1412 CIE or FDE instances.
1414 self
._emitline
('Contents of the %s section:' % section
.name
)
1416 for entry
in cfi_entries
:
1417 if isinstance(entry
, CIE
):
1418 self
._emitline
('\n%08x %s %s CIE "%s" cf=%d df=%d ra=%d' % (
1420 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1421 self
._format
_hex
(entry
['CIE_id'], fieldsize
=8, lead0x
=False),
1422 bytes2str(entry
['augmentation']),
1423 entry
['code_alignment_factor'],
1424 entry
['data_alignment_factor'],
1425 entry
['return_address_register']))
1426 ra_regnum
= entry
['return_address_register']
1428 elif isinstance(entry
, FDE
):
1429 self
._emitline
('\n%08x %s %s FDE cie=%08x pc=%s..%s' % (
1431 self
._format
_hex
(entry
['length'], fullhex
=True, lead0x
=False),
1432 self
._format
_hex
(entry
['CIE_pointer'], fieldsize
=8, lead0x
=False),
1434 self
._format
_hex
(entry
['initial_location'], fullhex
=True, lead0x
=False),
1435 self
._format
_hex
(entry
['initial_location'] + entry
['address_range'],
1436 fullhex
=True, lead0x
=False)))
1437 ra_regnum
= entry
.cie
['return_address_register']
1439 # If the FDE brings adds no unwinding information compared to
1440 # its CIE, omit its table.
1441 if (len(entry
.get_decoded().table
) ==
1442 len(entry
.cie
.get_decoded().table
)):
1445 else: # ZERO terminator
1446 assert isinstance(entry
, ZERO
)
1447 self
._emitline
('\n%08x ZERO terminator' % entry
.offset
)
1451 decoded_table
= entry
.get_decoded()
1452 if len(decoded_table
.table
) == 0:
1455 # Print the heading row for the decoded table
1457 self
._emit
(' ' if entry
.structs
.address_size
== 4 else ' ')
1460 # Look at the registers the decoded table describes.
1461 # We build reg_order here to match readelf's order. In particular,
1462 # registers are sorted by their number, so that the register
1463 # matching ra_regnum is usually listed last with a special heading.
1464 # (LoongArch is a notable exception in that its return register's
1465 # DWARF register number is not greater than other GPRs.)
1466 decoded_table
= entry
.get_decoded()
1467 reg_order
= sorted(decoded_table
.reg_order
)
1468 if len(decoded_table
.reg_order
):
1469 # Headings for the registers
1470 for regnum
in reg_order
:
1471 if regnum
== ra_regnum
:
1474 self
._emit
('%-6s' % describe_reg_name(regnum
))
1477 for line
in decoded_table
.table
:
1478 self
._emit
(self
._format
_hex
(
1479 line
['pc'], fullhex
=True, lead0x
=False))
1481 if line
['cfa'] is not None:
1482 s
= describe_CFI_CFA_rule(line
['cfa'])
1485 self
._emit
(' %-9s' % s
)
1487 for regnum
in reg_order
:
1489 s
= describe_CFI_register_rule(line
[regnum
])
1492 self
._emit
('%-6s' % s
)
1496 def _dump_debug_frames_interp(self
):
1497 """ Dump the interpreted (decoded) frame information from .debug_frame
1498 and .eh_frame sections.
1500 if self
._dwarfinfo
.has_EH_CFI():
1501 self
._dump
_frames
_interp
_info
(
1502 self
._dwarfinfo
.eh_frame_sec
,
1503 self
._dwarfinfo
.EH_CFI_entries())
1506 if self
._dwarfinfo
.has_CFI():
1507 self
._dump
_frames
_interp
_info
(
1508 self
._dwarfinfo
.debug_frame_sec
,
1509 self
._dwarfinfo
.CFI_entries())
1511 def _dump_debug_locations(self
):
1512 """ Dump the location lists from .debug_loc/.debug_loclists section
1514 di
= self
._dwarfinfo
1515 loc_lists_sec
= di
.location_lists()
1516 if not loc_lists_sec
: # No locations section - readelf outputs nothing
1519 if isinstance(loc_lists_sec
, LocationListsPair
):
1520 self
._dump
_debug
_locsection
(di
, loc_lists_sec
._loc
)
1521 self
._dump
_debug
_locsection
(di
, loc_lists_sec
._loclists
)
1523 self
._dump
_debug
_locsection
(di
, loc_lists_sec
)
1525 def _dump_debug_locsection(self
, di
, loc_lists_sec
):
1526 """ Dump the location lists from .debug_loc/.debug_loclists section
1528 ver5
= loc_lists_sec
.version
>= 5
1529 section_name
= (di
.debug_loclists_sec
if ver5
else di
.debug_loc_sec
).name
1531 # To dump a location list, one needs to know the CU.
1532 # Scroll through DIEs once, list the known location list offsets.
1533 # Don't need this CU/DIE scan if all entries are absolute or prefixed by base,
1534 # but let's not optimize for that yet.
1535 cu_map
= dict() # Loc list offset => CU
1536 for cu
in di
.iter_CUs():
1537 for die
in cu
.iter_DIEs():
1538 for key
in die
.attributes
:
1539 attr
= die
.attributes
[key
]
1540 if (LocationParser
.attribute_has_location(attr
, cu
['version']) and
1541 LocationParser
._attribute
_has
_loc
_list
(attr
, cu
['version'])):
1542 cu_map
[attr
.value
] = cu
1544 addr_size
= di
.config
.default_address_size
# In bytes, 4 or 8
1545 addr_width
= addr_size
* 2 # In hex digits, 8 or 16
1546 line_template
= " %%08x %%0%dx %%0%dx %%s%%s" % (addr_width
, addr_width
)
1548 loc_lists
= list(loc_lists_sec
.iter_location_lists())
1549 if len(loc_lists
) == 0:
1550 # Present but empty locations section - readelf outputs a message
1551 self
._emitline
("\nSection '%s' has no debugging data." % (section_name
,))
1554 self
._emitline
('Contents of the %s section:\n' % (section_name
,))
1555 self
._emitline
(' Offset Begin End Expression')
1556 for loc_list
in loc_lists
:
1557 self
._dump
_loclist
(loc_list
, line_template
, cu_map
)
1559 def _dump_loclist(self
, loc_list
, line_template
, cu_map
):
1565 for entry
in loc_list
:
1566 if isinstance(entry
, LocationViewPair
):
1567 has_views
= in_views
= True
1568 # The "v" before address is conditional in binutils, haven't figured out how
1569 self
._emitline
(" %08x v%015x v%015x location view pair" % (entry
.entry_offset
, entry
.begin
, entry
.end
))
1575 # Readelf quirk: indexed loclists don't show the real base IP
1579 cu
= cu_map
.get(entry
.entry_offset
, False)
1581 raise ValueError("Location list can't be tracked to a CU")
1583 if isinstance(entry
, LocationEntry
):
1584 if base_ip
is None and not entry
.is_absolute
:
1585 base_ip
= _get_cu_base(cu
)
1587 begin_offset
= (0 if entry
.is_absolute
else base_ip
) + entry
.begin_offset
1588 end_offset
= (0 if entry
.is_absolute
else base_ip
) + entry
.end_offset
1589 expr
= describe_DWARF_expr(entry
.loc_expr
, cu
.structs
, cu
.cu_offset
)
1591 view
= loc_list
[loc_entry_count
]
1592 postfix
= ' (start == end)' if entry
.begin_offset
== entry
.end_offset
and view
.begin
== view
.end
else ''
1593 self
._emitline
(' %08x v%015x v%015x views at %08x for:' %(
1598 self
._emitline
(' %016x %016x %s%s' %(
1603 loc_entry_count
+= 1
1605 postfix
= ' (start == end)' if entry
.begin_offset
== entry
.end_offset
else ''
1606 self
._emitline
(line_template
% (
1612 elif isinstance(entry
, LocBaseAddressEntry
):
1613 base_ip
= entry
.base_address
1614 self
._emitline
(" %08x %016x (base address)" % (entry
.entry_offset
, entry
.base_address
))
1616 # Pyelftools doesn't store the terminating entry,
1617 # but readelf emits its offset, so this should too.
1619 self
._emitline
(" %08x <End of list>" % (last
.entry_offset
+ last
.entry_length
))
1621 def _dump_debug_ranges(self
):
1622 # TODO: GNU readelf format doesn't need entry_length?
1623 di
= self
._dwarfinfo
1624 range_lists_sec
= di
.range_lists()
1625 if not range_lists_sec
: # No ranges section - readelf outputs nothing
1628 if isinstance(range_lists_sec
, RangeListsPair
):
1629 self
._dump
_debug
_rangesection
(di
, range_lists_sec
._ranges
)
1630 self
._dump
_debug
_rangesection
(di
, range_lists_sec
._rnglists
)
1632 self
._dump
_debug
_rangesection
(di
, range_lists_sec
)
1634 def _dump_debug_rnglists_CU_header(self
, cu
):
1635 self
._emitline
(' Table at Offset: %s:' % self
._format
_hex
(cu
.cu_offset
, alternate
=True))
1636 self
._emitline
(' Length: %s' % self
._format
_hex
(cu
.unit_length
, alternate
=True))
1637 self
._emitline
(' DWARF version: %d' % cu
.version
)
1638 self
._emitline
(' Address size: %d' % cu
.address_size
)
1639 self
._emitline
(' Segment size: %d' % cu
.segment_selector_size
)
1640 self
._emitline
(' Offset entries: %d\n' % cu
.offset_count
)
1641 if cu
.offsets
and len(cu
.offsets
):
1642 self
._emitline
(' Offsets starting at 0x%x:' % cu
.offset_table_offset
)
1643 for i_offset
in enumerate(cu
.offsets
):
1644 self
._emitline
(' [%6d] 0x%x' % i_offset
)
1646 def _dump_debug_rangesection(self
, di
, range_lists_sec
):
1647 # Last amended to match readelf 2.41
1648 ver5
= range_lists_sec
.version
>= 5
1649 section_name
= (di
.debug_rnglists_sec
if ver5
else di
.debug_ranges_sec
).name
1650 addr_size
= di
.config
.default_address_size
# In bytes, 4 or 8
1651 addr_width
= addr_size
* 2 # In hex digits, 8 or 16
1652 line_template
= " %%08x %%0%dx %%0%dx %%s" % (addr_width
, addr_width
)
1653 base_template
= " %%08x %%0%dx (base address)" % (addr_width
)
1654 base_template_indexed
= " %%08x %%0%dx (base address index) %%0%dx (base address)" % (addr_width
, addr_width
)
1656 # In order to determine the base address of the range
1657 # We need to know the corresponding CU.
1658 cu_map
= {die
.attributes
['DW_AT_ranges'].value
: cu
# Range list offset => CU
1659 for cu
in di
.iter_CUs()
1660 for die
in cu
.iter_DIEs()
1661 if 'DW_AT_ranges' in die
.attributes
}
1663 rcus
= list(range_lists_sec
.iter_CUs()) if ver5
else None
1667 range_lists
= list(range_lists_sec
.iter_range_lists())
1668 if len(range_lists
) == 0:
1669 # Present but empty ranges section - readelf outputs a message
1670 self
._emitline
("\nSection '%s' has no debugging data." % section_name
)
1673 self
._emitline
('Contents of the %s section:\n\n\n' % section_name
)
1675 self
._emitline
(' Offset Begin End')
1677 for range_list
in range_lists
:
1678 # Emit CU headers before the curernt rangelist
1679 if ver5
and range_list
[0].entry_offset
> next_rcu_offset
:
1680 while range_list
[0].entry_offset
> next_rcu_offset
:
1681 rcu
= rcus
[rcu_index
]
1682 self
._dump
_debug
_rnglists
_CU
_header
(rcu
)
1683 next_rcu_offset
= rcu
.offset_after_length
+ rcu
.unit_length
1685 self
._emitline
(' Offset Begin End')
1686 self
._dump
_rangelist
(range_list
, cu_map
, ver5
, line_template
, base_template
, base_template_indexed
, range_lists_sec
)
1688 # TODO: trailing empty CUs, if any?
1690 def _dump_rangelist(self
, range_list
, cu_map
, ver5
, line_template
, base_template
, base_template_indexed
, range_lists_sec
):
1691 # Weird discrepancy in binutils: for DWARFv5 it outputs entry offset,
1692 # for DWARF<=4 list offset.
1693 first
= range_list
[0]
1694 base_ip
= _get_cu_base(cu_map
[first
.entry_offset
])
1695 raw_v5_rangelist
= None
1696 for entry
in range_list
:
1697 if isinstance(entry
, RangeEntry
):
1698 postfix
= ' (start == end)' if entry
.begin_offset
== entry
.end_offset
else ''
1699 self
._emitline
(line_template
% (
1700 entry
.entry_offset
if ver5
else first
.entry_offset
,
1701 (0 if entry
.is_absolute
else base_ip
) + entry
.begin_offset
,
1702 (0 if entry
.is_absolute
else base_ip
) + entry
.end_offset
,
1704 elif isinstance(entry
,RangeBaseAddressEntry
):
1705 base_ip
= entry
.base_address
1706 # V5 base entries with index are reported differently in readelf - need to go back to the raw V5 format
1707 # Maybe other subtypes too, but no such cases in the test corpus
1710 if not raw_v5_rangelist
:
1711 raw_v5_rangelist
= range_lists_sec
.get_range_list_at_offset_ex(range_list
[0].entry_offset
)
1712 raw_v5_entry
= next(re
for re
in raw_v5_rangelist
if re
.entry_offset
== entry
.entry_offset
)
1713 if raw_v5_entry
and raw_v5_entry
.entry_type
== 'DW_RLE_base_addressx':
1714 self
._emitline
(base_template_indexed
% (
1717 entry
.base_address
))
1719 self
._emitline
(base_template
% (
1720 entry
.entry_offset
if ver5
else first
.entry_offset
,
1721 entry
.base_address
))
1723 raise NotImplementedError("Unknown object in a range list")
1724 last
= range_list
[-1]
1725 self
._emitline
(' %08x <End of list>' % (last
.entry_offset
+ last
.entry_length
if ver5
else first
.entry_offset
))
1727 def _display_attributes(self
, attr_sec
, descriptor
):
1728 """ Display the attributes contained in the section.
1730 for s
in attr_sec
.iter_subsections():
1731 self
._emitline
("Attribute Section: %s" % s
.header
['vendor_name'])
1732 for ss
in s
.iter_subsubsections():
1733 h_val
= "" if ss
.header
.extra
is None else " ".join("%d" % x
for x
in ss
.header
.extra
)
1734 self
._emitline
(descriptor(ss
.header
.tag
, h_val
, None))
1736 for attr
in ss
.iter_attributes():
1738 self
._emitline
(descriptor(attr
.tag
, attr
.value
, attr
.extra
))
1740 def _display_arch_specific_arm(self
):
1741 """ Display the ARM architecture-specific info contained in the file.
1743 attr_sec
= self
.elffile
.get_section_by_name('.ARM.attributes')
1744 self
._display
_attributes
(attr_sec
, describe_attr_tag_arm
)
1746 def _display_arch_specific_riscv(self
):
1747 """ Display the RISC-V architecture-specific info contained in the file.
1749 attr_sec
= self
.elffile
.get_section_by_name('.riscv.attributes')
1750 self
._display
_attributes
(attr_sec
, describe_attr_tag_riscv
)
1752 def _emit(self
, s
=''):
1753 """ Emit an object to output
1755 self
.output
.write(str(s
))
1757 def _emitline(self
, s
=''):
1758 """ Emit an object to output, followed by a newline
1760 self
.output
.write(str(s
).rstrip() + '\n')
1763 SCRIPT_DESCRIPTION
= 'Display information about the contents of ELF format files'
1764 VERSION_STRING
= '%%(prog)s: based on pyelftools %s' % __version__
1767 def main(stream
=None):
1768 # parse the command-line arguments and invoke ReadElf
1769 argparser
= argparse
.ArgumentParser(
1770 usage
='usage: %(prog)s [options] <elf-file>',
1771 description
=SCRIPT_DESCRIPTION
,
1772 add_help
=False, # -h is a real option of readelf
1774 argparser
.add_argument('file',
1775 nargs
='?', default
=None,
1776 help='ELF file to parse')
1777 argparser
.add_argument('-v', '--version',
1778 action
='version', version
=VERSION_STRING
)
1779 argparser
.add_argument('-d', '--dynamic',
1780 action
='store_true', dest
='show_dynamic_tags',
1781 help='Display the dynamic section')
1782 argparser
.add_argument('-H', '--help',
1783 action
='store_true', dest
='help',
1784 help='Display this information')
1785 argparser
.add_argument('-h', '--file-header',
1786 action
='store_true', dest
='show_file_header',
1787 help='Display the ELF file header')
1788 argparser
.add_argument('-l', '--program-headers', '--segments',
1789 action
='store_true', dest
='show_program_header',
1790 help='Display the program headers')
1791 argparser
.add_argument('-S', '--section-headers', '--sections',
1792 action
='store_true', dest
='show_section_header',
1793 help="Display the sections' headers")
1794 argparser
.add_argument('-e', '--headers',
1795 action
='store_true', dest
='show_all_headers',
1796 help='Equivalent to: -h -l -S')
1797 argparser
.add_argument('-s', '--symbols', '--syms',
1798 action
='store_true', dest
='show_symbols',
1799 help='Display the symbol table')
1800 argparser
.add_argument('-n', '--notes',
1801 action
='store_true', dest
='show_notes',
1802 help='Display the core notes (if present)')
1803 argparser
.add_argument('-r', '--relocs',
1804 action
='store_true', dest
='show_relocs',
1805 help='Display the relocations (if present)')
1806 argparser
.add_argument('-au', '--arm-unwind',
1807 action
='store_true', dest
='show_arm_unwind',
1808 help='Display the armeabi unwind information (if present)')
1809 argparser
.add_argument('-x', '--hex-dump',
1810 action
='store', dest
='show_hex_dump', metavar
='<number|name>',
1811 help='Dump the contents of section <number|name> as bytes')
1812 argparser
.add_argument('-p', '--string-dump',
1813 action
='store', dest
='show_string_dump', metavar
='<number|name>',
1814 help='Dump the contents of section <number|name> as strings')
1815 argparser
.add_argument('-V', '--version-info',
1816 action
='store_true', dest
='show_version_info',
1817 help='Display the version sections (if present)')
1818 argparser
.add_argument('-A', '--arch-specific',
1819 action
='store_true', dest
='show_arch_specific',
1820 help='Display the architecture-specific information (if present)')
1821 argparser
.add_argument('--debug-dump',
1822 action
='store', dest
='debug_dump_what', metavar
='<what>',
1824 'Display the contents of DWARF debug sections. <what> can ' +
1825 'one of {info,decodedline,frames,frames-interp,aranges,pubtypes,pubnames,loc,Ranges}'))
1826 argparser
.add_argument('--traceback',
1827 action
='store_true', dest
='show_traceback',
1828 help='Dump the Python traceback on ELFError'
1829 ' exceptions from elftools')
1831 args
= argparser
.parse_args()
1833 if args
.help or not args
.file:
1834 argparser
.print_help()
1837 if args
.show_all_headers
:
1838 do_file_header
= do_section_header
= do_program_header
= True
1840 do_file_header
= args
.show_file_header
1841 do_section_header
= args
.show_section_header
1842 do_program_header
= args
.show_program_header
1844 with
open(args
.file, 'rb') as file:
1846 readelf
= ReadElf(file, stream
or sys
.stdout
)
1848 readelf
.display_file_header()
1849 if do_section_header
:
1850 readelf
.display_section_headers(
1851 show_heading
=not do_file_header
)
1852 if do_program_header
:
1853 readelf
.display_program_headers(
1854 show_heading
=not do_file_header
)
1855 if args
.show_dynamic_tags
:
1856 readelf
.display_dynamic_tags()
1857 if args
.show_symbols
:
1858 readelf
.display_symbol_tables()
1860 readelf
.display_notes()
1861 if args
.show_relocs
:
1862 readelf
.display_relocations()
1863 if args
.show_arm_unwind
:
1864 readelf
.display_arm_unwind()
1865 if args
.show_version_info
:
1866 readelf
.display_version_info()
1867 if args
.show_arch_specific
:
1868 readelf
.display_arch_specific()
1869 if args
.show_hex_dump
:
1870 readelf
.display_hex_dump(args
.show_hex_dump
)
1871 if args
.show_string_dump
:
1872 readelf
.display_string_dump(args
.show_string_dump
)
1873 if args
.debug_dump_what
:
1874 readelf
.display_debug_dump(args
.debug_dump_what
)
1875 except ELFError
as ex
:
1877 sys
.stderr
.write('ELF error: %s\n' % ex
)
1878 if args
.show_traceback
:
1879 traceback
.print_exc()
1884 # Run 'main' redirecting its output to readelfout.txt
1885 # Saves profiling information in readelf.profile
1886 PROFFILE
= 'readelf.profile'
1888 cProfile
.run('main(open("readelfout.txt", "w"))', PROFFILE
)
1890 # Dig in some profiling stats
1892 p
= pstats
.Stats(PROFFILE
)
1893 p
.sort_stats('cumulative').print_stats(25)
1896 #-------------------------------------------------------------------------------
1897 if __name__
== '__main__':