documentation fixes + new examples
authorEli Bendersky <eliben@gmail.com>
Thu, 22 Dec 2011 13:22:00 +0000 (15:22 +0200)
committerEli Bendersky <eliben@gmail.com>
Thu, 22 Dec 2011 13:22:00 +0000 (15:22 +0200)
elftools/elf/relocation.py
examples/dwarf_die_tree.py [new file with mode: 0644]
examples/elf_low_high_api.py [new file with mode: 0644]
examples/elf_relocations.py [new file with mode: 0644]
examples/elfclass_address_size.py
examples/examine_dwarf_info.py [new file with mode: 0644]
examples/sample_exe64.elf [new file with mode: 0644]
scripts/readelf.py

index cc9003229e3cfd8869b0893ffa3356e69f6341c1..acb2da2d2536003150bac474dd190de87e238e8a 100644 (file)
@@ -44,6 +44,8 @@ class Relocation(object):
 
 
 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
diff --git a/examples/dwarf_die_tree.py b/examples/dwarf_die_tree.py
new file mode 100644 (file)
index 0000000..5633d59
--- /dev/null
@@ -0,0 +1,73 @@
+#-------------------------------------------------------------------------------
+# 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)
+
+
+
+
+
+
diff --git a/examples/elf_low_high_api.py b/examples/elf_low_high_api.py
new file mode 100644 (file)
index 0000000..43f9880
--- /dev/null
@@ -0,0 +1,74 @@
+#-------------------------------------------------------------------------------
+# 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)
+
+
diff --git a/examples/elf_relocations.py b/examples/elf_relocations.py
new file mode 100644 (file)
index 0000000..a09f014
--- /dev/null
@@ -0,0 +1,46 @@
+#-------------------------------------------------------------------------------
+# 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)
+
+
+
index e1314960faee9dc5a3bb173138bd33ffbbd41f04..21c839cea80467650d231a4f2bff2a0e991a8f9d 100644 (file)
@@ -7,6 +7,7 @@
 # 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
 
@@ -14,13 +15,17 @@ 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:]:
diff --git a/examples/examine_dwarf_info.py b/examples/examine_dwarf_info.py
new file mode 100644 (file)
index 0000000..ba712dd
--- /dev/null
@@ -0,0 +1,57 @@
+#-------------------------------------------------------------------------------
+# 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)
+
+
+
+
+
diff --git a/examples/sample_exe64.elf b/examples/sample_exe64.elf
new file mode 100644 (file)
index 0000000..ccfa6ae
Binary files /dev/null and b/examples/sample_exe64.elf differ
index 051a21a71dc16aca2c6e9b4d3ce03fa5ab3f204a..c133d5324ddc7e324e14b17c68acf9f9ab945c8c 100755 (executable)
@@ -756,8 +756,10 @@ def main(stream=None):
             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()