readelf 2.41 with Ranges test excluded on 2 files (#489)
[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 if fieldsize is not None:
953 fieldsize -= 2
954
955 s = '0x' if lead0x else ''
956 if fullhex:
957 fieldsize = 8 if self.elffile.elfclass == 32 else 16
958 if fieldsize is None:
959 field = '%x'
960 else:
961 field = '%' + '0%sx' % fieldsize
962 return s + field % addr
963
964 def _print_version_section_header(self, version_section, name, lead0x=True,
965 indent=1):
966 """ Print a section header of one version related section (versym,
967 verneed or verdef) with some options to accomodate readelf
968 little differences between each header (e.g. indentation
969 and 0x prefixing).
970 """
971 if hasattr(version_section, 'num_versions'):
972 num_entries = version_section.num_versions()
973 else:
974 num_entries = version_section.num_symbols()
975
976 self._emitline("\n%s section '%s' contains %d %s:" % (
977 name, version_section.name, num_entries,
978 'entry' if num_entries == 1 else 'entries'))
979 self._emitline('%sAddr: %s Offset: %s Link: %i (%s)' % (
980 ' ' * indent,
981 self._format_hex(
982 version_section['sh_addr'], fieldsize=16, lead0x=lead0x),
983 self._format_hex(
984 version_section['sh_offset'], fieldsize=8, lead0x=True),
985 version_section['sh_link'],
986 self.elffile.get_section(version_section['sh_link']).name
987 )
988 )
989
990 def _init_versioninfo(self):
991 """ Search and initialize informations about version related sections
992 and the kind of versioning used (GNU or Solaris).
993 """
994 if self._versioninfo is not None:
995 return
996
997 self._versioninfo = {'versym': None, 'verdef': None,
998 'verneed': None, 'type': None}
999
1000 for section in self.elffile.iter_sections():
1001 if isinstance(section, GNUVerSymSection):
1002 self._versioninfo['versym'] = section
1003 elif isinstance(section, GNUVerDefSection):
1004 self._versioninfo['verdef'] = section
1005 elif isinstance(section, GNUVerNeedSection):
1006 self._versioninfo['verneed'] = section
1007 elif isinstance(section, DynamicSection):
1008 for tag in section.iter_tags():
1009 if tag['d_tag'] == 'DT_VERSYM':
1010 self._versioninfo['type'] = 'GNU'
1011 break
1012
1013 if not self._versioninfo['type'] and (
1014 self._versioninfo['verneed'] or self._versioninfo['verdef']):
1015 self._versioninfo['type'] = 'Solaris'
1016
1017 def _symbol_version(self, nsym):
1018 """ Return a dict containing information on the
1019 or None if no version information is available
1020 """
1021 self._init_versioninfo()
1022
1023 symbol_version = dict.fromkeys(('index', 'name', 'filename', 'hidden'))
1024
1025 if (not self._versioninfo['versym'] or
1026 nsym >= self._versioninfo['versym'].num_symbols()):
1027 return None
1028
1029 symbol = self._versioninfo['versym'].get_symbol(nsym)
1030 index = symbol.entry['ndx']
1031 if not index in ('VER_NDX_LOCAL', 'VER_NDX_GLOBAL'):
1032 index = int(index)
1033
1034 if self._versioninfo['type'] == 'GNU':
1035 # In GNU versioning mode, the highest bit is used to
1036 # store whether the symbol is hidden or not
1037 if index & 0x8000:
1038 index &= ~0x8000
1039 symbol_version['hidden'] = True
1040
1041 if (self._versioninfo['verdef'] and
1042 index <= self._versioninfo['verdef'].num_versions()):
1043 _, verdaux_iter = \
1044 self._versioninfo['verdef'].get_version(index)
1045 symbol_version['name'] = next(verdaux_iter).name
1046 else:
1047 verneed, vernaux = \
1048 self._versioninfo['verneed'].get_version(index)
1049 symbol_version['name'] = vernaux.name
1050 symbol_version['filename'] = verneed.name
1051
1052 symbol_version['index'] = index
1053 return symbol_version
1054
1055 def _section_from_spec(self, spec):
1056 """ Retrieve a section given a "spec" (either number or name).
1057 Return None if no such section exists in the file.
1058 """
1059 try:
1060 num = int(spec)
1061 if num < self.elffile.num_sections():
1062 return self.elffile.get_section(num)
1063 else:
1064 return None
1065 except ValueError:
1066 # Not a number. Must be a name then
1067 return self.elffile.get_section_by_name(spec)
1068
1069 def _get_symbol_shndx(self, symbol, symbol_index, symtab_index):
1070 """ Get the index into the section header table for the "symbol"
1071 at "symbol_index" located in the symbol table with section index
1072 "symtab_index".
1073 """
1074 symbol_shndx = symbol['st_shndx']
1075 if symbol_shndx != SHN_INDICES.SHN_XINDEX:
1076 return symbol_shndx
1077
1078 # Check for or lazily construct index section mapping (symbol table
1079 # index -> corresponding symbol table index section object)
1080 if self._shndx_sections is None:
1081 self._shndx_sections = {sec.symboltable: sec for sec in self.elffile.iter_sections()
1082 if isinstance(sec, SymbolTableIndexSection)}
1083 return self._shndx_sections[symtab_index].get_section_index(symbol_index)
1084
1085 def _note_relocs_for_section(self, section):
1086 """ If there are relocation sections pointing to the givne section,
1087 emit a note about it.
1088 """
1089 for relsec in self.elffile.iter_sections():
1090 if isinstance(relsec, RelocationSection):
1091 info_idx = relsec['sh_info']
1092 if self.elffile.get_section(info_idx) == section:
1093 self._emitline(' Note: This section has relocations against it, but these have NOT been applied to this dump.')
1094 return
1095
1096 def _init_dwarfinfo(self):
1097 """ Initialize the DWARF info contained in the file and assign it to
1098 self._dwarfinfo.
1099 Leave self._dwarfinfo at None if no DWARF info was found in the file
1100 """
1101 if self._dwarfinfo is not None:
1102 return
1103
1104 if self.elffile.has_dwarf_info():
1105 self._dwarfinfo = self.elffile.get_dwarf_info()
1106 else:
1107 self._dwarfinfo = None
1108
1109 def _dump_debug_info(self):
1110 """ Dump the debugging info section.
1111 """
1112 if not self._dwarfinfo.has_debug_info:
1113 return
1114 self._emitline('Contents of the %s section:\n' % self._dwarfinfo.debug_info_sec.name)
1115
1116 # Offset of the .debug_info section in the stream
1117 section_offset = self._dwarfinfo.debug_info_sec.global_offset
1118
1119 for cu in self._dwarfinfo.iter_CUs():
1120 self._emitline(' Compilation Unit @ offset %s:' %
1121 self._format_hex(cu.cu_offset, alternate=True))
1122 self._emitline(' Length: %s (%s)' % (
1123 self._format_hex(cu['unit_length']),
1124 '%s-bit' % cu.dwarf_format()))
1125 self._emitline(' Version: %s' % cu['version'])
1126 if cu['version'] >= 5:
1127 if cu.header.get("unit_type", ''):
1128 unit_type = cu.header.unit_type
1129 self._emitline(' Unit Type: %s (%d)' % (
1130 unit_type, ENUM_DW_UT.get(cu.header.unit_type, 0)))
1131 self._emitline(' Abbrev Offset: %s' % (
1132 self._format_hex(cu['debug_abbrev_offset'], alternate=True)))
1133 self._emitline(' Pointer Size: %s' % cu['address_size'])
1134 if unit_type in ('DW_UT_skeleton', 'DW_UT_split_compile'):
1135 self._emitline(' Dwo id: %s' % cu['dwo_id'])
1136 elif unit_type in ('DW_UT_type', 'DW_UT_split_type'):
1137 self._emitline(' Signature: 0x%x' % cu['type_signature'])
1138 self._emitline(' Type Offset: 0x%x' % cu['type_offset'])
1139 else:
1140 self._emitline(' Abbrev Offset: %s' % (
1141 self._format_hex(cu['debug_abbrev_offset'], alternate=True))),
1142 self._emitline(' Pointer Size: %s' % cu['address_size'])
1143
1144 # The nesting depth of each DIE within the tree of DIEs must be
1145 # displayed. To implement this, a counter is incremented each time
1146 # the current DIE has children, and decremented when a null die is
1147 # encountered. Due to the way the DIE tree is serialized, this will
1148 # correctly reflect the nesting depth
1149 #
1150 die_depth = 0
1151 current_function = None
1152 for die in cu.iter_DIEs():
1153 if die.tag == 'DW_TAG_subprogram':
1154 current_function = die
1155 self._emitline(' <%s><%x>: Abbrev Number: %s%s' % (
1156 die_depth,
1157 die.offset,
1158 die.abbrev_code,
1159 (' (%s)' % die.tag) if not die.is_null() else ''))
1160 if die.is_null():
1161 die_depth -= 1
1162 continue
1163
1164 for attr in die.attributes.values():
1165 name = attr.name
1166 # Unknown attribute values are passed-through as integers
1167 if isinstance(name, int):
1168 name = 'Unknown AT value: %x' % name
1169
1170 attr_desc = describe_attr_value(attr, die, section_offset)
1171
1172 if 'DW_OP_fbreg' in attr_desc and current_function and not 'DW_AT_frame_base' in current_function.attributes:
1173 postfix = ' [without dw_at_frame_base]'
1174 else:
1175 postfix = ''
1176
1177 self._emitline(' <%x> %-18s: %s%s' % (
1178 attr.offset,
1179 name,
1180 attr_desc,
1181 postfix))
1182
1183 if die.has_children:
1184 die_depth += 1
1185
1186 self._emitline()
1187
1188 def _dump_debug_line_programs(self):
1189 """ Dump the (decoded) line programs from .debug_line
1190 The programs are dumped in the order of the CUs they belong to.
1191 """
1192 if not self._dwarfinfo.has_debug_info:
1193 return
1194 self._emitline('Contents of the %s section:' % self._dwarfinfo.debug_line_sec.name)
1195 self._emitline()
1196 lineprogram_list = []
1197
1198 for cu in self._dwarfinfo.iter_CUs():
1199 # Avoid dumping same lineprogram multiple times
1200 lineprogram = self._dwarfinfo.line_program_for_CU(cu)
1201
1202 if lineprogram in lineprogram_list:
1203 continue
1204
1205 lineprogram_list.append(lineprogram)
1206 ver5 = lineprogram.header.version >= 5
1207
1208 cu_filename = bytes2str(lineprogram['file_entry'][0].name)
1209 if len(lineprogram['include_directory']) > 0:
1210 # GNU readelf 2.38 only outputs directory in wide mode
1211 self._emitline('%s:' % cu_filename)
1212 else:
1213 self._emitline('CU: %s:' % cu_filename)
1214
1215 self._emitline('File name Line number Starting address Stmt')
1216 # GNU readelf has a View column that we don't try to replicate
1217 # The autotest has logic in place to ignore that
1218
1219 # Print each state's file, line and address information. For some
1220 # instructions other output is needed to be compatible with
1221 # readelf.
1222 for entry in lineprogram.get_entries():
1223 state = entry.state
1224 if state is None:
1225 # Special handling for commands that don't set a new state
1226 if entry.command == DW_LNS_set_file:
1227 file_entry = lineprogram['file_entry'][entry.args[0] - 1]
1228 if file_entry.dir_index == 0:
1229 # current directory
1230 self._emitline('\n./%s:[++]' % (
1231 bytes2str(file_entry.name)))
1232 else:
1233 self._emitline('\n%s/%s:' % (
1234 bytes2str(lineprogram['include_directory'][file_entry.dir_index - 1]),
1235 bytes2str(file_entry.name)))
1236 elif entry.command == DW_LNE_define_file:
1237 self._emitline('%s:' % (
1238 bytes2str(lineprogram['include_directory'][entry.args[0].dir_index])))
1239 elif lineprogram['version'] < 4 or self.elffile['e_machine'] == 'EM_PPC64':
1240 self._emitline('%-35s %11s %18s %s' % (
1241 bytes2str(lineprogram['file_entry'][state.file - 1].name),
1242 state.line if not state.end_sequence else '-',
1243 '0' if state.address == 0 else self._format_hex(state.address),
1244 'x' if state.is_stmt and not state.end_sequence else ''))
1245 else:
1246 # In readelf, on non-VLIW machines there is no op_index postfix after address.
1247 # It used to be unconditional.
1248 self._emitline('%-35s %s %18s%s %s' % (
1249 bytes2str(lineprogram['file_entry'][state.file - 1].name),
1250 "%11d" % (state.line,) if not state.end_sequence else '-',
1251 '0' if state.address == 0 else self._format_hex(state.address),
1252 '' if lineprogram.header.maximum_operations_per_instruction == 1 else '[%d]' % (state.op_index,),
1253 'x' if state.is_stmt and not state.end_sequence else ''))
1254 if entry.command == DW_LNS_copy:
1255 # Another readelf oddity...
1256 self._emitline()
1257
1258 def _dump_frames_info(self, section, cfi_entries):
1259 """ Dump the raw call frame info in a section.
1260
1261 `section` is the Section instance that contains the call frame info
1262 while `cfi_entries` must be an iterable that yields the sequence of
1263 CIE or FDE instances.
1264 """
1265 self._emitline('Contents of the %s section:' % section.name)
1266
1267 for entry in cfi_entries:
1268 if isinstance(entry, CIE):
1269 self._emitline('\n%08x %s %s CIE' % (
1270 entry.offset,
1271 self._format_hex(entry['length'], fullhex=True, lead0x=False),
1272 self._format_hex(entry['CIE_id'], fieldsize=8, lead0x=False)))
1273 self._emitline(' Version: %d' % entry['version'])
1274 self._emitline(' Augmentation: "%s"' % bytes2str(entry['augmentation']))
1275 self._emitline(' Code alignment factor: %u' % entry['code_alignment_factor'])
1276 self._emitline(' Data alignment factor: %d' % entry['data_alignment_factor'])
1277 self._emitline(' Return address column: %d' % entry['return_address_register'])
1278 if entry.augmentation_bytes:
1279 self._emitline(' Augmentation data: {}'.format(' '.join(
1280 '{:02x}'.format(ord(b))
1281 for b in iterbytes(entry.augmentation_bytes)
1282 )))
1283 self._emitline()
1284
1285 elif isinstance(entry, FDE):
1286 self._emitline('\n%08x %s %s FDE cie=%08x pc=%s..%s' % (
1287 entry.offset,
1288 self._format_hex(entry['length'], fullhex=True, lead0x=False),
1289 self._format_hex(entry['CIE_pointer'], fieldsize=8, lead0x=False),
1290 entry.cie.offset,
1291 self._format_hex(entry['initial_location'], fullhex=True, lead0x=False),
1292 self._format_hex(
1293 entry['initial_location'] + entry['address_range'],
1294 fullhex=True, lead0x=False)))
1295 if entry.augmentation_bytes:
1296 self._emitline(' Augmentation data: {}'.format(' '.join(
1297 '{:02x}'.format(ord(b))
1298 for b in iterbytes(entry.augmentation_bytes)
1299 )))
1300
1301 else: # ZERO terminator
1302 assert isinstance(entry, ZERO)
1303 self._emitline('\n%08x ZERO terminator' % entry.offset)
1304 continue
1305
1306 self._emit(describe_CFI_instructions(entry))
1307 self._emitline()
1308
1309 def _dump_debug_frames(self):
1310 """ Dump the raw frame info from .debug_frame and .eh_frame sections.
1311 """
1312 if self._dwarfinfo.has_EH_CFI():
1313 self._dump_frames_info(
1314 self._dwarfinfo.eh_frame_sec,
1315 self._dwarfinfo.EH_CFI_entries())
1316 self._emitline()
1317
1318 if self._dwarfinfo.has_CFI():
1319 self._dump_frames_info(
1320 self._dwarfinfo.debug_frame_sec,
1321 self._dwarfinfo.CFI_entries())
1322
1323 def _dump_debug_namelut(self, what):
1324 """
1325 Dump the debug pubnames section.
1326 """
1327 if what == 'pubnames':
1328 namelut = self._dwarfinfo.get_pubnames()
1329 section = self._dwarfinfo.debug_pubnames_sec
1330 else:
1331 namelut = self._dwarfinfo.get_pubtypes()
1332 section = self._dwarfinfo.debug_pubtypes_sec
1333
1334 # readelf prints nothing if the section is not present.
1335 if namelut is None or len(namelut) == 0:
1336 return
1337
1338 self._emitline('Contents of the %s section:' % section.name)
1339 self._emitline()
1340
1341 cu_headers = namelut.get_cu_headers()
1342
1343 # go over CU-by-CU first and item-by-item next.
1344 for (cu_hdr, (cu_ofs, items)) in izip(cu_headers, itertools.groupby(
1345 namelut.items(), key = lambda x: x[1].cu_ofs)):
1346
1347 self._emitline(' Length: %d' % cu_hdr.unit_length)
1348 self._emitline(' Version: %d' % cu_hdr.version)
1349 self._emitline(' Offset into .debug_info section: 0x%x' % cu_hdr.debug_info_offset)
1350 self._emitline(' Size of area in .debug_info section: %d' % cu_hdr.debug_info_length)
1351 self._emitline()
1352 self._emitline(' Offset Name')
1353 for item in items:
1354 self._emitline(' %x %s' % (item[1].die_ofs - cu_ofs, item[0]))
1355 self._emitline()
1356
1357 def _dump_debug_aranges(self):
1358 """ Dump the aranges table
1359 """
1360 aranges_table = self._dwarfinfo.get_aranges()
1361 if aranges_table == None:
1362 return
1363 # Seems redundant, but we need to get the unsorted set of entries
1364 # to match system readelf.
1365 # Also, sometimes there are blank sections in aranges, but readelf
1366 # dumps them, so we should too.
1367 unordered_entries = aranges_table._get_entries(need_empty=True)
1368
1369 if len(unordered_entries) == 0:
1370 self._emitline()
1371 self._emitline("Section '.debug_aranges' has no debugging data.")
1372 return
1373
1374 self._emitline('Contents of the %s section:' % self._dwarfinfo.debug_aranges_sec.name)
1375 self._emitline()
1376 prev_offset = None
1377 for entry in unordered_entries:
1378 if prev_offset != entry.info_offset:
1379 if entry != unordered_entries[0]:
1380 self._emitline(' %s %s' % (
1381 self._format_hex(0, fullhex=True, lead0x=False),
1382 self._format_hex(0, fullhex=True, lead0x=False)))
1383 self._emitline(' Length: %d' % (entry.unit_length))
1384 self._emitline(' Version: %d' % (entry.version))
1385 self._emitline(' Offset into .debug_info: 0x%x' % (entry.info_offset))
1386 self._emitline(' Pointer Size: %d' % (entry.address_size))
1387 self._emitline(' Segment Size: %d' % (entry.segment_size))
1388 self._emitline()
1389 self._emitline(' Address Length')
1390 if entry.begin_addr != 0 or entry.length != 0:
1391 self._emitline(' %s %s' % (
1392 self._format_hex(entry.begin_addr, fullhex=True, lead0x=False),
1393 self._format_hex(entry.length, fullhex=True, lead0x=False)))
1394 prev_offset = entry.info_offset
1395 self._emitline(' %s %s' % (
1396 self._format_hex(0, fullhex=True, lead0x=False),
1397 self._format_hex(0, fullhex=True, lead0x=False)))
1398
1399 def _dump_frames_interp_info(self, section, cfi_entries):
1400 """ Dump interpreted (decoded) frame information in a section.
1401
1402 `section` is the Section instance that contains the call frame info
1403 while `cfi_entries` must be an iterable that yields the sequence of
1404 CIE or FDE instances.
1405 """
1406 self._emitline('Contents of the %s section:' % section.name)
1407
1408 for entry in cfi_entries:
1409 if isinstance(entry, CIE):
1410 self._emitline('\n%08x %s %s CIE "%s" cf=%d df=%d ra=%d' % (
1411 entry.offset,
1412 self._format_hex(entry['length'], fullhex=True, lead0x=False),
1413 self._format_hex(entry['CIE_id'], fieldsize=8, lead0x=False),
1414 bytes2str(entry['augmentation']),
1415 entry['code_alignment_factor'],
1416 entry['data_alignment_factor'],
1417 entry['return_address_register']))
1418 ra_regnum = entry['return_address_register']
1419
1420 elif isinstance(entry, FDE):
1421 self._emitline('\n%08x %s %s FDE cie=%08x pc=%s..%s' % (
1422 entry.offset,
1423 self._format_hex(entry['length'], fullhex=True, lead0x=False),
1424 self._format_hex(entry['CIE_pointer'], fieldsize=8, lead0x=False),
1425 entry.cie.offset,
1426 self._format_hex(entry['initial_location'], fullhex=True, lead0x=False),
1427 self._format_hex(entry['initial_location'] + entry['address_range'],
1428 fullhex=True, lead0x=False)))
1429 ra_regnum = entry.cie['return_address_register']
1430
1431 # If the FDE brings adds no unwinding information compared to
1432 # its CIE, omit its table.
1433 if (len(entry.get_decoded().table) ==
1434 len(entry.cie.get_decoded().table)):
1435 continue
1436
1437 else: # ZERO terminator
1438 assert isinstance(entry, ZERO)
1439 self._emitline('\n%08x ZERO terminator' % entry.offset)
1440 continue
1441
1442 # Decode the table.
1443 decoded_table = entry.get_decoded()
1444 if len(decoded_table.table) == 0:
1445 continue
1446
1447 # Print the heading row for the decoded table
1448 self._emit(' LOC')
1449 self._emit(' ' if entry.structs.address_size == 4 else ' ')
1450 self._emit(' CFA ')
1451
1452 # Look at the registers the decoded table describes.
1453 # We build reg_order here to match readelf's order. In particular,
1454 # registers are sorted by their number, and the register matching
1455 # ra_regnum is always listed last with a special heading.
1456 decoded_table = entry.get_decoded()
1457 reg_order = sorted(filter(
1458 lambda r: r != ra_regnum,
1459 decoded_table.reg_order))
1460 if len(decoded_table.reg_order):
1461
1462 # Headings for the registers
1463 for regnum in reg_order:
1464 self._emit('%-6s' % describe_reg_name(regnum))
1465 self._emitline('ra ')
1466
1467 # Now include ra_regnum in reg_order to print its values
1468 # similarly to the other registers.
1469 reg_order.append(ra_regnum)
1470 else:
1471 self._emitline()
1472
1473 for line in decoded_table.table:
1474 self._emit(self._format_hex(
1475 line['pc'], fullhex=True, lead0x=False))
1476
1477 if line['cfa'] is not None:
1478 s = describe_CFI_CFA_rule(line['cfa'])
1479 else:
1480 s = 'u'
1481 self._emit(' %-9s' % s)
1482
1483 for regnum in reg_order:
1484 if regnum in line:
1485 s = describe_CFI_register_rule(line[regnum])
1486 else:
1487 s = 'u'
1488 self._emit('%-6s' % s)
1489 self._emitline()
1490 self._emitline()
1491
1492 def _dump_debug_frames_interp(self):
1493 """ Dump the interpreted (decoded) frame information from .debug_frame
1494 and .eh_frame sections.
1495 """
1496 if self._dwarfinfo.has_EH_CFI():
1497 self._dump_frames_interp_info(
1498 self._dwarfinfo.eh_frame_sec,
1499 self._dwarfinfo.EH_CFI_entries())
1500 self._emitline()
1501
1502 if self._dwarfinfo.has_CFI():
1503 self._dump_frames_interp_info(
1504 self._dwarfinfo.debug_frame_sec,
1505 self._dwarfinfo.CFI_entries())
1506
1507 def _dump_debug_locations(self):
1508 """ Dump the location lists from .debug_loc/.debug_loclists section
1509 """
1510 di = self._dwarfinfo
1511 loc_lists_sec = di.location_lists()
1512 if not loc_lists_sec: # No locations section - readelf outputs nothing
1513 return
1514
1515 if isinstance(loc_lists_sec, LocationListsPair):
1516 self._dump_debug_locsection(di, loc_lists_sec._loc)
1517 self._dump_debug_locsection(di, loc_lists_sec._loclists)
1518 else:
1519 self._dump_debug_locsection(di, loc_lists_sec)
1520
1521 def _dump_debug_locsection(self, di, loc_lists_sec):
1522 """ Dump the location lists from .debug_loc/.debug_loclists section
1523 """
1524 ver5 = loc_lists_sec.version >= 5
1525 section_name = (di.debug_loclists_sec if ver5 else di.debug_loc_sec).name
1526
1527 # To dump a location list, one needs to know the CU.
1528 # Scroll through DIEs once, list the known location list offsets.
1529 # Don't need this CU/DIE scan if all entries are absolute or prefixed by base,
1530 # but let's not optimize for that yet.
1531 cu_map = dict() # Loc list offset => CU
1532 for cu in di.iter_CUs():
1533 for die in cu.iter_DIEs():
1534 for key in die.attributes:
1535 attr = die.attributes[key]
1536 if (LocationParser.attribute_has_location(attr, cu['version']) and
1537 LocationParser._attribute_has_loc_list(attr, cu['version'])):
1538 cu_map[attr.value] = cu
1539
1540 addr_size = di.config.default_address_size # In bytes, 4 or 8
1541 addr_width = addr_size * 2 # In hex digits, 8 or 16
1542 line_template = " %%08x %%0%dx %%0%dx %%s%%s" % (addr_width, addr_width)
1543
1544 loc_lists = list(loc_lists_sec.iter_location_lists())
1545 if len(loc_lists) == 0:
1546 # Present but empty locations section - readelf outputs a message
1547 self._emitline("\nSection '%s' has no debugging data." % (section_name,))
1548 return
1549
1550 self._emitline('Contents of the %s section:\n' % (section_name,))
1551 self._emitline(' Offset Begin End Expression')
1552 for loc_list in loc_lists:
1553 self._dump_loclist(loc_list, line_template, cu_map)
1554
1555 def _dump_loclist(self, loc_list, line_template, cu_map):
1556 in_views = False
1557 has_views = False
1558 base_ip = None
1559 loc_entry_count = 0
1560 cu = None
1561 for entry in loc_list:
1562 if isinstance(entry, LocationViewPair):
1563 has_views = in_views = True
1564 # The "v" before address is conditional in binutils, haven't figured out how
1565 self._emitline(" %08x v%015x v%015x location view pair" % (entry.entry_offset, entry.begin, entry.end))
1566 else:
1567 if in_views:
1568 in_views = False
1569 self._emitline("")
1570
1571 # Readelf quirk: indexed loclists don't show the real base IP
1572 if cu_map is None:
1573 base_ip = 0
1574 elif cu is None:
1575 cu = cu_map.get(entry.entry_offset, False)
1576 if not cu:
1577 raise ValueError("Location list can't be tracked to a CU")
1578
1579 if isinstance(entry, LocationEntry):
1580 if base_ip is None and not entry.is_absolute:
1581 base_ip = _get_cu_base(cu)
1582
1583 begin_offset = (0 if entry.is_absolute else base_ip) + entry.begin_offset
1584 end_offset = (0 if entry.is_absolute else base_ip) + entry.end_offset
1585 expr = describe_DWARF_expr(entry.loc_expr, cu.structs, cu.cu_offset)
1586 if has_views:
1587 view = loc_list[loc_entry_count]
1588 postfix = ' (start == end)' if entry.begin_offset == entry.end_offset and view.begin == view.end else ''
1589 self._emitline(' %08x v%015x v%015x views at %08x for:' %(
1590 entry.entry_offset,
1591 view.begin,
1592 view.end,
1593 view.entry_offset))
1594 self._emitline(' %016x %016x %s%s' %(
1595 begin_offset,
1596 end_offset,
1597 expr,
1598 postfix))
1599 loc_entry_count += 1
1600 else:
1601 postfix = ' (start == end)' if entry.begin_offset == entry.end_offset else ''
1602 self._emitline(line_template % (
1603 entry.entry_offset,
1604 begin_offset,
1605 end_offset,
1606 expr,
1607 postfix))
1608 elif isinstance(entry, LocBaseAddressEntry):
1609 base_ip = entry.base_address
1610 self._emitline(" %08x %016x (base address)" % (entry.entry_offset, entry.base_address))
1611
1612 # Pyelftools doesn't store the terminating entry,
1613 # but readelf emits its offset, so this should too.
1614 last = loc_list[-1]
1615 self._emitline(" %08x <End of list>" % (last.entry_offset + last.entry_length))
1616
1617 def _dump_debug_ranges(self):
1618 # TODO: GNU readelf format doesn't need entry_length?
1619 di = self._dwarfinfo
1620 range_lists_sec = di.range_lists()
1621 if not range_lists_sec: # No ranges section - readelf outputs nothing
1622 return
1623
1624 if isinstance(range_lists_sec, RangeListsPair):
1625 self._dump_debug_rangesection(di, range_lists_sec._ranges)
1626 self._dump_debug_rangesection(di, range_lists_sec._rnglists)
1627 else:
1628 self._dump_debug_rangesection(di, range_lists_sec)
1629
1630 def _dump_debug_rangesection(self, di, range_lists_sec):
1631 # Last amended to match readelf 2.41
1632 ver5 = range_lists_sec.version >= 5
1633 section_name = (di.debug_rnglists_sec if ver5 else di.debug_ranges_sec).name
1634 addr_size = di.config.default_address_size # In bytes, 4 or 8
1635 addr_width = addr_size * 2 # In hex digits, 8 or 16
1636 line_template = " %%08x %%0%dx %%0%dx %%s" % (addr_width, addr_width)
1637 base_template = " %%08x %%0%dx (base address)" % (addr_width)
1638
1639 # In order to determine the base address of the range
1640 # We need to know the corresponding CU.
1641 cu_map = {die.attributes['DW_AT_ranges'].value : cu # Range list offset => CU
1642 for cu in di.iter_CUs()
1643 for die in cu.iter_DIEs()
1644 if 'DW_AT_ranges' in die.attributes}
1645
1646 if ver5: # Dump by CUs - unsure at this point what does readelf do, ranges dump is buggy in 2.41
1647 self._emitline('Contents of the %s section:\n\n\n' % section_name)
1648 for cu in range_lists_sec.iter_CUs():
1649 self._emitline(' Table at Offset: %s:' % self._format_hex(cu.cu_offset, alternate=True))
1650 self._emitline(' Length: %s' % self._format_hex(cu.unit_length, alternate=True))
1651 self._emitline(' DWARF version: %d' % cu.version)
1652 self._emitline(' Address size: %d' % cu.address_size)
1653 self._emitline(' Segment size: %d' % cu.segment_selector_size)
1654 self._emitline(' Offset entries: %d\n' % cu.offset_count)
1655 # Is the offset table dumped too?
1656 for (i, range_list) in enumerate(range_lists_sec.iter_CU_range_lists_ex(cu)):
1657 list_offset = range_list[0].entry_offset
1658 range_list = list(range_lists_sec.translate_v5_entry(entry, cu_map[list_offset]) for entry in range_list)
1659 self._emitline(' Offset: %s, Index: %d' % (self._format_hex(list_offset, alternate=True), i))
1660 self._emitline(' Offset Begin End')
1661 self._dump_rangelist(range_list, cu_map, ver5, line_template, base_template)
1662 else: # Dump by DIE reference offset
1663 range_lists = list(range_lists_sec.iter_range_lists())
1664 if len(range_lists) == 0:
1665 # Present but empty ranges section - readelf outputs a message
1666 self._emitline("\nSection '%s' has no debugging data." % section_name)
1667 return
1668
1669 self._emitline('Contents of the %s section:\n\n\n' % section_name)
1670 self._emitline(' Offset Begin End')
1671
1672 for range_list in range_lists:
1673 if len(range_list) == 0: # working around a bogus behavior in readelf 2.41
1674 # No entries means no offset. Dirty hack: peek the stream position
1675 range_list_offset = range_lists_sec.stream.tell() - self._dwarfinfo.config.default_address_size*2
1676 self._emitline(' %08x <End of list>' % (range_list_offset))
1677 else:
1678 self._dump_rangelist(range_list, cu_map, ver5, line_template, base_template)
1679
1680 def _dump_rangelist(self, range_list, cu_map, ver5, line_template, base_template):
1681 # Weird discrepancy in binutils: for DWARFv5 it outputs entry offset,
1682 # for DWARF<=4 list offset.
1683 first = range_list[0]
1684 base_ip = _get_cu_base(cu_map[first.entry_offset])
1685 for entry in range_list:
1686 if isinstance(entry, RangeEntry):
1687 postfix = ' (start == end)' if entry.begin_offset == entry.end_offset else ''
1688 self._emitline(line_template % (
1689 entry.entry_offset if ver5 else first.entry_offset,
1690 (0 if entry.is_absolute else base_ip) + entry.begin_offset,
1691 (0 if entry.is_absolute else base_ip) + entry.end_offset,
1692 postfix))
1693 elif isinstance(entry,RangeBaseAddressEntry):
1694 base_ip = entry.base_address
1695 self._emitline(base_template % (
1696 entry.entry_offset if ver5 else first.entry_offset,
1697 entry.base_address))
1698 else:
1699 raise NotImplementedError("Unknown object in a range list")
1700 last = range_list[-1]
1701 self._emitline(' %08x <End of list>' % (last.entry_offset + last.entry_length if ver5 else first.entry_offset))
1702
1703 def _display_attributes(self, attr_sec, descriptor):
1704 """ Display the attributes contained in the section.
1705 """
1706 for s in attr_sec.iter_subsections():
1707 self._emitline("Attribute Section: %s" % s.header['vendor_name'])
1708 for ss in s.iter_subsubsections():
1709 h_val = "" if ss.header.extra is None else " ".join("%d" % x for x in ss.header.extra)
1710 self._emitline(descriptor(ss.header.tag, h_val, None))
1711
1712 for attr in ss.iter_attributes():
1713 self._emit(' ')
1714 self._emitline(descriptor(attr.tag, attr.value, attr.extra))
1715
1716 def _display_arch_specific_arm(self):
1717 """ Display the ARM architecture-specific info contained in the file.
1718 """
1719 attr_sec = self.elffile.get_section_by_name('.ARM.attributes')
1720 self._display_attributes(attr_sec, describe_attr_tag_arm)
1721
1722 def _display_arch_specific_riscv(self):
1723 """ Display the RISC-V architecture-specific info contained in the file.
1724 """
1725 attr_sec = self.elffile.get_section_by_name('.riscv.attributes')
1726 self._display_attributes(attr_sec, describe_attr_tag_riscv)
1727
1728 def _emit(self, s=''):
1729 """ Emit an object to output
1730 """
1731 self.output.write(str(s))
1732
1733 def _emitline(self, s=''):
1734 """ Emit an object to output, followed by a newline
1735 """
1736 self.output.write(str(s).rstrip() + '\n')
1737
1738
1739 SCRIPT_DESCRIPTION = 'Display information about the contents of ELF format files'
1740 VERSION_STRING = '%%(prog)s: based on pyelftools %s' % __version__
1741
1742
1743 def main(stream=None):
1744 # parse the command-line arguments and invoke ReadElf
1745 argparser = argparse.ArgumentParser(
1746 usage='usage: %(prog)s [options] <elf-file>',
1747 description=SCRIPT_DESCRIPTION,
1748 add_help=False, # -h is a real option of readelf
1749 prog='readelf.py')
1750 argparser.add_argument('file',
1751 nargs='?', default=None,
1752 help='ELF file to parse')
1753 argparser.add_argument('-v', '--version',
1754 action='version', version=VERSION_STRING)
1755 argparser.add_argument('-d', '--dynamic',
1756 action='store_true', dest='show_dynamic_tags',
1757 help='Display the dynamic section')
1758 argparser.add_argument('-H', '--help',
1759 action='store_true', dest='help',
1760 help='Display this information')
1761 argparser.add_argument('-h', '--file-header',
1762 action='store_true', dest='show_file_header',
1763 help='Display the ELF file header')
1764 argparser.add_argument('-l', '--program-headers', '--segments',
1765 action='store_true', dest='show_program_header',
1766 help='Display the program headers')
1767 argparser.add_argument('-S', '--section-headers', '--sections',
1768 action='store_true', dest='show_section_header',
1769 help="Display the sections' headers")
1770 argparser.add_argument('-e', '--headers',
1771 action='store_true', dest='show_all_headers',
1772 help='Equivalent to: -h -l -S')
1773 argparser.add_argument('-s', '--symbols', '--syms',
1774 action='store_true', dest='show_symbols',
1775 help='Display the symbol table')
1776 argparser.add_argument('-n', '--notes',
1777 action='store_true', dest='show_notes',
1778 help='Display the core notes (if present)')
1779 argparser.add_argument('-r', '--relocs',
1780 action='store_true', dest='show_relocs',
1781 help='Display the relocations (if present)')
1782 argparser.add_argument('-au', '--arm-unwind',
1783 action='store_true', dest='show_arm_unwind',
1784 help='Display the armeabi unwind information (if present)')
1785 argparser.add_argument('-x', '--hex-dump',
1786 action='store', dest='show_hex_dump', metavar='<number|name>',
1787 help='Dump the contents of section <number|name> as bytes')
1788 argparser.add_argument('-p', '--string-dump',
1789 action='store', dest='show_string_dump', metavar='<number|name>',
1790 help='Dump the contents of section <number|name> as strings')
1791 argparser.add_argument('-V', '--version-info',
1792 action='store_true', dest='show_version_info',
1793 help='Display the version sections (if present)')
1794 argparser.add_argument('-A', '--arch-specific',
1795 action='store_true', dest='show_arch_specific',
1796 help='Display the architecture-specific information (if present)')
1797 argparser.add_argument('--debug-dump',
1798 action='store', dest='debug_dump_what', metavar='<what>',
1799 help=(
1800 'Display the contents of DWARF debug sections. <what> can ' +
1801 'one of {info,decodedline,frames,frames-interp,aranges,pubtypes,pubnames,loc,Ranges}'))
1802 argparser.add_argument('--traceback',
1803 action='store_true', dest='show_traceback',
1804 help='Dump the Python traceback on ELFError'
1805 ' exceptions from elftools')
1806
1807 args = argparser.parse_args()
1808
1809 if args.help or not args.file:
1810 argparser.print_help()
1811 sys.exit(0)
1812
1813 if args.show_all_headers:
1814 do_file_header = do_section_header = do_program_header = True
1815 else:
1816 do_file_header = args.show_file_header
1817 do_section_header = args.show_section_header
1818 do_program_header = args.show_program_header
1819
1820 with open(args.file, 'rb') as file:
1821 try:
1822 readelf = ReadElf(file, stream or sys.stdout)
1823 if do_file_header:
1824 readelf.display_file_header()
1825 if do_section_header:
1826 readelf.display_section_headers(
1827 show_heading=not do_file_header)
1828 if do_program_header:
1829 readelf.display_program_headers(
1830 show_heading=not do_file_header)
1831 if args.show_dynamic_tags:
1832 readelf.display_dynamic_tags()
1833 if args.show_symbols:
1834 readelf.display_symbol_tables()
1835 if args.show_notes:
1836 readelf.display_notes()
1837 if args.show_relocs:
1838 readelf.display_relocations()
1839 if args.show_arm_unwind:
1840 readelf.display_arm_unwind()
1841 if args.show_version_info:
1842 readelf.display_version_info()
1843 if args.show_arch_specific:
1844 readelf.display_arch_specific()
1845 if args.show_hex_dump:
1846 readelf.display_hex_dump(args.show_hex_dump)
1847 if args.show_string_dump:
1848 readelf.display_string_dump(args.show_string_dump)
1849 if args.debug_dump_what:
1850 readelf.display_debug_dump(args.debug_dump_what)
1851 except ELFError as ex:
1852 sys.stdout.flush()
1853 sys.stderr.write('ELF error: %s\n' % ex)
1854 if args.show_traceback:
1855 traceback.print_exc()
1856 sys.exit(1)
1857
1858
1859 def profile_main():
1860 # Run 'main' redirecting its output to readelfout.txt
1861 # Saves profiling information in readelf.profile
1862 PROFFILE = 'readelf.profile'
1863 import cProfile
1864 cProfile.run('main(open("readelfout.txt", "w"))', PROFFILE)
1865
1866 # Dig in some profiling stats
1867 import pstats
1868 p = pstats.Stats(PROFFILE)
1869 p.sort_stats('cumulative').print_stats(25)
1870
1871
1872 #-------------------------------------------------------------------------------
1873 if __name__ == '__main__':
1874 main()
1875 #profile_main()