Update version to 0.25 to prepare for release
[pyelftools.git] / elftools / dwarf / die.py
old mode 100644 (file)
new mode 100755 (executable)
index 91c0d0b..184ff8c
@@ -6,11 +6,13 @@
 # Eli Bendersky (eliben@gmail.com)
 # This code is in the public domain
 #-------------------------------------------------------------------------------
-from collections import namedtuple
+from collections import namedtuple, OrderedDict
 import os
 
-from ..common.py3compat import OrderedDict, bytes2str, iteritems
+from ..common.exceptions import DWARFError
+from ..common.py3compat import bytes2str, iteritems
 from ..common.utils import struct_parse, preserve_stream_pos
+from .enums import DW_FORM_raw2name
 
 
 # AttributeValue - describes an attribute value in the DIE:
@@ -141,7 +143,7 @@ class DIE(object):
     #------ PRIVATE ------#
 
     def __repr__(self):
-        s = 'DIE %s, size=%s, has_chidren=%s\n' % (
+        s = 'DIE %s, size=%s, has_children=%s\n' % (
             self.tag, self.size, self.has_children)
         for attrname, attrval in iteritems(self.attributes):
             s += '    |%-18s:  %s\n' % (attrname, attrval)
@@ -160,7 +162,6 @@ class DIE(object):
         # obtain the abbrev declaration for this DIE.
         # Note: here and elsewhere, preserve_stream_pos is used on operations
         # that manipulate the stream by reading data from it.
-        #
         self.abbrev_code = struct_parse(
             structs.Dwarf_uleb128(''), self.stream, self.offset)
 
@@ -177,7 +178,6 @@ class DIE(object):
 
         # Guided by the attributes listed in the abbreviation declaration, parse
         # values from the stream.
-        #
         for name, form in abbrev_decl.iter_attr_specs():
             attr_offset = self.stream.tell()
             raw_value = struct_parse(structs.Dwarf_dw_form[form], self.stream)
@@ -190,6 +190,19 @@ class DIE(object):
                 raw_value=raw_value,
                 offset=attr_offset)
 
+        # Count and then consume any null termination bytes to avoid wrong die
+        # size calculation.
+        num_zero_terminators = 0
+        with preserve_stream_pos(self.stream):
+            while True:
+                if self.stream.read(1) == 0:
+                    num_zero_terminators += 1
+                else:
+                    break
+        if num_zero_terminators > 0:
+            # There was at least one zero termination -> consume all of them.
+            self.stream.read(num_zero_terminators)
+
         self.size = self.stream.tell() - self.offset
 
     def _translate_attr_value(self, form, raw_value):
@@ -202,9 +215,15 @@ class DIE(object):
         elif form == 'DW_FORM_flag':
             value = not raw_value == 0
         elif form == 'DW_FORM_indirect':
-            form = raw_value
+            try:
+                form = DW_FORM_raw2name[raw_value]
+            except KeyError as err:
+                raise DWARFError(
+                        'Found DW_FORM_indirect with unknown raw_value=' +
+                        str(raw_value))
+
             raw_value = struct_parse(
-                structs.Dwarf_dw_form[form], self.stream)
+                self.cu.structs.Dwarf_dw_form[form], self.stream)
             # Let's hope this doesn't get too deep :-)
             return self._translate_attr_value(form, raw_value)
         else: