Add TLS and PowerPC to Machine and Program Headers description tables to match binuti...
[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 os, sys
11 from optparse import OptionParser
12 import string
13
14 # For running from development directory. It should take precedence over the
15 # installed pyelftools.
16 sys.path.insert(0, '.')
17
18
19 from elftools import __version__
20 from elftools.common.exceptions import ELFError
21 from elftools.common.py3compat import (
22 ifilter, byte2int, bytes2str, itervalues, str2bytes, iterbytes)
23 from elftools.elf.elffile import ELFFile
24 from elftools.elf.dynamic import DynamicSection, DynamicSegment
25 from elftools.elf.enums import ENUM_D_TAG
26 from elftools.elf.segments import InterpSegment
27 from elftools.elf.sections import NoteSection, SymbolTableSection
28 from elftools.elf.gnuversions import (
29 GNUVerSymSection, GNUVerDefSection,
30 GNUVerNeedSection,
31 )
32 from elftools.elf.relocation import RelocationSection
33 from elftools.elf.descriptions import (
34 describe_ei_class, describe_ei_data, describe_ei_version,
35 describe_ei_osabi, describe_e_type, describe_e_machine,
36 describe_e_version_numeric, describe_p_type, describe_p_flags,
37 describe_sh_type, describe_sh_flags,
38 describe_symbol_type, describe_symbol_bind, describe_symbol_visibility,
39 describe_symbol_shndx, describe_reloc_type, describe_dyn_tag,
40 describe_ver_flags, describe_note, describe_attr_tag_arm
41 )
42 from elftools.elf.constants import E_FLAGS
43 from elftools.dwarf.dwarfinfo import DWARFInfo
44 from elftools.dwarf.descriptions import (
45 describe_reg_name, describe_attr_value, set_global_machine_arch,
46 describe_CFI_instructions, describe_CFI_register_rule,
47 describe_CFI_CFA_rule,
48 )
49 from elftools.dwarf.constants import (
50 DW_LNS_copy, DW_LNS_set_file, DW_LNE_define_file)
51 from elftools.dwarf.callframe import CIE, FDE, ZERO
52
53
54 class ReadElf(object):
55 """ display_* methods are used to emit output into the output stream
56 """
57 def __init__(self, file, output):
58 """ file:
59 stream object with the ELF file to read
60
61 output:
62 output stream to write to
63 """
64 self.elffile = ELFFile(file)
65 self.output = output
66
67 # Lazily initialized if a debug dump is requested
68 self._dwarfinfo = None
69
70 self._versioninfo = None
71
72 def display_file_header(self):
73 """ Display the ELF file header
74 """
75 self._emitline('ELF Header:')
76 self._emit(' Magic: ')
77 self._emit(' '.join('%2.2x' % byte2int(b)
78 for b in self.elffile.e_ident_raw))
79 self._emitline(' ')
80 header = self.elffile.header
81 e_ident = header['e_ident']
82 self._emitline(' Class: %s' %
83 describe_ei_class(e_ident['EI_CLASS']))
84 self._emitline(' Data: %s' %
85 describe_ei_data(e_ident['EI_DATA']))
86 self._emitline(' Version: %s' %
87 describe_ei_version(e_ident['EI_VERSION']))
88 self._emitline(' OS/ABI: %s' %
89 describe_ei_osabi(e_ident['EI_OSABI']))
90 self._emitline(' ABI Version: %d' %
91 e_ident['EI_ABIVERSION'])
92 self._emitline(' Type: %s' %
93 describe_e_type(header['e_type']))
94 self._emitline(' Machine: %s' %
95 describe_e_machine(header['e_machine']))
96 self._emitline(' Version: %s' %
97 describe_e_version_numeric(header['e_version']))
98 self._emitline(' Entry point address: %s' %
99 self._format_hex(header['e_entry']))
100 self._emit(' Start of program headers: %s' %
101 header['e_phoff'])
102 self._emitline(' (bytes into file)')
103 self._emit(' Start of section headers: %s' %
104 header['e_shoff'])
105 self._emitline(' (bytes into file)')
106 self._emitline(' Flags: %s%s' %
107 (self._format_hex(header['e_flags']),
108 self.decode_flags(header['e_flags'])))
109 self._emitline(' Size of this header: %s (bytes)' %
110 header['e_ehsize'])
111 self._emitline(' Size of program headers: %s (bytes)' %
112 header['e_phentsize'])
113 self._emitline(' Number of program headers: %s' %
114 header['e_phnum'])
115 self._emitline(' Size of section headers: %s (bytes)' %
116 header['e_shentsize'])
117 self._emitline(' Number of section headers: %s' %
118 header['e_shnum'])
119 self._emitline(' Section header string table index: %s' %
120 header['e_shstrndx'])
121
122 def decode_flags(self, flags):
123 description = ""
124 if self.elffile['e_machine'] == "EM_ARM":
125 eabi = flags & E_FLAGS.EF_ARM_EABIMASK
126 flags &= ~E_FLAGS.EF_ARM_EABIMASK
127
128 if flags & E_FLAGS.EF_ARM_RELEXEC:
129 description += ', relocatable executabl'
130 flags &= ~E_FLAGS.EF_ARM_RELEXEC
131
132 if eabi == E_FLAGS.EF_ARM_EABI_VER5:
133 description += ', Version5 EABI'
134 if flags:
135 description += ', <unknown>'
136 else:
137 desrciption += ', <unrecognized EABI>'
138
139 elif self.elffile['e_machine'] == "EM_MIPS":
140 if flags & E_FLAGS.EF_MIPS_NOREORDER:
141 description += ", noreorder"
142 if flags & E_FLAGS.EF_MIPS_CPIC:
143 description += ", cpic"
144 if not (flags & E_FLAGS.EF_MIPS_ABI2) and not (flags & E_FLAGS.EF_MIPS_ABI_ON32):
145 description += ", o32"
146 if (flags & E_FLAGS.EF_MIPS_ARCH) == E_FLAGS.EF_MIPS_ARCH_1:
147 description += ", mips1"
148
149 return description
150
151 def display_program_headers(self, show_heading=True):
152 """ Display the ELF program headers.
153 If show_heading is True, displays the heading for this information
154 (Elf file type is...)
155 """
156 self._emitline()
157 if self.elffile.num_segments() == 0:
158 self._emitline('There are no program headers in this file.')
159 return
160
161 elfheader = self.elffile.header
162 if show_heading:
163 self._emitline('Elf file type is %s' %
164 describe_e_type(elfheader['e_type']))
165 self._emitline('Entry point is %s' %
166 self._format_hex(elfheader['e_entry']))
167 # readelf weirness - why isn't e_phoff printed as hex? (for section
168 # headers, it is...)
169 self._emitline('There are %s program headers, starting at offset %s' % (
170 elfheader['e_phnum'], elfheader['e_phoff']))
171 self._emitline()
172
173 self._emitline('Program Headers:')
174
175 # Now comes the table of program headers with their attributes. Note
176 # that due to different formatting constraints of 32-bit and 64-bit
177 # addresses, there are some conditions on elfclass here.
178 #
179 # First comes the table heading
180 #
181 if self.elffile.elfclass == 32:
182 self._emitline(' Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align')
183 else:
184 self._emitline(' Type Offset VirtAddr PhysAddr')
185 self._emitline(' FileSiz MemSiz Flags Align')
186
187 # Now the entries
188 #
189 for segment in self.elffile.iter_segments():
190 self._emit(' %-14s ' % describe_p_type(segment['p_type']))
191
192 if self.elffile.elfclass == 32:
193 self._emitline('%s %s %s %s %s %-3s %s' % (
194 self._format_hex(segment['p_offset'], fieldsize=6),
195 self._format_hex(segment['p_vaddr'], fullhex=True),
196 self._format_hex(segment['p_paddr'], fullhex=True),
197 self._format_hex(segment['p_filesz'], fieldsize=5),
198 self._format_hex(segment['p_memsz'], fieldsize=5),
199 describe_p_flags(segment['p_flags']),
200 self._format_hex(segment['p_align'])))
201 else: # 64
202 self._emitline('%s %s %s' % (
203 self._format_hex(segment['p_offset'], fullhex=True),
204 self._format_hex(segment['p_vaddr'], fullhex=True),
205 self._format_hex(segment['p_paddr'], fullhex=True)))
206 self._emitline(' %s %s %-3s %s' % (
207 self._format_hex(segment['p_filesz'], fullhex=True),
208 self._format_hex(segment['p_memsz'], fullhex=True),
209 describe_p_flags(segment['p_flags']),
210 # lead0x set to False for p_align, to mimic readelf.
211 # No idea why the difference from 32-bit mode :-|
212 self._format_hex(segment['p_align'], lead0x=False)))
213
214 if isinstance(segment, InterpSegment):
215 self._emitline(' [Requesting program interpreter: %s]' %
216 segment.get_interp_name())
217
218 # Sections to segments mapping
219 #
220 if self.elffile.num_sections() == 0:
221 # No sections? We're done
222 return
223
224 self._emitline('\n Section to Segment mapping:')
225 self._emitline(' Segment Sections...')
226
227 for nseg, segment in enumerate(self.elffile.iter_segments()):
228 self._emit(' %2.2d ' % nseg)
229
230 for section in self.elffile.iter_sections():
231 if ( not section.is_null() and
232 segment.section_in_segment(section)):
233 self._emit('%s ' % section.name)
234
235 self._emitline('')
236
237 def display_section_headers(self, show_heading=True):
238 """ Display the ELF section headers
239 """
240 elfheader = self.elffile.header
241 if show_heading:
242 self._emitline('There are %s section headers, starting at offset %s' % (
243 elfheader['e_shnum'], self._format_hex(elfheader['e_shoff'])))
244
245 if self.elffile.num_sections() == 0:
246 self._emitline('There are no sections in this file.')
247 return
248
249 self._emitline('\nSection Header%s:' % (
250 's' if elfheader['e_shnum'] > 1 else ''))
251
252 # Different formatting constraints of 32-bit and 64-bit addresses
253 #
254 if self.elffile.elfclass == 32:
255 self._emitline(' [Nr] Name Type Addr Off Size ES Flg Lk Inf Al')
256 else:
257 self._emitline(' [Nr] Name Type Address Offset')
258 self._emitline(' Size EntSize Flags Link Info Align')
259
260 # Now the entries
261 #
262 for nsec, section in enumerate(self.elffile.iter_sections()):
263 self._emit(' [%2u] %-17.17s %-15.15s ' % (
264 nsec, section.name, describe_sh_type(section['sh_type'])))
265
266 if self.elffile.elfclass == 32:
267 self._emitline('%s %s %s %s %3s %2s %3s %2s' % (
268 self._format_hex(section['sh_addr'], fieldsize=8, lead0x=False),
269 self._format_hex(section['sh_offset'], fieldsize=6, lead0x=False),
270 self._format_hex(section['sh_size'], fieldsize=6, lead0x=False),
271 self._format_hex(section['sh_entsize'], fieldsize=2, lead0x=False),
272 describe_sh_flags(section['sh_flags']),
273 section['sh_link'], section['sh_info'],
274 section['sh_addralign']))
275 else: # 64
276 self._emitline(' %s %s' % (
277 self._format_hex(section['sh_addr'], fullhex=True, lead0x=False),
278 self._format_hex(section['sh_offset'],
279 fieldsize=16 if section['sh_offset'] > 0xffffffff else 8,
280 lead0x=False)))
281 self._emitline(' %s %s %3s %2s %3s %s' % (
282 self._format_hex(section['sh_size'], fullhex=True, lead0x=False),
283 self._format_hex(section['sh_entsize'], fullhex=True, lead0x=False),
284 describe_sh_flags(section['sh_flags']),
285 section['sh_link'], section['sh_info'],
286 section['sh_addralign']))
287
288 self._emitline('Key to Flags:')
289 self._emitline(' W (write), A (alloc), X (execute), M (merge),'
290 ' S (strings), I (info),')
291 self._emitline(' L (link order), O (extra OS processing required),'
292 ' G (group), T (TLS),')
293 self._emitline(' C (compressed), x (unknown), o (OS specific),'
294 ' E (exclude),')
295 self._emit(' ')
296 if self.elffile['e_machine'] == 'EM_ARM':
297 self._emit('y (purecode), ')
298 self._emitline('p (processor specific)')
299
300 def display_symbol_tables(self):
301 """ Display the symbol tables contained in the file
302 """
303 self._init_versioninfo()
304
305 symbol_tables = [s for s in self.elffile.iter_sections()
306 if isinstance(s, SymbolTableSection)]
307
308 if not symbol_tables and self.elffile.num_sections() == 0:
309 self._emitline('')
310 self._emitline('Dynamic symbol information is not available for'
311 ' displaying symbols.')
312
313 for section in symbol_tables:
314 if not isinstance(section, SymbolTableSection):
315 continue
316
317 if section['sh_entsize'] == 0:
318 self._emitline("\nSymbol table '%s' has a sh_entsize of zero!" % (
319 section.name))
320 continue
321
322 self._emitline("\nSymbol table '%s' contains %s entries:" % (
323 section.name, section.num_symbols()))
324
325 if self.elffile.elfclass == 32:
326 self._emitline(' Num: Value Size Type Bind Vis Ndx Name')
327 else: # 64
328 self._emitline(' Num: Value Size Type Bind Vis Ndx Name')
329
330 for nsym, symbol in enumerate(section.iter_symbols()):
331 version_info = ''
332 # readelf doesn't display version info for Solaris versioning
333 if (section['sh_type'] == 'SHT_DYNSYM' and
334 self._versioninfo['type'] == 'GNU'):
335 version = self._symbol_version(nsym)
336 if (version['name'] != symbol.name and
337 version['index'] not in ('VER_NDX_LOCAL',
338 'VER_NDX_GLOBAL')):
339 if version['filename']:
340 # external symbol
341 version_info = '@%(name)s (%(index)i)' % version
342 else:
343 # internal symbol
344 if version['hidden']:
345 version_info = '@%(name)s' % version
346 else:
347 version_info = '@@%(name)s' % version
348
349 # symbol names are truncated to 25 chars, similarly to readelf
350 self._emitline('%6d: %s %5d %-7s %-6s %-7s %4s %.25s%s' % (
351 nsym,
352 self._format_hex(
353 symbol['st_value'], fullhex=True, lead0x=False),
354 symbol['st_size'],
355 describe_symbol_type(symbol['st_info']['type']),
356 describe_symbol_bind(symbol['st_info']['bind']),
357 describe_symbol_visibility(symbol['st_other']['visibility']),
358 describe_symbol_shndx(symbol['st_shndx']),
359 symbol.name,
360 version_info))
361
362 def display_dynamic_tags(self):
363 """ Display the dynamic tags contained in the file
364 """
365 has_dynamic_sections = False
366 for section in self.elffile.iter_sections():
367 if not isinstance(section, DynamicSection):
368 continue
369
370 has_dynamic_sections = True
371 self._emitline("\nDynamic section at offset %s contains %s entries:" % (
372 self._format_hex(section['sh_offset']),
373 section.num_tags()))
374 self._emitline(" Tag Type Name/Value")
375
376 padding = 20 + (8 if self.elffile.elfclass == 32 else 0)
377 for tag in section.iter_tags():
378 if tag.entry.d_tag == 'DT_NEEDED':
379 parsed = 'Shared library: [%s]' % tag.needed
380 elif tag.entry.d_tag == 'DT_RPATH':
381 parsed = 'Library rpath: [%s]' % tag.rpath
382 elif tag.entry.d_tag == 'DT_RUNPATH':
383 parsed = 'Library runpath: [%s]' % tag.runpath
384 elif tag.entry.d_tag == 'DT_SONAME':
385 parsed = 'Library soname: [%s]' % tag.soname
386 elif tag.entry.d_tag.endswith(('SZ', 'ENT')):
387 parsed = '%i (bytes)' % tag['d_val']
388 elif tag.entry.d_tag.endswith(('NUM', 'COUNT')):
389 parsed = '%i' % tag['d_val']
390 elif tag.entry.d_tag == 'DT_PLTREL':
391 s = describe_dyn_tag(tag.entry.d_val)
392 if s.startswith('DT_'):
393 s = s[3:]
394 parsed = '%s' % s
395 else:
396 parsed = '%#x' % tag['d_val']
397
398 self._emitline(" %s %-*s %s" % (
399 self._format_hex(ENUM_D_TAG.get(tag.entry.d_tag, tag.entry.d_tag),
400 fullhex=True, lead0x=True),
401 padding,
402 '(%s)' % (tag.entry.d_tag[3:],),
403 parsed))
404 if not has_dynamic_sections:
405 self._emitline("\nThere is no dynamic section in this file.")
406
407 def display_notes(self):
408 """ Display the notes contained in the file
409 """
410 for section in self.elffile.iter_sections():
411 if isinstance(section, NoteSection):
412 for note in section.iter_notes():
413 self._emitline("\nDisplaying notes found in: {}".format(
414 section.name))
415 self._emitline(' Owner Data size Description')
416 self._emitline(' %s %s\t%s' % (
417 note['n_name'].ljust(20),
418 self._format_hex(note['n_descsz'], fieldsize=8),
419 describe_note(note)))
420
421 def display_relocations(self):
422 """ Display the relocations contained in the file
423 """
424 has_relocation_sections = False
425 for section in self.elffile.iter_sections():
426 if not isinstance(section, RelocationSection):
427 continue
428
429 has_relocation_sections = True
430 self._emitline("\nRelocation section '%s' at offset %s contains %s entries:" % (
431 section.name,
432 self._format_hex(section['sh_offset']),
433 section.num_relocations()))
434 if section.is_RELA():
435 self._emitline(" Offset Info Type Sym. Value Sym. Name + Addend")
436 else:
437 self._emitline(" Offset Info Type Sym.Value Sym. Name")
438
439 # The symbol table section pointed to in sh_link
440 symtable = self.elffile.get_section(section['sh_link'])
441
442 for rel in section.iter_relocations():
443 hexwidth = 8 if self.elffile.elfclass == 32 else 12
444 self._emit('%s %s %-17.17s' % (
445 self._format_hex(rel['r_offset'],
446 fieldsize=hexwidth, lead0x=False),
447 self._format_hex(rel['r_info'],
448 fieldsize=hexwidth, lead0x=False),
449 describe_reloc_type(
450 rel['r_info_type'], self.elffile)))
451
452 if rel['r_info_sym'] == 0:
453 self._emitline()
454 continue
455
456 symbol = symtable.get_symbol(rel['r_info_sym'])
457 # Some symbols have zero 'st_name', so instead what's used is
458 # the name of the section they point at. Truncate symbol names
459 # (excluding version info) to 22 chars, similarly to readelf.
460 if symbol['st_name'] == 0:
461 symsec = self.elffile.get_section(symbol['st_shndx'])
462 symbol_name = symsec.name
463 version = ''
464 else:
465 symbol_name = symbol.name
466 version = self._symbol_version(rel['r_info_sym'])
467 version = (version['name']
468 if version and version['name'] else '')
469 symbol_name = '%.22s' % symbol_name
470 if version:
471 symbol_name += '@' + version
472
473 self._emit(' %s %s' % (
474 self._format_hex(
475 symbol['st_value'],
476 fullhex=True, lead0x=False),
477 symbol_name))
478 if section.is_RELA():
479 self._emit(' %s %x' % (
480 '+' if rel['r_addend'] >= 0 else '-',
481 abs(rel['r_addend'])))
482 self._emitline()
483
484 if not has_relocation_sections:
485 self._emitline('\nThere are no relocations in this file.')
486
487 def display_version_info(self):
488 """ Display the version info contained in the file
489 """
490 self._init_versioninfo()
491
492 if not self._versioninfo['type']:
493 self._emitline("\nNo version information found in this file.")
494 return
495
496 for section in self.elffile.iter_sections():
497 if isinstance(section, GNUVerSymSection):
498 self._print_version_section_header(
499 section, 'Version symbols', lead0x=False)
500
501 num_symbols = section.num_symbols()
502
503 # Symbol version info are printed four by four entries
504 for idx_by_4 in range(0, num_symbols, 4):
505
506 self._emit(' %03x:' % idx_by_4)
507
508 for idx in range(idx_by_4, min(idx_by_4 + 4, num_symbols)):
509
510 symbol_version = self._symbol_version(idx)
511 if symbol_version['index'] == 'VER_NDX_LOCAL':
512 version_index = 0
513 version_name = '(*local*)'
514 elif symbol_version['index'] == 'VER_NDX_GLOBAL':
515 version_index = 1
516 version_name = '(*global*)'
517 else:
518 version_index = symbol_version['index']
519 version_name = '(%(name)s)' % symbol_version
520
521 visibility = 'h' if symbol_version['hidden'] else ' '
522
523 self._emit('%4x%s%-13s' % (
524 version_index, visibility, version_name))
525
526 self._emitline()
527
528 elif isinstance(section, GNUVerDefSection):
529 self._print_version_section_header(
530 section, 'Version definition', indent=2)
531
532 offset = 0
533 for verdef, verdaux_iter in section.iter_versions():
534 verdaux = next(verdaux_iter)
535
536 name = verdaux.name
537 if verdef['vd_flags']:
538 flags = describe_ver_flags(verdef['vd_flags'])
539 # Mimic exactly the readelf output
540 flags += ' '
541 else:
542 flags = 'none'
543
544 self._emitline(' %s: Rev: %i Flags: %s Index: %i'
545 ' Cnt: %i Name: %s' % (
546 self._format_hex(offset, fieldsize=6,
547 alternate=True),
548 verdef['vd_version'], flags, verdef['vd_ndx'],
549 verdef['vd_cnt'], name))
550
551 verdaux_offset = (
552 offset + verdef['vd_aux'] + verdaux['vda_next'])
553 for idx, verdaux in enumerate(verdaux_iter, start=1):
554 self._emitline(' %s: Parent %i: %s' %
555 (self._format_hex(verdaux_offset, fieldsize=4),
556 idx, verdaux.name))
557 verdaux_offset += verdaux['vda_next']
558
559 offset += verdef['vd_next']
560
561 elif isinstance(section, GNUVerNeedSection):
562 self._print_version_section_header(section, 'Version needs')
563
564 offset = 0
565 for verneed, verneed_iter in section.iter_versions():
566
567 self._emitline(' %s: Version: %i File: %s Cnt: %i' % (
568 self._format_hex(offset, fieldsize=6,
569 alternate=True),
570 verneed['vn_version'], verneed.name,
571 verneed['vn_cnt']))
572
573 vernaux_offset = offset + verneed['vn_aux']
574 for idx, vernaux in enumerate(verneed_iter, start=1):
575 if vernaux['vna_flags']:
576 flags = describe_ver_flags(vernaux['vna_flags'])
577 # Mimic exactly the readelf output
578 flags += ' '
579 else:
580 flags = 'none'
581
582 self._emitline(
583 ' %s: Name: %s Flags: %s Version: %i' % (
584 self._format_hex(vernaux_offset, fieldsize=4),
585 vernaux.name, flags,
586 vernaux['vna_other']))
587
588 vernaux_offset += vernaux['vna_next']
589
590 offset += verneed['vn_next']
591
592 def display_arch_specific(self):
593 """ Display the architecture-specific info contained in the file.
594 """
595 if self.elffile['e_machine'] == 'EM_ARM':
596 self._display_arch_specific_arm()
597
598 def display_hex_dump(self, section_spec):
599 """ Display a hex dump of a section. section_spec is either a section
600 number or a name.
601 """
602 section = self._section_from_spec(section_spec)
603 if section is None:
604 # readelf prints the warning to stderr. Even though stderrs are not compared
605 # in tests, we comply with that behavior.
606 sys.stderr.write('readelf: Warning: Section \'%s\' was not dumped because it does not exist!\n' % (
607 section_spec))
608 return
609 if section['sh_type'] == 'SHT_NOBITS':
610 self._emitline("\nSection '%s' has no data to dump." % (
611 section_spec))
612 return
613
614 self._emitline("\nHex dump of section '%s':" % section.name)
615 self._note_relocs_for_section(section)
616 addr = section['sh_addr']
617 data = section.data()
618 dataptr = 0
619
620 while dataptr < len(data):
621 bytesleft = len(data) - dataptr
622 # chunks of 16 bytes per line
623 linebytes = 16 if bytesleft > 16 else bytesleft
624
625 self._emit(' %s ' % self._format_hex(addr, fieldsize=8))
626 for i in range(16):
627 if i < linebytes:
628 self._emit('%2.2x' % byte2int(data[dataptr + i]))
629 else:
630 self._emit(' ')
631 if i % 4 == 3:
632 self._emit(' ')
633
634 for i in range(linebytes):
635 c = data[dataptr + i : dataptr + i + 1]
636 if byte2int(c[0]) >= 32 and byte2int(c[0]) < 0x7f:
637 self._emit(bytes2str(c))
638 else:
639 self._emit(bytes2str(b'.'))
640
641 self._emitline()
642 addr += linebytes
643 dataptr += linebytes
644
645 self._emitline()
646
647 def display_string_dump(self, section_spec):
648 """ Display a strings dump of a section. section_spec is either a
649 section number or a name.
650 """
651 section = self._section_from_spec(section_spec)
652 if section is None:
653 # readelf prints the warning to stderr. Even though stderrs are not compared
654 # in tests, we comply with that behavior.
655 sys.stderr.write('readelf.py: Warning: Section \'%s\' was not dumped because it does not exist!\n' % (
656 section_spec))
657 return
658 if section['sh_type'] == 'SHT_NOBITS':
659 self._emitline("\nSection '%s' has no data to dump." % (
660 section_spec))
661 return
662
663 self._emitline("\nString dump of section '%s':" % section.name)
664
665 found = False
666 data = section.data()
667 dataptr = 0
668
669 while dataptr < len(data):
670 while ( dataptr < len(data) and
671 not (32 <= byte2int(data[dataptr]) <= 127)):
672 dataptr += 1
673
674 if dataptr >= len(data):
675 break
676
677 endptr = dataptr
678 while endptr < len(data) and byte2int(data[endptr]) != 0:
679 endptr += 1
680
681 found = True
682 self._emitline(' [%6x] %s' % (
683 dataptr, bytes2str(data[dataptr:endptr])))
684
685 dataptr = endptr
686
687 if not found:
688 self._emitline(' No strings found in this section.')
689 else:
690 self._emitline()
691
692 def display_debug_dump(self, dump_what):
693 """ Dump a DWARF section
694 """
695 self._init_dwarfinfo()
696 if self._dwarfinfo is None:
697 return
698
699 set_global_machine_arch(self.elffile.get_machine_arch())
700
701 if dump_what == 'info':
702 self._dump_debug_info()
703 elif dump_what == 'decodedline':
704 self._dump_debug_line_programs()
705 elif dump_what == 'frames':
706 self._dump_debug_frames()
707 elif dump_what == 'frames-interp':
708 self._dump_debug_frames_interp()
709 elif dump_what == 'aranges':
710 self._dump_debug_aranges()
711 else:
712 self._emitline('debug dump not yet supported for "%s"' % dump_what)
713
714 def _format_hex(self, addr, fieldsize=None, fullhex=False, lead0x=True,
715 alternate=False):
716 """ Format an address into a hexadecimal string.
717
718 fieldsize:
719 Size of the hexadecimal field (with leading zeros to fit the
720 address into. For example with fieldsize=8, the format will
721 be %08x
722 If None, the minimal required field size will be used.
723
724 fullhex:
725 If True, override fieldsize to set it to the maximal size
726 needed for the elfclass
727
728 lead0x:
729 If True, leading 0x is added
730
731 alternate:
732 If True, override lead0x to emulate the alternate
733 hexadecimal form specified in format string with the #
734 character: only non-zero values are prefixed with 0x.
735 This form is used by readelf.
736 """
737 if alternate:
738 if addr == 0:
739 lead0x = False
740 else:
741 lead0x = True
742 fieldsize -= 2
743
744 s = '0x' if lead0x else ''
745 if fullhex:
746 fieldsize = 8 if self.elffile.elfclass == 32 else 16
747 if fieldsize is None:
748 field = '%x'
749 else:
750 field = '%' + '0%sx' % fieldsize
751 return s + field % addr
752
753 def _print_version_section_header(self, version_section, name, lead0x=True,
754 indent=1):
755 """ Print a section header of one version related section (versym,
756 verneed or verdef) with some options to accomodate readelf
757 little differences between each header (e.g. indentation
758 and 0x prefixing).
759 """
760 if hasattr(version_section, 'num_versions'):
761 num_entries = version_section.num_versions()
762 else:
763 num_entries = version_section.num_symbols()
764
765 self._emitline("\n%s section '%s' contains %s entries:" %
766 (name, version_section.name, num_entries))
767 self._emitline('%sAddr: %s Offset: %s Link: %i (%s)' % (
768 ' ' * indent,
769 self._format_hex(
770 version_section['sh_addr'], fieldsize=16, lead0x=lead0x),
771 self._format_hex(
772 version_section['sh_offset'], fieldsize=6, lead0x=True),
773 version_section['sh_link'],
774 self.elffile.get_section(version_section['sh_link']).name
775 )
776 )
777
778 def _init_versioninfo(self):
779 """ Search and initialize informations about version related sections
780 and the kind of versioning used (GNU or Solaris).
781 """
782 if self._versioninfo is not None:
783 return
784
785 self._versioninfo = {'versym': None, 'verdef': None,
786 'verneed': None, 'type': None}
787
788 for section in self.elffile.iter_sections():
789 if isinstance(section, GNUVerSymSection):
790 self._versioninfo['versym'] = section
791 elif isinstance(section, GNUVerDefSection):
792 self._versioninfo['verdef'] = section
793 elif isinstance(section, GNUVerNeedSection):
794 self._versioninfo['verneed'] = section
795 elif isinstance(section, DynamicSection):
796 for tag in section.iter_tags():
797 if tag['d_tag'] == 'DT_VERSYM':
798 self._versioninfo['type'] = 'GNU'
799 break
800
801 if not self._versioninfo['type'] and (
802 self._versioninfo['verneed'] or self._versioninfo['verdef']):
803 self._versioninfo['type'] = 'Solaris'
804
805 def _symbol_version(self, nsym):
806 """ Return a dict containing information on the
807 or None if no version information is available
808 """
809 self._init_versioninfo()
810
811 symbol_version = dict.fromkeys(('index', 'name', 'filename', 'hidden'))
812
813 if (not self._versioninfo['versym'] or
814 nsym >= self._versioninfo['versym'].num_symbols()):
815 return None
816
817 symbol = self._versioninfo['versym'].get_symbol(nsym)
818 index = symbol.entry['ndx']
819 if not index in ('VER_NDX_LOCAL', 'VER_NDX_GLOBAL'):
820 index = int(index)
821
822 if self._versioninfo['type'] == 'GNU':
823 # In GNU versioning mode, the highest bit is used to
824 # store wether the symbol is hidden or not
825 if index & 0x8000:
826 index &= ~0x8000
827 symbol_version['hidden'] = True
828
829 if (self._versioninfo['verdef'] and
830 index <= self._versioninfo['verdef'].num_versions()):
831 _, verdaux_iter = \
832 self._versioninfo['verdef'].get_version(index)
833 symbol_version['name'] = next(verdaux_iter).name
834 else:
835 verneed, vernaux = \
836 self._versioninfo['verneed'].get_version(index)
837 symbol_version['name'] = vernaux.name
838 symbol_version['filename'] = verneed.name
839
840 symbol_version['index'] = index
841 return symbol_version
842
843 def _section_from_spec(self, spec):
844 """ Retrieve a section given a "spec" (either number or name).
845 Return None if no such section exists in the file.
846 """
847 try:
848 num = int(spec)
849 if num < self.elffile.num_sections():
850 return self.elffile.get_section(num)
851 else:
852 return None
853 except ValueError:
854 # Not a number. Must be a name then
855 return self.elffile.get_section_by_name(spec)
856
857 def _note_relocs_for_section(self, section):
858 """ If there are relocation sections pointing to the givne section,
859 emit a note about it.
860 """
861 for relsec in self.elffile.iter_sections():
862 if isinstance(relsec, RelocationSection):
863 info_idx = relsec['sh_info']
864 if self.elffile.get_section(info_idx) == section:
865 self._emitline(' Note: This section has relocations against it, but these have NOT been applied to this dump.')
866 return
867
868 def _init_dwarfinfo(self):
869 """ Initialize the DWARF info contained in the file and assign it to
870 self._dwarfinfo.
871 Leave self._dwarfinfo at None if no DWARF info was found in the file
872 """
873 if self._dwarfinfo is not None:
874 return
875
876 if self.elffile.has_dwarf_info():
877 self._dwarfinfo = self.elffile.get_dwarf_info()
878 else:
879 self._dwarfinfo = None
880
881 def _dump_debug_info(self):
882 """ Dump the debugging info section.
883 """
884 if not self._dwarfinfo.has_debug_info:
885 return
886 self._emitline('Contents of the %s section:\n' % self._dwarfinfo.debug_info_sec.name)
887
888 # Offset of the .debug_info section in the stream
889 section_offset = self._dwarfinfo.debug_info_sec.global_offset
890
891 for cu in self._dwarfinfo.iter_CUs():
892 self._emitline(' Compilation Unit @ offset %s:' %
893 self._format_hex(cu.cu_offset))
894 self._emitline(' Length: %s (%s)' % (
895 self._format_hex(cu['unit_length']),
896 '%s-bit' % cu.dwarf_format()))
897 self._emitline(' Version: %s' % cu['version']),
898 self._emitline(' Abbrev Offset: %s' % (
899 self._format_hex(cu['debug_abbrev_offset']))),
900 self._emitline(' Pointer Size: %s' % cu['address_size'])
901
902 # The nesting depth of each DIE within the tree of DIEs must be
903 # displayed. To implement this, a counter is incremented each time
904 # the current DIE has children, and decremented when a null die is
905 # encountered. Due to the way the DIE tree is serialized, this will
906 # correctly reflect the nesting depth
907 #
908 die_depth = 0
909 for die in cu.iter_DIEs():
910 self._emitline(' <%s><%x>: Abbrev Number: %s%s' % (
911 die_depth,
912 die.offset,
913 die.abbrev_code,
914 (' (%s)' % die.tag) if not die.is_null() else ''))
915 if die.is_null():
916 die_depth -= 1
917 continue
918
919 for attr in itervalues(die.attributes):
920 name = attr.name
921 # Unknown attribute values are passed-through as integers
922 if isinstance(name, int):
923 name = 'Unknown AT value: %x' % name
924 self._emitline(' <%x> %-18s: %s' % (
925 attr.offset,
926 name,
927 describe_attr_value(
928 attr, die, section_offset)))
929
930 if die.has_children:
931 die_depth += 1
932
933 self._emitline()
934
935 def _dump_debug_line_programs(self):
936 """ Dump the (decoded) line programs from .debug_line
937 The programs are dumped in the order of the CUs they belong to.
938 """
939 if not self._dwarfinfo.has_debug_info:
940 return
941 self._emitline('Decoded dump of debug contents of section %s:\n' % self._dwarfinfo.debug_line_sec.name)
942
943 for cu in self._dwarfinfo.iter_CUs():
944 lineprogram = self._dwarfinfo.line_program_for_CU(cu)
945
946 cu_filename = bytes2str(lineprogram['file_entry'][0].name)
947 if len(lineprogram['include_directory']) > 0:
948 dir_index = lineprogram['file_entry'][0].dir_index
949 if dir_index > 0:
950 dir = lineprogram['include_directory'][dir_index - 1]
951 else:
952 dir = b'.'
953 cu_filename = '%s/%s' % (bytes2str(dir), cu_filename)
954
955 self._emitline('CU: %s:' % cu_filename)
956 self._emitline('File name Line number Starting address')
957
958 # Print each state's file, line and address information. For some
959 # instructions other output is needed to be compatible with
960 # readelf.
961 for entry in lineprogram.get_entries():
962 state = entry.state
963 if state is None:
964 # Special handling for commands that don't set a new state
965 if entry.command == DW_LNS_set_file:
966 file_entry = lineprogram['file_entry'][entry.args[0] - 1]
967 if file_entry.dir_index == 0:
968 # current directory
969 self._emitline('\n./%s:[++]' % (
970 bytes2str(file_entry.name)))
971 else:
972 self._emitline('\n%s/%s:' % (
973 bytes2str(lineprogram['include_directory'][file_entry.dir_index - 1]),
974 bytes2str(file_entry.name)))
975 elif entry.command == DW_LNE_define_file:
976 self._emitline('%s:' % (
977 bytes2str(lineprogram['include_directory'][entry.args[0].dir_index])))
978 elif not state.end_sequence:
979 # readelf doesn't print the state after end_sequence
980 # instructions. I think it's a bug but to be compatible
981 # I don't print them too.
982 if lineprogram['version'] < 4:
983 self._emitline('%-35s %11d %18s' % (
984 bytes2str(lineprogram['file_entry'][state.file - 1].name),
985 state.line,
986 '0' if state.address == 0 else
987 self._format_hex(state.address)))
988 else:
989 self._emitline('%-35s %11d %18s[%d]' % (
990 bytes2str(lineprogram['file_entry'][state.file - 1].name),
991 state.line,
992 '0' if state.address == 0 else
993 self._format_hex(state.address),
994 state.op_index))
995 if entry.command == DW_LNS_copy:
996 # Another readelf oddity...
997 self._emitline()
998
999 def _dump_frames_info(self, section, cfi_entries):
1000 """ Dump the raw call frame info in a section.
1001
1002 `section` is the Section instance that contains the call frame info
1003 while `cfi_entries` must be an iterable that yields the sequence of
1004 CIE or FDE instances.
1005 """
1006 self._emitline('Contents of the %s section:' % section.name)
1007
1008 for entry in cfi_entries:
1009 if isinstance(entry, CIE):
1010 self._emitline('\n%08x %s %s CIE' % (
1011 entry.offset,
1012 self._format_hex(entry['length'], fullhex=True, lead0x=False),
1013 self._format_hex(entry['CIE_id'], fieldsize=8, lead0x=False)))
1014 self._emitline(' Version: %d' % entry['version'])
1015 self._emitline(' Augmentation: "%s"' % bytes2str(entry['augmentation']))
1016 self._emitline(' Code alignment factor: %u' % entry['code_alignment_factor'])
1017 self._emitline(' Data alignment factor: %d' % entry['data_alignment_factor'])
1018 self._emitline(' Return address column: %d' % entry['return_address_register'])
1019 if entry.augmentation_bytes:
1020 self._emitline(' Augmentation data: {}'.format(' '.join(
1021 '{:02x}'.format(ord(b))
1022 for b in iterbytes(entry.augmentation_bytes)
1023 )))
1024 self._emitline()
1025
1026 elif isinstance(entry, FDE):
1027 self._emitline('\n%08x %s %s FDE cie=%08x pc=%s..%s' % (
1028 entry.offset,
1029 self._format_hex(entry['length'], fullhex=True, lead0x=False),
1030 self._format_hex(entry['CIE_pointer'], fieldsize=8, lead0x=False),
1031 entry.cie.offset,
1032 self._format_hex(entry['initial_location'], fullhex=True, lead0x=False),
1033 self._format_hex(
1034 entry['initial_location'] + entry['address_range'],
1035 fullhex=True, lead0x=False)))
1036 if entry.augmentation_bytes:
1037 self._emitline(' Augmentation data: {}'.format(' '.join(
1038 '{:02x}'.format(ord(b))
1039 for b in iterbytes(entry.augmentation_bytes)
1040 )))
1041
1042 else: # ZERO terminator
1043 assert isinstance(entry, ZERO)
1044 self._emitline('\n%08x ZERO terminator' % entry.offset)
1045 continue
1046
1047 self._emit(describe_CFI_instructions(entry))
1048 self._emitline()
1049
1050 def _dump_debug_frames(self):
1051 """ Dump the raw frame info from .debug_frame and .eh_frame sections.
1052 """
1053 if self._dwarfinfo.has_EH_CFI():
1054 self._dump_frames_info(
1055 self._dwarfinfo.eh_frame_sec,
1056 self._dwarfinfo.EH_CFI_entries())
1057 self._emitline()
1058
1059 if self._dwarfinfo.has_CFI():
1060 self._dump_frames_info(
1061 self._dwarfinfo.debug_frame_sec,
1062 self._dwarfinfo.CFI_entries())
1063
1064 def _dump_debug_aranges(self):
1065 """ Dump the aranges table
1066 """
1067 aranges_table = self._dwarfinfo.get_aranges()
1068 if aranges_table == None:
1069 return
1070 # seems redundent, but we need to get the unsorted set of entries to match system readelf
1071 unordered_entries = aranges_table._get_entries()
1072
1073 if len(unordered_entries) == 0:
1074 self._emitline()
1075 self._emitline("Section '.debug_aranges' has no debugging data.")
1076 return
1077
1078 self._emitline('Contents of the %s section:' % self._dwarfinfo.debug_aranges_sec.name)
1079 self._emitline()
1080 prev_offset = None
1081 for entry in unordered_entries:
1082 if prev_offset != entry.info_offset:
1083 if entry != unordered_entries[0]:
1084 self._emitline(' %s %s' % (
1085 self._format_hex(0, fullhex=True, lead0x=False),
1086 self._format_hex(0, fullhex=True, lead0x=False)))
1087 self._emitline(' Length: %d' % (entry.unit_length))
1088 self._emitline(' Version: %d' % (entry.version))
1089 self._emitline(' Offset into .debug_info: 0x%x' % (entry.info_offset))
1090 self._emitline(' Pointer Size: %d' % (entry.address_size))
1091 self._emitline(' Segment Size: %d' % (entry.segment_size))
1092 self._emitline()
1093 self._emitline(' Address Length')
1094 self._emitline(' %s %s' % (
1095 self._format_hex(entry.begin_addr, fullhex=True, lead0x=False),
1096 self._format_hex(entry.length, fullhex=True, lead0x=False)))
1097 prev_offset = entry.info_offset
1098 self._emitline(' %s %s' % (
1099 self._format_hex(0, fullhex=True, lead0x=False),
1100 self._format_hex(0, fullhex=True, lead0x=False)))
1101
1102 def _dump_frames_interp_info(self, section, cfi_entries):
1103 """ Dump interpreted (decoded) frame information in a section.
1104
1105 `section` is the Section instance that contains the call frame info
1106 while `cfi_entries` must be an iterable that yields the sequence of
1107 CIE or FDE instances.
1108 """
1109 self._emitline('Contents of the %s section:' % section.name)
1110
1111 for entry in cfi_entries:
1112 if isinstance(entry, CIE):
1113 self._emitline('\n%08x %s %s CIE "%s" cf=%d df=%d ra=%d' % (
1114 entry.offset,
1115 self._format_hex(entry['length'], fullhex=True, lead0x=False),
1116 self._format_hex(entry['CIE_id'], fieldsize=8, lead0x=False),
1117 bytes2str(entry['augmentation']),
1118 entry['code_alignment_factor'],
1119 entry['data_alignment_factor'],
1120 entry['return_address_register']))
1121 ra_regnum = entry['return_address_register']
1122
1123 elif isinstance(entry, FDE):
1124 self._emitline('\n%08x %s %s FDE cie=%08x pc=%s..%s' % (
1125 entry.offset,
1126 self._format_hex(entry['length'], fullhex=True, lead0x=False),
1127 self._format_hex(entry['CIE_pointer'], fieldsize=8, lead0x=False),
1128 entry.cie.offset,
1129 self._format_hex(entry['initial_location'], fullhex=True, lead0x=False),
1130 self._format_hex(entry['initial_location'] + entry['address_range'],
1131 fullhex=True, lead0x=False)))
1132 ra_regnum = entry.cie['return_address_register']
1133
1134 # If the FDE brings adds no unwinding information compared to
1135 # its CIE, omit its table.
1136 if (len(entry.get_decoded().table) ==
1137 len(entry.cie.get_decoded().table)):
1138 continue
1139
1140 else: # ZERO terminator
1141 assert isinstance(entry, ZERO)
1142 self._emitline('\n%08x ZERO terminator' % entry.offset)
1143 continue
1144
1145
1146 # Print the heading row for the decoded table
1147 self._emit(' LOC')
1148 self._emit(' ' if entry.structs.address_size == 4 else ' ')
1149 self._emit(' CFA ')
1150
1151 # Decode the table and look at the registers it describes.
1152 # We build reg_order here to match readelf's order. In particular,
1153 # registers are sorted by their number, and the register matching
1154 # ra_regnum is always listed last with a special heading.
1155 decoded_table = entry.get_decoded()
1156 reg_order = sorted(ifilter(
1157 lambda r: r != ra_regnum,
1158 decoded_table.reg_order))
1159 if len(decoded_table.reg_order):
1160
1161 # Headings for the registers
1162 for regnum in reg_order:
1163 self._emit('%-6s' % describe_reg_name(regnum))
1164 self._emitline('ra ')
1165
1166 # Now include ra_regnum in reg_order to print its values
1167 # similarly to the other registers.
1168 reg_order.append(ra_regnum)
1169 else:
1170 self._emitline()
1171
1172 for line in decoded_table.table:
1173 self._emit(self._format_hex(
1174 line['pc'], fullhex=True, lead0x=False))
1175 self._emit(' %-9s' % describe_CFI_CFA_rule(line['cfa']))
1176
1177 for regnum in reg_order:
1178 if regnum in line:
1179 s = describe_CFI_register_rule(line[regnum])
1180 else:
1181 s = 'u'
1182 self._emit('%-6s' % s)
1183 self._emitline()
1184 self._emitline()
1185
1186 def _dump_debug_frames_interp(self):
1187 """ Dump the interpreted (decoded) frame information from .debug_frame
1188 and .eh_framae sections.
1189 """
1190 if self._dwarfinfo.has_EH_CFI():
1191 self._dump_frames_interp_info(
1192 self._dwarfinfo.eh_frame_sec,
1193 self._dwarfinfo.EH_CFI_entries())
1194 self._emitline()
1195
1196 if self._dwarfinfo.has_CFI():
1197 self._dump_frames_interp_info(
1198 self._dwarfinfo.debug_frame_sec,
1199 self._dwarfinfo.CFI_entries())
1200
1201 def _display_arch_specific_arm(self):
1202 """ Display the ARM architecture-specific info contained in the file.
1203 """
1204 attr_sec = self.elffile.get_section_by_name('.ARM.attributes')
1205
1206 for s in attr_sec.iter_subsections():
1207 self._emitline("Attribute Section: %s" % s.header['vendor_name'])
1208 for ss in s.iter_subsubsections():
1209 h_val = "" if ss.header.extra is None else " ".join("%d" % x for x in ss.header.extra)
1210 self._emitline(describe_attr_tag_arm(ss.header.tag, h_val, None))
1211
1212 for attr in ss.iter_attributes():
1213 self._emit(' ')
1214 self._emitline(describe_attr_tag_arm(attr.tag,
1215 attr.value,
1216 attr.extra))
1217
1218 def _emit(self, s=''):
1219 """ Emit an object to output
1220 """
1221 self.output.write(str(s))
1222
1223 def _emitline(self, s=''):
1224 """ Emit an object to output, followed by a newline
1225 """
1226 self.output.write(str(s).rstrip() + '\n')
1227
1228
1229 SCRIPT_DESCRIPTION = 'Display information about the contents of ELF format files'
1230 VERSION_STRING = '%%prog: based on pyelftools %s' % __version__
1231
1232
1233 def main(stream=None):
1234 # parse the command-line arguments and invoke ReadElf
1235 optparser = OptionParser(
1236 usage='usage: %prog [options] <elf-file>',
1237 description=SCRIPT_DESCRIPTION,
1238 add_help_option=False, # -h is a real option of readelf
1239 prog='readelf.py',
1240 version=VERSION_STRING)
1241 optparser.add_option('-d', '--dynamic',
1242 action='store_true', dest='show_dynamic_tags',
1243 help='Display the dynamic section')
1244 optparser.add_option('-H', '--help',
1245 action='store_true', dest='help',
1246 help='Display this information')
1247 optparser.add_option('-h', '--file-header',
1248 action='store_true', dest='show_file_header',
1249 help='Display the ELF file header')
1250 optparser.add_option('-l', '--program-headers', '--segments',
1251 action='store_true', dest='show_program_header',
1252 help='Display the program headers')
1253 optparser.add_option('-S', '--section-headers', '--sections',
1254 action='store_true', dest='show_section_header',
1255 help="Display the sections' headers")
1256 optparser.add_option('-e', '--headers',
1257 action='store_true', dest='show_all_headers',
1258 help='Equivalent to: -h -l -S')
1259 optparser.add_option('-s', '--symbols', '--syms',
1260 action='store_true', dest='show_symbols',
1261 help='Display the symbol table')
1262 optparser.add_option('-n', '--notes',
1263 action='store_true', dest='show_notes',
1264 help='Display the core notes (if present)')
1265 optparser.add_option('-r', '--relocs',
1266 action='store_true', dest='show_relocs',
1267 help='Display the relocations (if present)')
1268 optparser.add_option('-x', '--hex-dump',
1269 action='store', dest='show_hex_dump', metavar='<number|name>',
1270 help='Dump the contents of section <number|name> as bytes')
1271 optparser.add_option('-p', '--string-dump',
1272 action='store', dest='show_string_dump', metavar='<number|name>',
1273 help='Dump the contents of section <number|name> as strings')
1274 optparser.add_option('-V', '--version-info',
1275 action='store_true', dest='show_version_info',
1276 help='Display the version sections (if present)')
1277 optparser.add_option('-A', '--arch-specific',
1278 action='store_true', dest='show_arch_specific',
1279 help='Display the architecture-specific information (if present)')
1280 optparser.add_option('--debug-dump',
1281 action='store', dest='debug_dump_what', metavar='<what>',
1282 help=(
1283 'Display the contents of DWARF debug sections. <what> can ' +
1284 'one of {info,decodedline,frames,frames-interp}'))
1285
1286 options, args = optparser.parse_args()
1287
1288 if options.help or len(args) == 0:
1289 optparser.print_help()
1290 sys.exit(0)
1291
1292 if options.show_all_headers:
1293 do_file_header = do_section_header = do_program_header = True
1294 else:
1295 do_file_header = options.show_file_header
1296 do_section_header = options.show_section_header
1297 do_program_header = options.show_program_header
1298
1299 with open(args[0], 'rb') as file:
1300 try:
1301 readelf = ReadElf(file, stream or sys.stdout)
1302 if do_file_header:
1303 readelf.display_file_header()
1304 if do_section_header:
1305 readelf.display_section_headers(
1306 show_heading=not do_file_header)
1307 if do_program_header:
1308 readelf.display_program_headers(
1309 show_heading=not do_file_header)
1310 if options.show_dynamic_tags:
1311 readelf.display_dynamic_tags()
1312 if options.show_symbols:
1313 readelf.display_symbol_tables()
1314 if options.show_notes:
1315 readelf.display_notes()
1316 if options.show_relocs:
1317 readelf.display_relocations()
1318 if options.show_version_info:
1319 readelf.display_version_info()
1320 if options.show_arch_specific:
1321 readelf.display_arch_specific()
1322 if options.show_hex_dump:
1323 readelf.display_hex_dump(options.show_hex_dump)
1324 if options.show_string_dump:
1325 readelf.display_string_dump(options.show_string_dump)
1326 if options.debug_dump_what:
1327 readelf.display_debug_dump(options.debug_dump_what)
1328 except ELFError as ex:
1329 sys.stderr.write('ELF error: %s\n' % ex)
1330 sys.exit(1)
1331
1332
1333 def profile_main():
1334 # Run 'main' redirecting its output to readelfout.txt
1335 # Saves profiling information in readelf.profile
1336 PROFFILE = 'readelf.profile'
1337 import cProfile
1338 cProfile.run('main(open("readelfout.txt", "w"))', PROFFILE)
1339
1340 # Dig in some profiling stats
1341 import pstats
1342 p = pstats.Stats(PROFFILE)
1343 p.sort_stats('cumulative').print_stats(25)
1344
1345
1346 #-------------------------------------------------------------------------------
1347 if __name__ == '__main__':
1348 main()
1349 #profile_main()