abbrev table almost functioning
authoreliben <devnull@localhost>
Tue, 20 Sep 2011 13:03:59 +0000 (16:03 +0300)
committereliben <devnull@localhost>
Tue, 20 Sep 2011 13:03:59 +0000 (16:03 +0300)
elftools/dwarf/abbrevtable.py
elftools/dwarf/compileunit.py
elftools/dwarf/dwarfinfo.py
elftools/dwarf/structs.py
z.py

index 63485bd0454246e5ac5988c518d405e6fc08ab53..14f88f59814b946e623a97d6d9aa28beb463650c 100644 (file)
@@ -6,11 +6,69 @@
 # Eli Bendersky (eliben@gmail.com)
 # This code is in the public domain
 #-------------------------------------------------------------------------------
+from ..common.utils import struct_parse, dwarf_assert
 
 
 class AbbrevTable(object):
-    def __init__(self, structs, stream):
+    """ Represents a DWARF abbreviation table.
+    """
+    def __init__(self, structs, stream, offset):
+        """ Create new abbreviation table. Parses the actual table from the
+            stream and stores it internally.
+        
+            structs:
+                A DWARFStructs instance for parsing the data
+            
+            stream, offset:
+                The stream and offset into the stream where this abbreviation
+                table lives.
+                Note that this is the absolute offset into the stream, not 
+                relative to the debug_abbrev section.
+        """
         self.structs = structs
         self.stream = stream
+        self.offset = offset
+        
+        self._abbrev_map = self._parse_abbrev_table()
+
+    def get_abbrev(self, code):
+        """ Get the AbbrevDecl for a given code. Raise KeyError if no
+            declaration for this code exists.
+        """
+        return AbbrevDecl(code, self._abbrev_map[code])
+
+    def _parse_abbrev_table(self):
+        """ Parse the abbrev table from the stream
+        """
+        map = {}
+        self.stream.seek(self.offset)
+        while True:
+            decl_code = struct_parse(
+                struct=self.structs.Dwarf_uleb128(''),
+                stream=self.stream)
+            if decl_code == 0:
+                break
+            declaration = struct_parse(
+                struct=self.structs.Dwarf_abbrev_declaration,
+                stream=self.stream)
+            map[decl_code] = declaration
+        return map
+
+
+class AbbrevDecl(object):
+    """ Wraps a parsed abbreviation declaration, exposing its fields with 
+        dict-like access, and adding some convenience methods.
+    """
+    def __init__(self, code, decl):
+        self.code = code
+        self.decl = decl
+    
+    def has_children(self):
+        return self['children_flag'] == 'DW_CHILDREN_yes'
+    
+    def __getitem__(self, entry):
+        return self.decl[entry]
+
+
 
 
index 6eb5afa18826d87417058cd6d8a3f17cdb095387..92198e44d6848b827a0bbb0ff58dc3dc57740f47 100644 (file)
@@ -9,13 +9,13 @@
 
 
 class CompileUnit(object):
-    def __init__(self, dwarfinfo, header, structs):
-        """ dwarfinfo:
-                The DWARFInfo context object which created this one
-            
-            header:
+    def __init__(self, header, dwarfinfo, structs):
+        """ header:
                 CU header for this compile unit
             
+            dwarfinfo:
+                The DWARFInfo context object which created this one
+                        
             structs:
                 A DWARFStructs instance suitable for this compile unit
         """
index f49458fa8b7bff6061a7dab6ada4607c56a525ee..6e96f14fb3518a584e07c2c6a0edca2d282fe0e0 100644 (file)
@@ -71,15 +71,14 @@ class DWARFInfo(object):
             AbbrevTable objects are cached internally (two calls for the same
             offset will return the same object).
         """
-        section_boundary = self.debug_abbrev_loc.offset + self.debug_abbrev_loc.size
         dwarf_assert(
-            self.debug_abbrev_loc.offset <= offset < section_boundary,
+            offset < self.debug_abbrev_loc.size,
             "Offset '0x%x' to abbrev table out of section bounds" % offset)
         if offset not in self._abbrevtable_cache:
             self._abbrevtable_cache[offset] = AbbrevTable(
                 structs=self.structs,
-                stream=self.stream)
-        
+                stream=self.stream,
+                offset=offset + self.debug_abbrev_loc.offset)
         return self._abbrevtable_cache[offset]
     
     def _parse_CUs(self):
@@ -110,7 +109,10 @@ class DWARFInfo(object):
             dwarf_assert(
                 self._is_supported_version(cu_header['version']),
                 "Expected supported DWARF version. Got '%s'" % cu_header['version'])
