class RelocationSection(Section):
+ """ ELF relocation section. Serves as a collection of Relocation entries.
+ """
def __init__(self, header, name, stream, elffile):
super(RelocationSection, self).__init__(header, name, stream)
self.elffile = elffile
--- /dev/null
+#-------------------------------------------------------------------------------
+# elftools example: dwarf_die_tree.py
+#
+# In the .debug_info section, Dwarf Information Entries (DIEs) form a tree.
+# pyelftools provides easy access to this tree, as demonstrated here.
+#
+# Eli Bendersky (eliben@gmail.com)
+# This code is in the public domain
+#-------------------------------------------------------------------------------
+from __future__ import print_function
+import sys
+from elftools.elf.elffile import ELFFile
+
+
+def process_file(filename):
+ print('Processing file:', filename)
+ with open(filename) as f:
+ elffile = ELFFile(f)
+
+ if not elffile.has_dwarf_info():
+ print(' file has no DWARF info')
+ return
+
+ # get_dwarf_info returns a DWARFInfo context object, which is the
+ # starting point for all DWARF-based processing in pyelftools.
+ dwarfinfo = elffile.get_dwarf_info()
+
+ for CU in dwarfinfo.iter_CUs():
+ # DWARFInfo allows to iterate over the compile units contained in
+ # the .debug_info section. CU is a CompileUnit object, with some
+ # computed attributes (such as its offset in the section) and
+ # a header which conforms to the DWARF standard. The access to
+ # header elements is, as usual, via item-lookup.
+ print(' Found a compile unit at offset %s, length %s' % (
+ CU.cu_offset, CU['unit_length']))
+
+ # Start with the top DIE, the root for this CU's DIE tree
+ top_DIE = CU.get_top_DIE()
+ print(' Top DIE with tag=%s' % top_DIE.tag)
+
+ # Each DIE holds an OrderedDict of attributes, mapping names to
+ # values. Values are represented by AttributeValue objects in
+ # elftools/dwarf/die.py
+ # We're interested in the DW_AT_name attribute. Note that its value
+ # is usually a string taken from the .debug_string section. This
+ # is done transparently by the library, and such a value will be
+ # simply given as a string.
+ name_attr = top_DIE.attributes['DW_AT_name']
+ print(' name=%s' % name_attr.value)
+
+ # Display DIEs recursively starting with top_DIE
+ die_info_rec(top_DIE)
+
+
+def die_info_rec(die, indent_level=' '):
+ """ A recursive function for showing information about a DIE and its
+ children.
+ """
+ print(indent_level + 'DIE tag=%s' % die.tag)
+ child_indent = indent_level + ' '
+ for child in die.iter_children():
+ die_info_rec(child, child_indent)
+
+
+if __name__ == '__main__':
+ for filename in sys.argv[1:]:
+ process_file(filename)
+
+
+
+
+
+
--- /dev/null
+#-------------------------------------------------------------------------------
+# elftools example: elf_low_high_api.py
+#
+# A simple example that shows some usage of the low-level API pyelftools
+# provides versus the high-level API.
+#
+# Eli Bendersky (eliben@gmail.com)
+# This code is in the public domain
+#-------------------------------------------------------------------------------
+from __future__ import print_function
+import sys
+from elftools.elf.elffile import ELFFile
+from elftools.elf.sections import SymbolTableSection
+
+
+def process_file(filename):
+ print('Processing file:', filename)
+ with open(filename) as f:
+ section_info_lowlevel(f)
+ f.seek(0)
+ section_info_highlevel(f)
+
+
+def section_info_lowlevel(stream):
+ print('Low level API...')
+ # We'll still be using the ELFFile context object. It's just too
+ # convenient to give up, even in the low-level API demonstation :-)
+ elffile = ELFFile(stream)
+
+ # The e_shnum ELF header field says how many sections there are in a file
+ print(' %s sections' % elffile['e_shnum'])
+
+ # We need section #40
+ section_offset = elffile['e_shoff'] + 40 * elffile['e_shentsize']
+
+ # Parse the section header using structs.Elf_Shdr
+ stream.seek(section_offset)
+ section_header = elffile.structs.Elf_Shdr.parse_stream(stream)
+
+ # Some details about the section. Note that the section name is a pointer
+ # to the object's string table, so it's only a number here. To get to the
+ # actual name one would need to parse the string table section and extract
+ # the name from there (or use the high-level API!)
+ print(' Section name: %s, type: %s' % (
+ section_header['sh_name'], section_header['sh_type']))
+
+
+def section_info_highlevel(stream):
+ print('High level API...')
+ elffile = ELFFile(stream)
+
+ # Just use the public methods of ELFFile to get what we need
+ print(' %s sections' % elffile.num_sections())
+ section = elffile.get_section(40)
+
+ # A section type is in its header, but the name was decoded and placed in
+ # a public attribute.
+ print(' Section name: %s, type: %s' %(
+ section.name, section['sh_type']))
+
+ # But there's more... If this section is a symbol table section (which is
+ # the case in the sample ELF file that comes with the examples), we can
+ # get some more information about it.
+ if isinstance(section, SymbolTableSection):
+ print(" It's a symbol section with %s symbols" % section.num_symbols())
+ print(" The name of symbol #60 is: %s" % (
+ section.get_symbol(60).name))
+
+
+if __name__ == '__main__':
+ for filename in sys.argv[1:]:
+ process_file(filename)
+
+
--- /dev/null
+#-------------------------------------------------------------------------------
+# elftools example: elf_relocations.py
+#
+# An example of obtaining a relocation section from an ELF file and examining
+# the relocation entries it contains.
+#
+# Eli Bendersky (eliben@gmail.com)
+# This code is in the public domain
+#-------------------------------------------------------------------------------
+from __future__ import print_function
+import sys
+from elftools.elf.elffile import ELFFile
+from elftools.elf.relocation import RelocationSection
+
+
+def process_file(filename):
+ print('Processing file:', filename)
+ with open(filename) as f:
+ elffile = ELFFile(f)
+
+ # Read the .rela.dyn section from the file, by explicitly asking
+ # ELFFile for this section
+ reladyn_name = '.rela.dyn'
+ reladyn = elffile.get_section_by_name(reladyn_name)
+
+ if not isinstance(reladyn, RelocationSection):
+ print(' The file has no %s section' % reladyn_name)
+
+ print(' %s section with %s relocations' % (
+ reladyn_name, reladyn.num_relocations()))
+
+ for reloc in reladyn.iter_relocations():
+ # Use the Relocation's object ability to pretty-print itself to a
+ # string to examine it
+ print(' ', reloc)
+
+ # Relocation entry attributes are available through item lookup
+ print(' offset = %s' % reloc['r_offset'])
+
+
+if __name__ == '__main__':
+ for filename in sys.argv[1:]:
+ process_file(filename)
+
+
+
# Eli Bendersky (eliben@gmail.com)
# This code is in the public domain
#-------------------------------------------------------------------------------
+from __future__ import print_function
import sys
from elftools.elf.elffile import ELFFile
def process_file(filename):
with open(filename) as f:
elffile = ELFFile(f)
- print '%s: elfclass is %s' % (filename, elffile.elfclass)
+ # elfclass is a public attribute of ELFFile, read from its header
+ print('%s: elfclass is %s' % (filename, elffile.elfclass))
if elffile.has_dwarf_info():
dwarfinfo = elffile.get_dwarf_info()
for CU in dwarfinfo.iter_CUs():
- print ' CU at offset 0x%x. address_size is %s' % (
- CU.cu_offset, CU['address_size'])
+ # cu_offset is a public attribute of CU
+ # address_size is part of the CU header
+ print(' CU at offset 0x%x. address_size is %s' % (
+ CU.cu_offset, CU['address_size']))
+
if __name__ == '__main__':
for filename in sys.argv[1:]:
--- /dev/null
+#-------------------------------------------------------------------------------
+# elftools example: examine_dwarf_info.py
+#
+# An example of examining information in the .debug_info section of an ELF file.
+#
+# Eli Bendersky (eliben@gmail.com)
+# This code is in the public domain
+#-------------------------------------------------------------------------------
+from __future__ import print_function
+import sys
+from elftools.elf.elffile import ELFFile
+
+
+def process_file(filename):
+ print('Processing file:', filename)
+ with open(filename) as f:
+ elffile = ELFFile(f)
+
+ if not elffile.has_dwarf_info():
+ print(' file has no DWARF info')
+ return
+
+ # get_dwarf_info returns a DWARFInfo context object, which is the
+ # starting point for all DWARF-based processing in pyelftools.
+ dwarfinfo = elffile.get_dwarf_info()
+
+ for CU in dwarfinfo.iter_CUs():
+ # DWARFInfo allows to iterate over the compile units contained in
+ # the .debug_info section. CU is a CompileUnit object, with some
+ # computed attributes (such as its offset in the section) and
+ # a header which conforms to the DWARF standard. The access to
+ # header elements is, as usual, via item-lookup.
+ print(' Found a compile unit at offset %s, length %s' % (
+ CU.cu_offset, CU['unit_length']))
+
+ # The first DIE in each compile unit describes it.
+ top_DIE = CU.get_top_DIE()
+ print(' Top DIE with tag=%s' % top_DIE.tag)
+
+ # Each DIE holds an OrderedDict of attributes, mapping names to
+ # values. Values are represented by AttributeValue objects in
+ # elftools/dwarf/die.py
+ # We're interested in the DW_AT_name attribute. Note that its value
+ # is usually a string taken from the .debug_string section. This
+ # is done transparently by the library, and such a value will be
+ # simply given as a string.
+ name_attr = top_DIE.attributes['DW_AT_name']
+ print(' name=%s' % name_attr.value)
+
+if __name__ == '__main__':
+ for filename in sys.argv[1:]:
+ process_file(filename)
+
+
+
+
+
action='store', dest='show_string_dump', metavar='<number|name>',
help='Dump the contents of section <number|name> as strings')
optparser.add_option('--debug-dump',
- action='store', dest='debug_dump_what', metavar='<section>',
- help='Display the contents of DWARF debug sections')
+ action='store', dest='debug_dump_what', metavar='<what>',
+ help=(
+ 'Display the contents of DWARF debug sections. <what> can ' +
+ 'one of {info,decodedline,frames,frames-interp}'))
options, args = optparser.parse_args()