Add support for LoongArch (#470)
[pyelftools.git] / scripts / readelf.py
1 #!/usr/bin/env python
2 #-------------------------------------------------------------------------------
3 # scripts/readelf.py
4 #
5 # A clone of 'readelf' in Python, based on the pyelftools library
6 #
7 # Eli Bendersky (eliben@gmail.com)
8 # This code is in the public domain
9 #-------------------------------------------------------------------------------
10 import argparse
11 import os, sys
12 import string
13 import traceback
14 import itertools
15 # Note: zip has different behaviour between Python 2.x and 3.x.
16 # - Using izip ensures compatibility.
17 try:
18 from itertools import izip
19 except:
20 izip = zip
21
22 # For running from development directory. It should take precedence over the
23 # installed pyelftools.
24 sys.path.insert(0, '.')
25
26
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
36 )
37 from elftools.elf.gnuversions import (
38 GNUVerSymSection, GNUVerDefSection,
39 GNUVerNeedSection,
40 )
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
51 )
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
61 )
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
69
70 def _get_cu_base(cu):
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)
82 base_ip = None
83 for r in rl:
84 if isinstance(r, RangeBaseAddressEntry):
85 ip = r.base_address
86 elif isinstance(r, RangeEntry) and r.is_absolute:
87 ip = r.begin_offset
88 else:
89 ip = None
90 if ip is not None and (base_ip is None or ip < base_ip):
91 base_ip = ip
92 if base_ip is None:
93 raise ValueError("Can't find the base IP (low_pc) for a CU")
94 return base_ip
95 else:
96 raise ValueError("Can't find the base IP (low_pc) for a CU")
97
98 class ReadElf(object):
99 """ display_* methods are used to emit output into the output stream
100 """
101 def __init__(self, file, output):
102 """ file:
103 stream object with the ELF file to read
104
105 output:
106 output stream to write to
107 """
108 self.elffile = ELFFile(file)
109 self.output = output
110
111 # Lazily initialized if a debug dump is requested
112 self._dwarfinfo = None
113
114 self._versioninfo = None
115
116 self._shndx_sections = None
117
118 def display_file_header(self):
119 """ Display the ELF file header
120 """
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))
125 self._emitline(' ')
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' %
147 header['e_phoff'])
148 self._emitline(' (bytes into file)')
149 self._emit(' Start of section headers: %s' %
150 header['e_shoff'])
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)' %
156 header['e_ehsize'])
157 self._emitline(' Size of program headers: %s (bytes)' %
158 header['e_phentsize'])
159 self._emitline(' Number of program headers: %s' %
160 header['e_phnum'])
161 self._emitline(' Size of section headers: %s (bytes)' %
162 header['e_shentsize'])
163 self._emit(' Number of section headers: %s' %
164 header['e_shnum'])
165 if header['e_shnum'] == 0 and self.elffile.num_sections() != 0:
166 self._emitline(' (%d)' % self.elffile.num_sections())
167 else:
168 self._emitline('')
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())
173 else:
174 self._emitline('')
175
176 def decode_flags(self, flags):
177 description = ""
178 if self.elffile['e_machine'] == "EM_ARM":
179 eabi = flags & E_FLAGS.EF_ARM_EABIMASK
180 flags &= ~E_FLAGS.EF_ARM_EABIMASK
181
182 if flags & E_FLAGS.EF_ARM_RELEXEC:
183 description += ', relocatable executabl'
184 flags &= ~E_FLAGS.EF_ARM_RELEXEC
185
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"
193
194 if flags & E_FLAGS.EF_ARM_BE8:
195 description += ", BE8"
196 elif flags & E_FLAGS.EF_ARM_LE8:
197 description += ", LE8"
198
199 if flags & ~EF_ARM_KNOWN_FLAGS:
200 description += ', <unknown>'
201 else:
202 description += ', <unrecognized EABI>'
203
204 elif self.elffile['e_machine'] == 'EM_PPC64':
205 if flags & E_FLAGS.EF_PPC64_ABI_V2:
206 description += ', abiv2'
207
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"
245
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"
261
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"
273
274 return description
275
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...)
280 """
281 self._emitline()
282 if self.elffile.num_segments() == 0:
283 self._emitline('There are no program headers in this file.')
284 return
285
286 elfheader = self.elffile.header
287 if show_heading:
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
293 # headers, it is...)
294 self._emitline('There are %s program headers, starting at offset %s' % (
295 self.elffile.num_segments(), elfheader['e_phoff']))
296 self._emitline()
297
298 self._emitline('Program Headers:')
299
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.
303 #
304 # First comes the table heading
305 #
306 if self.elffile.elfclass == 32:
307 self._emitline(' Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align')
308 else:
309 self._emitline(' Type Offset VirtAddr PhysAddr')
310 self._emitline(' FileSiz MemSiz Flags Align')
311
312 # Now the entries
313 #
314 for segment in self.elffile.iter_segments():
315 self._emit(' %-14s ' % describe_p_type(segment['p_type']))
316
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'])))
326 else: # 64
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)))
338
339 if isinstance(segment, InterpSegment):
340 self._emitline(' [Requesting program interpreter: %s]' %
341 segment.get_interp_name())
342
343 # Sections to segments mapping
344 #
345 if self.elffile.num_sections() == 0:
346 # No sections? We're done
347 return
348
349 self._emitline('\n Section to Segment mapping:')
350 self._emitline(' Segment Sections...')
351
352 for nseg, segment in enumerate(self.elffile.iter_segments()):
353 self._emit(' %2.2d ' % nseg)
354
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)
362
363 self._emitline('')
364
365 def display_section_headers(self, show_heading=True):
366 """ Display the ELF section headers
367 """
368 elfheader = self.elffile.header
369 if show_heading:
370 self._emitline('There are %s section headers, starting at offset %s' % (
371 elfheader['e_shnum'], self._format_hex(elfheader['e_shoff'])))
372
373 if self.elffile.num_sections() == 0:
374 self._emitline('There are no sections in this file.')
375 return
376
377 self._emitline('\nSection Header%s:' % (
378 's' if self.elffile.num_sections() > 1 else ''))
379
380 # Different formatting constraints of 32-bit and 64-bit addresses
381 #
382 if self.elffile.elfclass == 32:
383 self._emitline(' [Nr] Name Type Addr Off Size ES Flg Lk Inf Al')
384 else:
385 self._emitline(' [Nr] Name Type Address Offset')
386 self._emitline(' Size EntSize Flags Link Info Align')
387
388 # Now the entries
389 #
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'])))
393
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']))
403 else: # 64
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,
408 lead0x=False)))
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']))
415
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),'
422 ' E (exclude),')
423 self._emit(' ')
424 if self.elffile['e_machine'] == 'EM_ARM':
425 self._emit('y (purecode), ')
426 self._emitline('p (processor specific)')
427
428 def display_symbol_tables(self):
429 """ Display the symbol tables contained in the file
430 """
431 self._init_versioninfo()
432
433 symbol_tables = [(idx, s) for idx, s in enumerate(self.elffile.iter_sections())
434 if isinstance(s, SymbolTableSection)]
435
436 if not symbol_tables and self.elffile.num_sections() == 0:
437 self._emitline('')
438 self._emitline('Dynamic symbol information is not available for'
439 ' displaying symbols.')
440
441 for section_index, section in symbol_tables:
442 if not isinstance(section, SymbolTableSection):
443 continue
444
445 if section['sh_entsize'] == 0:
446 self._emitline("\nSymbol table '%s' has a sh_entsize of zero!" % (
447 section.name))
448 continue
449
450 self._emitline("\nSymbol table '%s' contains %d %s:" % (
451 section.name,
452 section.num_symbols(),
453 'entry' if section.num_symbols() == 1 else 'entries'))
454
455 if self.elffile.elfclass == 32:
456 self._emitline(' Num: Value Size Type Bind Vis Ndx Name')
457 else: # 64
458 self._emitline(' Num: Value Size Type Bind Vis Ndx Name')
459
460 for nsym, symbol in enumerate(section.iter_symbols()):
461 version_info = ''
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',
468 'VER_NDX_GLOBAL')):
469 if version['filename']:
470 # external symbol
471 version_info = '@%(name)s (%(index)i)' % version
472 else:
473 # internal symbol
474 if version['hidden']:
475 version_info = '@%(name)s' % version
476 else:
477 version_info = '@@%(name)s' % version
478
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
485
486 # symbol names are truncated to 25 chars, similarly to readelf
487 self._emitline('%6d: %s %s %-7s %-6s %-7s %4s %.25s%s' % (
488 nsym,
489 self._format_hex(
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,
496 nsym,
497 section_index)),
498 symbol_name,
499 version_info))
500
501 def display_dynamic_tags(self):
502 """ Display the dynamic tags contained in the file
503 """
504 has_dynamic_sections = False
505 for section in self.elffile.iter_sections():
506 if not isinstance(section, DynamicSection):
507 continue
508
509 has_dynamic_sections = True
510 self._emitline("\nDynamic section at offset %s contains %d %s:" % (
511 self._format_hex(section['sh_offset']),
512 section.num_tags(),
513 'entry' if section.num_tags() == 1 else 'entries'))
514 self._emitline(" Tag Type Name/Value")
515
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_'):
537 s = s[3:]
538 parsed = '%s' % s
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)
544 else:
545 parsed = '%#x' % tag['d_val']
546
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),
550 padding,
551 '(%s)' % (tag.entry.d_tag[3:],),
552 parsed))
553 if not has_dynamic_sections:
554 self._emitline("\nThere is no dynamic section in this file.")
555
556 def display_notes(self):
557 """ Display the notes contained in the file
558 """
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(
563 section.name))
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)))
569
570 def display_relocations(self):
571 """ Display the relocations contained in the file
572 """
573 has_relocation_sections = False
574 for section in self.elffile.iter_sections():
575 if not isinstance(section, RelocationSection):
576 continue
577
578 has_relocation_sections = True
579 self._emitline("\nRelocation section '%.128s' at offset %s contains %d %s:" % (
580 section.name,
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")
586 else:
587 self._emitline(" Offset Info Type Sym.Value Sym. Name")
588
589 # The symbol table section pointed to in sh_link
590 symtable = self.elffile.get_section(section['sh_link'])
591
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),
599 describe_reloc_type(
600 rel['r_info_type'], self.elffile)))
601
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))
607 self._emitline()
608
609 else:
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
614 # readelf.
615 if symbol['st_name'] == 0:
616 symsecidx = self._get_symbol_shndx(symbol,
617 rel['r_info_sym'],
618 section['sh_link'])
619 symsec = self.elffile.get_section(symsecidx)
620 symbol_name = symsec.name
621 version = ''
622 else:
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
628 if version:
629 symbol_name += '@' + version
630
631 self._emit(' %s %s' % (
632 self._format_hex(
633 symbol['st_value'],
634 fullhex=True, lead0x=False),
635 symbol_name))
636 if section.is_RELA():
637 self._emit(' %s %x' % (
638 '+' if rel['r_addend'] >= 0 else '-',
639 abs(rel['r_addend'])))
640 self._emitline()
641
642 # Emit the two additional relocation types for ELF64 MIPS
643 # binaries.
644 if (self.elffile.elfclass == 64 and
645 self.elffile['e_machine'] == 'EM_MIPS'):
646 for i in (2, 3):
647 rtype = rel['r_info_type%s' % i]
648 self._emit(' Type%s: %s' % (
649 i,
650 describe_reloc_type(rtype, self.elffile)))
651 self._emitline()
652
653 if not has_relocation_sections:
654 self._emitline('\nThere are no relocations in this file.')
655
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.')
659 return
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'))
667
668 for i in range(ehabi_info.num_entry()):
669 entry = ehabi_info.get_entry(i)
670 self._emitline()
671 self._emitline("Entry %d:" % i)
672 if isinstance(entry, CorruptEHABIEntry):
673 self._emitline(" [corrupt] %s" % entry.reason)
674 continue
675 self._emit(" Function offset 0x%x: " % entry.function_offset)
676 if isinstance(entry, CannotUnwindEHABIEntry):
677 self._emitline("[cantunwind]")
678 continue
679 elif entry.eh_table_offset:
680 self._emitline("@0x%x" % entry.eh_table_offset)
681 else:
682 self._emitline("Compact (inline)")
683 if isinstance(entry, GenericEHABIEntry):
684 self._emitline(" Personality: 0x%x" % entry.personality)
685 else:
686 self._emitline(" Compact model index: %d" % entry.personality)
687 for mnemonic_item in entry.mnmemonic_array():
688 self._emit(' ')
689 self._emitline(mnemonic_item)
690
691 def display_version_info(self):
692 """ Display the version info contained in the file
693 """
694 self._init_versioninfo()
695
696 if not self._versioninfo['type']:
697 self._emitline("\nNo version information found in this file.")
698 return
699
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()
704
705 # Symbol version info are printed four by four entries
706 for idx_by_4 in range(0, num_symbols, 4):
707
708 self._emit(' %03x:' % idx_by_4)
709
710 for idx in range(idx_by_4, min(idx_by_4 + 4, num_symbols)):
711
712 symbol_version = self._symbol_version(idx)
713 if symbol_version['index'] == 'VER_NDX_LOCAL':
714 version_index = 0
715 version_name = '(*local*)'
716 elif symbol_version['index'] == 'VER_NDX_GLOBAL':
717 version_index = 1
718 version_name = '(*global*)'
719 else:
720 version_index = symbol_version['index']
721 version_name = '(%(name)s)' % symbol_version
722
723 visibility = 'h' if symbol_version['hidden'] else ' '
724
725 self._emit('%4x%s%-13s' % (
726 version_index, visibility, version_name))
727
728 self._emitline()
729
730 elif isinstance(section, GNUVerDefSection):
731 self._print_version_section_header(
732 section, 'Version definition', indent=2)
733
734 offset = 0
735 for verdef, verdaux_iter in section.iter_versions():
736 verdaux = next(verdaux_iter)
737
738 name = verdaux.name
739 if verdef['vd_flags']:
740 flags = describe_ver_flags(verdef['vd_flags'])
741 # Mimic exactly the readelf output
742 flags += ' '
743 else:
744 flags = 'none'
745
746 self._emitline(' %s: Rev: %i Flags: %s Index: %i'
747 ' Cnt: %i Name: %s' % (
748 self._format_hex(offset, fieldsize=6,
749 alternate=True),
750 verdef['vd_version'], flags, verdef['vd_ndx'],
751 verdef['vd_cnt'], name))
752
753 verdaux_offset = (
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),
758 idx, verdaux.name))
759 verdaux_offset += verdaux['vda_next']
760
761 offset += verdef['vd_next']
762
763 elif isinstance(section, GNUVerNeedSection):
764 self._print_version_section_header(section, 'Version needs')
765
766 offset = 0
767 for verneed, verneed_iter in section.iter_versions():
768
769 self._emitline(' %s: Version: %i File: %s Cnt: %i' % (
770 self._format_hex(offset, fieldsize=6,
771 alternate=True),
772 verneed['vn_version'], verneed.name,
773 verneed['vn_cnt']))
774
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
780 flags += ' '
781 else:
782 flags = 'none'
783
784 self._emitline(
785 ' %s: Name: %s Flags: %s Version: %i' % (
786 self._format_hex(vernaux_offset, fieldsize=4),
787 vernaux.name, flags,
788 vernaux['vna_other']))
789
790 vernaux_offset += vernaux['vna_next']
791
792 offset += verneed['vn_next']
793
794 def display_arch_specific(self):
795 """ Display the architecture-specific info contained in the file.
796 """
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()
801
802 def display_hex_dump(self, section_spec):
803 """ Display a hex dump of a section. section_spec is either a section
804 number or a name.
805 """
806 section = self._section_from_spec(section_spec)
807 if section is None:
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' % (
811 section_spec))
812 return
813 if section['sh_type'] == 'SHT_NOBITS':
814 self._emitline("\nSection '%s' has no data to dump." % (
815 section_spec))
816 return
817
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()
822 dataptr = 0
823
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
828
829 self._emit(' %s ' % self._format_hex(addr, fieldsize=8))
830 for i in range(16):
831 if i < linebytes:
832 self._emit('%2.2x' % data[dataptr + i])
833 else:
834 self._emit(' ')
835 if i % 4 == 3:
836 self._emit(' ')
837
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))
842 else:
843 self._emit(bytes2str(b'.'))
844
845 self._emitline()
846 addr += linebytes
847 dataptr += linebytes
848
849 self._emitline()
850
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.
854 """
855 section = self._section_from_spec(section_spec)
856 if section is None:
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' % (
860 section_spec))
861 return
862 if section['sh_type'] == 'SHT_NOBITS':
863 self._emitline("\nSection '%s' has no data to dump." % (
864 section_spec))
865 return
866
867 self._emitline("\nString dump of section '%s':" % section.name)
868
869 found = False
870 data = section.data()
871 dataptr = 0
872
873 while dataptr < len(data):
874 while ( dataptr < len(data) and
875 not (32 <= data[dataptr] <= 127)):
876 dataptr += 1
877
878 if dataptr >= len(data):
879 break
880
881 endptr = dataptr
882 while endptr < len(data) and data[endptr] != 0:
883 endptr += 1
884
885 found = True
886 self._emitline(' [%6x] %s' % (
887 dataptr, bytes2str(data[dataptr:endptr])))
888
889 dataptr = endptr
890
891 if not found:
892 self._emitline(' No strings found in this section.')
893 else:
894 self._emitline()
895
896 def display_debug_dump(self, dump_what):
897 """ Dump a DWARF section
898 """
899 self._init_dwarfinfo()
900 if self._dwarfinfo is None:
901 return
902
903 set_global_machine_arch(self.elffile.get_machine_arch())
904
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()
921 else:
922 self._emitline('debug dump not yet supported for "%s"' % dump_what)
923
924 def _format_hex(self, addr, fieldsize=None, fullhex=False, lead0x=True,
925 alternate=False):
926 """ Format an address into a hexadecimal string.
927
928 fieldsize:
929 Size of the hexadecimal field (with leading zeros to fit the
930 address into. For example with fieldsize=8, the format will
931 be %08x
932 If None, the minimal required field size will be used.
933
934 fullhex:
935 If True, override fieldsize to set it to the maximal size
936 needed for the elfclass
937
938 lead0x:
939 If True, leading 0x is added
940
941 alternate:
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.
946 """
947 if alternate:
948 if addr == 0:
949 lead0x = False
950 else:
951 lead0x = True
952 fieldsize -= 2
953
954 s = '0x' if lead0x else ''
955 if fullhex:
956 fieldsize = 8 if self.elffile.elfclass == 32 else 16
957 if fieldsize is None:
958 field = '%x'
959 else:
960 field = '%' + '0%sx' % fieldsize
961 return s + field % addr
962
963 def _print_version_section_header(self, version_section, name, lead0x=True,
964 indent=1):
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
968 and 0x prefixing).
969 """
970 if hasattr(version_section, 'num_versions'):
971 num_entries = version_section.num_versions()
972 else:
973 num_entries = version_section.num_symbols()
974
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)' % (
979 ' ' * indent,
980 self._format_hex(
981 version_section['sh_addr'], fieldsize=16, lead0x=lead0x),
982 self._format_hex(
983 version_section['sh_offset'], fieldsize=6, lead0x=True),
984 version_section['sh_link'],
985 self.elffile.get_section(version_section['sh_link']).name
986 )
987 )
988
989 def _init_versioninfo(self):
990 """ Search and initialize informations about version related sections
991 and the kind of versioning used (GNU or Solaris).
992 """
993 if self._versioninfo is not None:
994 return
995
996 self._versioninfo = {'versym': None, 'verdef': None,
997 'verneed': None, 'type': None}
998
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'
1010 break
1011
1012 if not self._versioninfo['type'] and (
1013 self._versioninfo['verneed'] or self._versioninfo['verdef']):
1014 self._versioninfo['type'] = 'Solaris'
1015
1016 def _symbol_version(self, nsym):
1017 """ Return a dict containing information on the
1018 or None if no version information is available
1019 """
1020 self._init_versioninfo()
1021
1022 symbol_version = dict.fromkeys(('index', 'name', 'filename', 'hidden'))
1023
1024 if (not self._versioninfo['versym'] or
1025 nsym >= self._versioninfo['versym'].num_symbols()):
1026 return None
1027
1028 symbol = self._versioninfo['versym'].get_symbol(nsym)
1029 index = symbol.entry['ndx']
1030 if not index in ('VER_NDX_LOCAL', 'VER_NDX_GLOBAL'):
1031 index = int(index)
1032
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
1036 if index & 0x8000:
1037 index &= ~0x8000
1038 symbol_version['hidden'] = True
1039
1040 if (self._versioninfo['verdef'] and
1041 index <= self._versioninfo['verdef'].num_versions()):
1042 _, verdaux_iter = \
1043 self._versioninfo['verdef'].get_version(index)
1044 symbol_version['name'] = next(verdaux_iter).name
1045 else:
1046 verneed, vernaux = \
1047 self._versioninfo['verneed'].get_version(index)
1048 symbol_version['name'] = vernaux.name
1049 symbol_version['filename'] = verneed.name
1050
1051 symbol_version['index'] = index
1052 return symbol_version
1053
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.
1057 """
1058 try:
1059 num = int(spec)
1060 if num < self.elffile.num_sections():
1061 return self.elffile.get_section(num)
1062 else:
1063 return None
1064 except ValueError:
1065 # Not a number. Must be a name then
1066 return self.elffile.get_section_by_name(spec)
1067
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
1071 "symtab_index".
1072 """
1073 symbol_shndx = symbol['st_shndx']
1074 if symbol_shndx != SHN_INDICES.SHN_XINDEX:
1075 return symbol_shndx
1076
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)
1083
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.
1087 """
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.')
1093 return
1094
1095 def _init_dwarfinfo(self):
1096 """ Initialize the DWARF info contained in the file and assign it to
1097 self._dwarfinfo.
1098 Leave self._dwarfinfo at None if no DWARF info was found in the file
1099 """
1100 if self._dwarfinfo is not None:
1101 return
1102
1103 if self.elffile.has_dwarf_info():
1104 self._dwarfinfo = self.elffile.get_dwarf_info()
1105 else:
1106 self._dwarfinfo = None
1107
1108 def _dump_debug_info(self):
1109 """ Dump the debugging info section.
1110 """
1111 if not self._dwarfinfo.has_debug_info:
1112 return
1113 self._emitline('Contents of the %s section:\n' % self._dwarfinfo.debug_info_sec.name)
1114
1115 # Offset of the .debug_info section in the stream
1116 section_offset = self._dwarfinfo.debug_info_sec.global_offset
1117
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'])
1138 else:
1139 self._emitline(' Abbrev Offset: %s' % (
1140 self._format_hex(cu['debug_abbrev_offset']))),
1141 self._emitline(' Pointer Size: %s' % cu['address_size'])
1142
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
1148 #
1149 die_depth = 0
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' % (
1155 die_depth,
1156 die.offset,
1157 die.abbrev_code,
1158 (' (%s)' % die.tag) if not die.is_null() else ''))
1159 if die.is_null():
1160 die_depth -= 1
1161 continue
1162
1163 for attr in die.attributes.values():
1164 name = attr.name
1165 # Unknown attribute values are passed-through as integers
1166 if isinstance(name, int):
1167 name = 'Unknown AT value: %x' % name
1168
1169 attr_desc = describe_attr_value(attr, die, section_offset)
1170
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]'
1173 else:
1174 postfix = ''
1175
1176 self._emitline(' <%x> %-18s: %s%s' % (
1177 attr.offset,
1178 name,
1179 attr_desc,
1180 postfix))
1181
1182 if die.has_children:
1183 die_depth += 1
1184
1185 self._emitline()
1186
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.
1190 """
1191 if not self._dwarfinfo.has_debug_info:
1192 return
1193 self._emitline('Contents of the %s section:' % self._dwarfinfo.debug_line_sec.name)
1194 self._emitline()
1195 lineprogram_list = []
1196
1197 for cu in self._dwarfinfo.iter_CUs():
1198 # Avoid dumping same lineprogram multiple times
1199 lineprogram = self._dwarfinfo.line_program_for_CU(cu)
1200
1201 if lineprogram in lineprogram_list:
1202 continue
1203
1204 lineprogram_list.append(lineprogram)
1205 ver5 = lineprogram.header.version >= 5
1206
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)
1211 else:
1212 self._emitline('CU: %s:' % cu_filename)
1213
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
1217
1218 # Print each state's file, line and address information. For some
1219 # instructions other output is needed to be compatible with
1220 # readelf.
1221 for entry in lineprogram.get_entries():
1222 state = entry.state
1223 if state is None:
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:
1228 # current directory
1229 self._emitline('\n./%s:[++]' % (
1230 bytes2str(file_entry.name)))
1231 else:
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 ''))
1244 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...
1255 self._emitline()
1256
1257 def _dump_frames_info(self, section, cfi_entries):
1258 """ Dump the raw call frame info in a section.
1259
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.
1263 """
1264 self._emitline('Contents of the %s section:' % section.name)
1265
1266 for entry in cfi_entries:
1267 if isinstance(entry, CIE):
1268 self._emitline('\n%08x %s %s CIE' % (
1269 entry.offset,
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)
1281 )))
1282 self._emitline()
1283
1284 elif isinstance(entry, FDE):
1285 self._emitline('\n%08x %s %s FDE cie=%08x pc=%s..%s' % (
1286 entry.offset,
1287 self._format_hex(entry['length'], fullhex=True, lead0x=False),
1288 self._format_hex(entry['CIE_pointer'], fieldsize=8, lead0x=False),
1289 entry.cie.offset,
1290 self._format_hex(entry['initial_location'], fullhex=True, lead0x=False),
1291 self._format_hex(
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)
1298 )))
1299
1300 else: # ZERO terminator
1301 assert isinstance(entry, ZERO)
1302 self._emitline('\n%08x ZERO terminator' % entry.offset)
1303 continue
1304
1305 self._emit(describe_CFI_instructions(entry))
1306 self._emitline()
1307
1308 def _dump_debug_frames(self):
1309 """ Dump the raw frame info from .debug_frame and .eh_frame sections.
1310 """
1311 if self._dwarfinfo.has_EH_CFI():
1312 self._dump_frames_info(
1313 self._dwarfinfo.eh_frame_sec,
1314 self._dwarfinfo.EH_CFI_entries())
1315 self._emitline()
1316
1317 if self._dwarfinfo.has_CFI():
1318 self._dump_frames_info(
1319 self._dwarfinfo.debug_frame_sec,
1320 self._dwarfinfo.CFI_entries())
1321
1322 def _dump_debug_namelut(self, what):
1323 """
1324 Dump the debug pubnames section.
1325 """
1326 if what == 'pubnames':
1327 namelut = self._dwarfinfo.get_pubnames()
1328 section = self._dwarfinfo.debug_pubnames_sec
1329 else:
1330 namelut = self._dwarfinfo.get_pubtypes()
1331 section = self._dwarfinfo.debug_pubtypes_sec
1332
1333 # readelf prints nothing if the section is not present.
1334 if namelut is None or len(namelut) == 0:
1335 return
1336
1337 self._emitline('Contents of the %s section:' % section.name)
1338 self._emitline()
1339
1340 cu_headers = namelut.get_cu_headers()
1341
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)):
1345
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)
1350 self._emitline()
1351 self._emitline(' Offset Name')
1352 for item in items:
1353 self._emitline(' %x %s' % (item[1].die_ofs - cu_ofs, item[0]))
1354 self._emitline()
1355
1356 def _dump_debug_aranges(self):
1357 """ Dump the aranges table
1358 """
1359 aranges_table = self._dwarfinfo.get_aranges()
1360 if aranges_table == None:
1361 return
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)
1367
1368 if len(unordered_entries) == 0:
1369 self._emitline()
1370 self._emitline("Section '.debug_aranges' has no debugging data.")
1371 return
1372
1373 self._emitline('Contents of the %s section:' % self._dwarfinfo.debug_aranges_sec.name)
1374 self._emitline()
1375 prev_offset = None
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))
1387 self._emitline()
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)))
1397
1398 def _dump_frames_interp_info(self, section, cfi_entries):
1399 """ Dump interpreted (decoded) frame information in a section.
1400
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.
1404 """
1405 self._emitline('Contents of the %s section:' % section.name)
1406
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' % (
1410 entry.offset,
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']
1418
1419 elif isinstance(entry, FDE):
1420 self._emitline('\n%08x %s %s FDE cie=%08x pc=%s..%s' % (
1421 entry.offset,
1422 self._format_hex(entry['length'], fullhex=True, lead0x=False),
1423 self._format_hex(entry['CIE_pointer'], fieldsize=8, lead0x=False),
1424 entry.cie.offset,
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']
1429
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)):
1434 continue
1435
1436 else: # ZERO terminator
1437 assert isinstance(entry, ZERO)
1438 self._emitline('\n%08x ZERO terminator' % entry.offset)
1439 continue
1440
1441 # Decode the table.
1442 decoded_table = entry.get_decoded()
1443 if len(decoded_table.table) == 0:
1444 continue
1445
1446 # Print the heading row for the decoded table
1447 self._emit(' LOC')
1448 self._emit(' ' if entry.structs.address_size == 4 else ' ')
1449 self._emit(' CFA ')
1450
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):
1460
1461 # Headings for the registers
1462 for regnum in reg_order:
1463 self._emit('%-6s' % describe_reg_name(regnum))
1464 self._emitline('ra ')
1465
1466 # Now include ra_regnum in reg_order to print its values
1467 # similarly to the other registers.
1468 reg_order.append(ra_regnum)
1469 else:
1470 self._emitline()
1471
1472 for line in decoded_table.table:
1473 self._emit(self._format_hex(
1474 line['pc'], fullhex=True, lead0x=False))
1475
1476 if line['cfa'] is not None:
1477 s = describe_CFI_CFA_rule(line['cfa'])
1478 else:
1479 s = 'u'
1480 self._emit(' %-9s' % s)
1481
1482 for regnum in reg_order:
1483 if regnum in line:
1484 s = describe_CFI_register_rule(line[regnum])
1485 else:
1486 s = 'u'
1487 self._emit('%-6s' % s)
1488 self._emitline()
1489 self._emitline()
1490
1491 def _dump_debug_frames_interp(self):
1492 """ Dump the interpreted (decoded) frame information from .debug_frame
1493 and .eh_frame sections.
1494 """
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())
1499 self._emitline()
1500
1501 if self._dwarfinfo.has_CFI():
1502 self._dump_frames_interp_info(
1503 self._dwarfinfo.debug_frame_sec,
1504 self._dwarfinfo.CFI_entries())
1505
1506 def _dump_debug_locations(self):
1507 """ Dump the location lists from .debug_loc/.debug_loclists section
1508 """
1509 di = self._dwarfinfo
1510 loc_lists_sec = di.location_lists()
1511 if not loc_lists_sec: # No locations section - readelf outputs nothing
1512 return
1513
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)
1517 else:
1518 self._dump_debug_locsection(di, loc_lists_sec)
1519
1520 def _dump_debug_locsection(self, di, loc_lists_sec):
1521 """ Dump the location lists from .debug_loc/.debug_loclists section
1522 """
1523 ver5 = loc_lists_sec.version >= 5
1524 section_name = (di.debug_loclists_sec if ver5 else di.debug_loc_sec).name
1525
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
1538
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)
1542
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,))
1547 return
1548
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)
1553
1554 def _dump_loclist(self, loc_list, line_template, cu_map):
1555 in_views = False
1556 has_views = False
1557 base_ip = None
1558 loc_entry_count = 0
1559 cu = None
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))
1565 else:
1566 if in_views:
1567 in_views = False
1568 self._emitline("")
1569
1570 # Readelf quirk: indexed loclists don't show the real base IP
1571 if cu_map is None:
1572 base_ip = 0
1573 elif cu is None:
1574 cu = cu_map.get(entry.entry_offset, False)
1575 if not cu:
1576 raise ValueError("Location list can't be tracked to a CU")
1577
1578 if isinstance(entry, LocationEntry):
1579 if base_ip is None and not entry.is_absolute:
1580 base_ip = _get_cu_base(cu)
1581
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)
1585 if has_views:
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:' %(
1589 entry.entry_offset,
1590 view.begin,
1591 view.end,
1592 view.entry_offset))
1593 self._emitline(' %016x %016x %s%s' %(
1594 begin_offset,
1595 end_offset,
1596 expr,
1597 postfix))
1598 loc_entry_count += 1
1599 else:
1600 postfix = ' (start == end)' if entry.begin_offset == entry.end_offset else ''
1601 self._emitline(line_template % (
1602 entry.entry_offset,
1603 begin_offset,
1604 end_offset,
1605 expr,
1606 postfix))
1607 elif isinstance(entry, LocBaseAddressEntry):
1608 base_ip = entry.base_address
1609 self._emitline(" %08x %016x (base address)" % (entry.entry_offset, entry.base_address))
1610
1611 # Pyelftools doesn't store the terminating entry,
1612 # but readelf emits its offset, so this should too.
1613 last = loc_list[-1]
1614 self._emitline(" %08x <End of list>" % (last.entry_offset + last.entry_length))
1615
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
1621 return
1622
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)
1626 else:
1627 self._dump_debug_rangesection(di, range_lists_sec)
1628
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.
1631
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)
1638
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)
1643 return
1644
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}
1651
1652 self._emitline('Contents of the %s section:\n' % section_name)
1653 self._emitline(' Offset Begin End')
1654
1655 for range_list in range_lists:
1656 self._dump_rangelist(range_list, cu_map, ver5, line_template, base_template)
1657
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,
1670 postfix))
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))
1676 else:
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))
1680
1681 def _display_attributes(self, attr_sec, descriptor):
1682 """ Display the attributes contained in the section.
1683 """
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))
1689
1690 for attr in ss.iter_attributes():
1691 self._emit(' ')
1692 self._emitline(descriptor(attr.tag, attr.value, attr.extra))
1693
1694 def _display_arch_specific_arm(self):
1695 """ Display the ARM architecture-specific info contained in the file.
1696 """
1697 attr_sec = self.elffile.get_section_by_name('.ARM.attributes')
1698 self._display_attributes(attr_sec, describe_attr_tag_arm)
1699
1700 def _display_arch_specific_riscv(self):
1701 """ Display the RISC-V architecture-specific info contained in the file.
1702 """
1703 attr_sec = self.elffile.get_section_by_name('.riscv.attributes')
1704 self._display_attributes(attr_sec, describe_attr_tag_riscv)
1705
1706 def _emit(self, s=''):
1707 """ Emit an object to output
1708 """
1709 self.output.write(str(s))
1710
1711 def _emitline(self, s=''):
1712 """ Emit an object to output, followed by a newline
1713 """
1714 self.output.write(str(s).rstrip() + '\n')
1715
1716
1717 SCRIPT_DESCRIPTION = 'Display information about the contents of ELF format files'
1718 VERSION_STRING = '%%(prog)s: based on pyelftools %s' % __version__
1719
1720
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
1727 prog='readelf.py')
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>',
1777 help=(
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')
1784
1785 args = argparser.parse_args()
1786
1787 if args.help or not args.file:
1788 argparser.print_help()
1789 sys.exit(0)
1790
1791 if args.show_all_headers:
1792 do_file_header = do_section_header = do_program_header = True
1793 else:
1794 do_file_header = args.show_file_header
1795 do_section_header = args.show_section_header
1796 do_program_header = args.show_program_header
1797
1798 with open(args.file, 'rb') as file:
1799 try:
1800 readelf = ReadElf(file, stream or sys.stdout)
1801 if do_file_header:
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()
1813 if args.show_notes:
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:
1830 sys.stdout.flush()
1831 sys.stderr.write('ELF error: %s\n' % ex)
1832 if args.show_traceback:
1833 traceback.print_exc()
1834 sys.exit(1)
1835
1836
1837 def profile_main():
1838 # Run 'main' redirecting its output to readelfout.txt
1839 # Saves profiling information in readelf.profile
1840 PROFFILE = 'readelf.profile'
1841 import cProfile
1842 cProfile.run('main(open("readelfout.txt", "w"))', PROFFILE)
1843
1844 # Dig in some profiling stats
1845 import pstats
1846 p = pstats.Stats(PROFFILE)
1847 p.sort_stats('cumulative').print_stats(25)
1848
1849
1850 #-------------------------------------------------------------------------------
1851 if __name__ == '__main__':
1852 main()
1853 #profile_main()