-            CUlist.append(CompileUnit(cu_header, cu_structs, None))
+            CUlist.append(CompileUnit(
+                header=cu_header,
+                dwarfinfo=self,
+                structs=cu_structs))
             # Compute the offset of the next CU in the section. The unit_length
             # field of the CU header contains its size not including the length
             # field itself.
index ab272693fbca5063d9d355b6cb0c866558992dce..e77f98e3b7d7e3e8a2e3864f623f61fc6bd31815 100644 (file)
@@ -10,7 +10,7 @@
 from ..construct import (
     UBInt8, UBInt16, UBInt32, UBInt64,
     ULInt8, ULInt16, ULInt32, ULInt64,
-    Adapter, Struct, ConstructError, If, RepeatUntil, Field, Rename,
+    Adapter, Struct, ConstructError, If, RepeatUntil, Field, Rename, Enum,
     )
 
 from .enums import *
@@ -39,9 +39,9 @@ class DWARFStructs(object):
             Dwarf_CU_header:
                 Compilation unit header
         
-            Dwarf_abbrev_entry:
-                Abbreviation table entry - doesn't include the initial code,
-                only the contents.
+            Dwarf_abbrev_declaration:
+                Abbreviation table declaration - doesn't include the initial
+                code, only the contents.
         
         See also the documentation of public methods.
     """
@@ -73,7 +73,7 @@ class DWARFStructs(object):
         self._create_initial_length()
         self._create_leb128()
         self._create_cu_header()
-        self._create_abbrev_entry()
+        self._create_abbrev_declaration()
 
     def _create_initial_length(self):
         def _InitialLength(name):
@@ -100,14 +100,16 @@ class DWARFStructs(object):
             self.Dwarf_offset('debug_abbrev_offset'),
             self.Dwarf_uint8('address_size'))
     
-    def _create_abbrev_entry(self):
-        self.Dwarf_abbrev_entry = Struct('Dwarf_abbrev_entry',
-            self.Dwarf_uleb128('tag'),                  # ZZZ: wrap in enums
-            self.Dwarf_uint8('children_flag'),
-            RepeatUntil(lambda obj, ctx: obj.name == obj.form == 0,
+    def _create_abbrev_declaration(self):
+        self.Dwarf_abbrev_declaration = Struct('Dwarf_abbrev_entry',
+            Enum(self.Dwarf_uleb128('tag'), **ENUM_DW_TAG),
+            Enum(self.Dwarf_uint8('children_flag'), **ENUM_DW_CHILDREN),
+            RepeatUntil(
+                lambda obj, ctx: 
+                    obj.name == 'DW_AT_null' and obj.form == 'DW_FORM_null',
                 Struct('spec',
-                    self.Dwarf_uleb128('name'),
-                    self.Dwarf_uleb128('form'))))
+                    Enum(self.Dwarf_uleb128('name'), **ENUM_DW_AT),
+                    Enum(self.Dwarf_uleb128('form'), **ENUM_DW_FORM))))
 
 
 class _InitialLengthAdapter(Adapter):
diff --git a/z.py b/z.py
index b16ef690e7232b9723a2a95fc88515b5b2bc1eec..648145895b2dc5db21f6275a8d4769290e658a70 100644 (file)
--- a/z.py
+++ b/z.py
@@ -2,7 +2,7 @@
 # please ignore it!
 #
 
-import sys
+import sys, pprint
 from elftools.elf.structs import ELFStructs
 from elftools.elf.elffile import ELFFile
 from elftools.elf.sections import *
@@ -20,9 +20,20 @@ print '===> %s sections!' % efile.num_sections()
 print efile.has_dwarf_info()
 
 dwarfinfo = efile.get_dwarf_info()
-print dwarfinfo
-for cu in dwarfinfo._CU:
-    print cu, cu.header
+
+#~ print dwarfinfo.structs.Dwarf_abbrev_entry.parse('\x13\x01\x01\x03\x50\x04\x00\x00')
+
+print id(dwarfinfo.get_abbrev_table(0))
+print id(dwarfinfo.get_abbrev_table(0))
+pprint.pprint(dwarfinfo.get_abbrev_table(0)._abbrev_map)
+
+print dwarfinfo.get_abbrev_table(0).get_abbrev(1).decl
+print dwarfinfo.get_abbrev_table(0).get_abbrev(1).has_children()
+
+#~ for cu in dwarfinfo._CU:
+    #~ print cu, cu.header
+
+
 
 
 #~ print efile.get_section_by_name('.debug_info').name