changeset 124:8e42b2816893

Fixing compute_size() and sizeof() for DEX types. - Prevent compute_size() and sizeof() of depend_* to include size of depend-on.
author Thinker K.F. Li <thinker@codemud.net>
date Sun, 07 Aug 2011 22:07:08 +0800
parents 78357afb4a9d
children b9688a3badaa
files paraspace/dex_deptracker.py paraspace/dexfile.py paraspace/tests/dex_deptracker_test.py paraspace/tests/dexfile_test.py
diffstat 4 files changed, 243 insertions(+), 57 deletions(-) [+]
line wrap: on
line diff
--- a/paraspace/dex_deptracker.py	Sat Aug 06 19:09:15 2011 +0800
+++ b/paraspace/dex_deptracker.py	Sun Aug 07 22:07:08 2011 +0800
@@ -298,12 +298,19 @@
     return all_dep_decls
 
 
+## Mark where we need offset information for link dependencies.
+#
 class _marker(dexfile.null_relocatable):
     back_type = None
 
     def set_marker(self, obj, off):
         raise NotImplementedError, \
             'The marker does not implement set_marker()'
+
+    ## \brief Prepare data_offset for linking.
+    def link_prepare(self, obj, name_path, parents, markers_info):
+        raise NotImplementedError, \
+            '_marker should be used to instantiate an instance directly'
     pass
 
 class _uid_marker(_marker):
@@ -730,6 +737,7 @@
             depon2 = _rel_offset_marker.find_depon(dep[2], parents)
             offset = depon2.data_offset + obj
             depon1 = markers_info[dep[1]][offset]
+            dep_type._depon2_log[depon1] = depon2
 
             name = name_path.split('.')[-1]
             _dex_tree_set_child(imm_parent, name, depon1)
@@ -785,7 +793,7 @@
 # \param all_dep_decls is a dictionary returned by prepare_dep_decls().
 #
 def update_offset(dexroot, all_dep_decls):
-    from dexfile import man_off
+    from paraspace.dexfile import man_off
 
     depon_dep_map = _build_depon_dep_map(all_dep_decls)
     dex_type_names = _all_dex_type_to_names()
@@ -835,12 +843,11 @@
             continue
 
         if not isinstance(obj, dexfile.relocatable):
-            #if isinstance(obj_clazz, dexfile.auto_align):
-            #    obj = obj_clazz.recompute_align(moff())
-            #    print '%s %x %d' % (name_path, moff(), obj)
-            #    name = name_path.split('.')[-1]
-            #    _dex_tree_set_child(parent, name, obj)
-            #    pass
+            if isinstance(obj_clazz, dexfile.auto_align):
+                obj = obj_clazz.recompute_align(moff())
+                name = name_path.split('.')[-1]
+                _dex_tree_set_child(parent, name, obj)
+                pass
             moff(obj_clazz.sizeof(obj))
             continue
         
--- a/paraspace/dexfile.py	Sat Aug 06 19:09:15 2011 +0800
+++ b/paraspace/dexfile.py	Sun Aug 07 22:07:08 2011 +0800
@@ -109,8 +109,8 @@
 
 def _compute_sz(o, _type):
     if hasattr(o, 'compute_size'):
-        o.compute_size()
-        return o.data_size
+        _type.compute_size(o)
+        pass
     return _type.sizeof(o)
 
 
@@ -190,6 +190,10 @@
     def parse(parent, data, off):
         v = _to_uint(data[off:off + 4])
         return v
+
+    @staticmethod
+    def compute_size(v):
+        pass
     
     @staticmethod
     def sizeof(v):
@@ -209,6 +213,10 @@
         return v
     
     @staticmethod
+    def compute_size(v):
+        pass
+    
+    @staticmethod
     def sizeof(v):
         return 2
 
@@ -225,6 +233,10 @@
         return v
     
     @staticmethod
+    def compute_size(v):
+        pass
+    
+    @staticmethod
     def sizeof(v):
         return 1
 
@@ -241,6 +253,10 @@
         return v
     
     @staticmethod
+    def compute_size(v):
+        pass
+    
+    @staticmethod
     def sizeof(v):
         return 4
 
@@ -258,6 +274,10 @@
         return v
 
     @staticmethod
+    def compute_size(v):
+        pass
+    
+    @staticmethod
     def sizeof(v):
         return 2
 
@@ -274,6 +294,10 @@
         return v
 
     @staticmethod
+    def compute_size(v):
+        pass
+    
+    @staticmethod
     def sizeof(v):
         return _uleb128_sz(v)
 
@@ -290,6 +314,10 @@
         return v
 
     @staticmethod
+    def compute_size(v):
+        pass
+    
+    @staticmethod
     def sizeof(v):
         return _leb128_sz(v)
 
@@ -315,6 +343,10 @@
         return self.recompute_align(off)
 
     @staticmethod
+    def compute_size(v):
+        pass
+    
+    @staticmethod
     def sizeof(v):
         return v
 
@@ -377,6 +409,7 @@
     def to_str(self):
         return ''
 
+    @staticmethod
     def compute_size(self):
         pass
 
@@ -457,7 +490,7 @@
         return 0
 
     @staticmethod
-    def compute_size():
+    def compute_size(self):
         pass
 
     @staticmethod
@@ -535,6 +568,7 @@
         obj.data_size = moff() - off
         return obj
 
+    @staticmethod
     def compute_size(self):
         sizes = [_compute_sz(item, self.child_type)
                  for item in self.items]
@@ -640,6 +674,7 @@
             return 0
         return self.child_type.sizeof(v.value)
 
+    @staticmethod
     def compute_size(self):
         if self.is_true:
             self.data_size = _compute_sz(self.value, self.child_type)
@@ -705,6 +740,7 @@
     def sizeof(v):
         return v.child_type.sizeof(v.value)
 
+    @staticmethod
     def compute_size(self):
         self.data_size = _compute_sz(self.value, self.child_type)
         pass
@@ -742,6 +778,12 @@
     pass
 
 
+## \brief Make a dependency to a depend-on for back type.
+#
+# Depend-on is the object that the back type is supposed to point to.
+# Back type of a depend must be not a composite type while depend-on
+# must be.
+#
 class depend(null_relocatable):
     depend_on = None
     
@@ -750,6 +792,7 @@
         pass
 
     def __call__(self, back_type):
+        assert type(back_type) != type or not issubclass(back_type, composite)
         self.back_type = back_type
         return self
 
@@ -792,16 +835,38 @@
 
 
 class depend_off(depend):
+    def compute_size(self, child):
+        pass
+
+    def sizeof(self, child):
+        if isinstance(child, composite):
+            return self.back_type.sizeof(child.data_offset)
+        return self.back_type.sizeof(child)
     pass
 
 
 class depend_off_rel(depend):
     relative_to = None
+    _depon2_log = {}
 
     def __init__(self, relative_to, depend_on):
         super(depend_off_rel, self).__init__(depend_on)
         self.relative_to = relative_to
         pass
+
+    def parse(self, parent, data, off):
+        v = super(depend_off_rel, self).parse(parent, data, off)
+        return v
+
+    def compute_size(self, child):
+        pass
+
+    def sizeof(self, child):
+        if isinstance(child, composite):
+            pivot = self._depon2_log[child] # depon2
+            off_diff = child.data_offset - pivot.data_offset
+            return self.back_type.sizeof(off_diff)
+        return self.back_type.sizeof(child)
     pass
 
 
@@ -823,7 +888,14 @@
             pass
         v = self.back_type.sizeof(v)
         return v
+
+    def compute_size(self, child):
         pass
+
+    def sizeof(self, child):
+        if isinstance(child, composite):
+            return self.back_type.sizeof(child.data_idx)
+        return self.back_type.sizeof(child)
     pass
 
 
@@ -1309,7 +1381,7 @@
     pass
 
 
-class _DEX_DebugCodeBlock(relocatable):
+class _DEX_DebugCodeBlock(_dex_type):
     DBG_END_SEQUENCE = 0x00
     DBG_ADVANCE_PC = 0x01
     DBG_ADVANCE_LINE = 0x02
@@ -1434,6 +1506,10 @@
         
         self.data_size = opcodes_size
         pass
+
+    @staticmethod
+    def sizeof(obj):
+        return obj.data_size
     
     @staticmethod
     def to_str(self):
--- a/paraspace/tests/dex_deptracker_test.py	Sat Aug 06 19:09:15 2011 +0800
+++ b/paraspace/tests/dex_deptracker_test.py	Sun Aug 07 22:07:08 2011 +0800
@@ -1,10 +1,65 @@
-from paraspace.dexfile import DEXFile, DEXFile_linked
+from paraspace import dexfile
 from paraspace.dex_deptracker import prepare_dep_decls
 from paraspace.dex_deptracker import restore_dependencies
 import os
 
+
+def _install_dexfile_4_deptracker():
+    global dexfile
+    import imp, sys
+    from paraspace import dex_deptracker
+    from paraspace import injection
+    
+    try:
+        new_dexfile = imp.load_compiled('paraspace.dexfile', dexfile.__file__)
+    except ImportError:
+        new_dexfile = imp.load_source('paraspace.dexfile', dexfile.__file__)
+        pass
+    dex_deptracker.dexfile = new_dexfile
+    dexfile = new_dexfile
+    dex_deptracker._nest_types = (dexfile.array, dexfile.cond, dexfile.switch)
+
+    injection.dex_type_2_array_attr_map = \
+        injection._saved_dex_type_2_array_attr_map
+    
+    sys.modules['paraspace.dexfile'] = new_dexfile
+    pass
+
+
+def update_offset_test():
+    from paraspace.dex_deptracker import collect_all_dep_decls
+    from paraspace.dex_deptracker import build_dependencies
+    from paraspace.dex_deptracker import _install_markers
+    from paraspace.dex_deptracker import _patch_dex_type_markers
+    from paraspace.dex_deptracker import update_offset
+
+    _install_dexfile_4_deptracker()
+
+    all_dep_decls = collect_all_dep_decls()
+    _install_markers(all_dep_decls)
+    _patch_dex_type_markers(all_dep_decls)
+
+    srcdir = os.path.dirname(__file__)
+    srcroot = os.path.join(srcdir, '..', '..')
+    testdatapath = os.path.join(srcroot, 'data', 'testdata1.dex')
+    dex = dexfile.DEXFile.open(testdatapath)
+
+    build_dependencies(dex, all_dep_decls)
+
+    offset0 = dex.typeLists.items[0].value.data_offset
+    dex.typeLists.items[0].value.data_offset = 0
+    offset1 = dex.typeLists.items[1].value.data_offset
+    dex.typeLists.items[1].value.data_offset = 0
+    
+    update_offset(dex, all_dep_decls)
+
+    assert dex.typeLists.items[0].value.data_offset == offset0
+    assert dex.typeLists.items[1].value.data_offset == offset1
+    pass
+
+
 def restore_dependencies_test():
-    from paraspace.dexfile import _DEX_StringId
+    _install_dexfile_4_deptracker()
     
     srcdir = os.path.dirname(__file__)
     srcroot = os.path.join(srcdir, '..', '..')
@@ -13,34 +68,114 @@
     
     decls = prepare_dep_decls()
     
-    hello_dex = DEXFile.open(helloworld_path)
+    hello_dex = dexfile.DEXFile.open(helloworld_path)
     strids_size_saved = hello_dex.header.stringIdsSize
     typeids_off_saved = hello_dex.header.typeIdsOff
     data_off_saved = hello_dex.header.dataOff
     map_off_saved = hello_dex.header.mapOff
     file_sz_saved = hello_dex.header.fileSize
-    for map_item in hello_dex.maps.items.items:
-        print '%d %x' % (map_item.type, map_item.offset)
-        pass
 
-    hello_linked = DEXFile_linked.build_dependencies(hello_dex, decls)
+    hello_linked = dexfile.DEXFile_linked.build_dependencies(hello_dex, decls)
     
     first_strid = hello_linked.stringIds.items[0]
-    strid = _DEX_StringId()
+    strid = dexfile._DEX_StringId()
     strid.stringDataOff = first_strid.stringDataOff
     hello_linked.stringIds.items.append(strid)
 
     restore_dependencies(hello_linked, decls)
 
-    print file_sz_saved, hello_linked.header.fileSize
-    print map_off_saved, hello_linked.header.mapOff
-    for map_item in hello_linked.maps.items.items:
-        print '%d %x' % (map_item.type, map_item.offset)
-        pass
-
     assert hello_linked.header.fileSize == (file_sz_saved + 4)
     assert hello_linked.header.stringIdsSize == (strids_size_saved + 1)
     assert hello_linked.header.typeIdsOff == (typeids_off_saved + 4)
     assert hello_linked.header.dataOff == (data_off_saved + 4)
     assert hello_linked.header.mapOff == (map_off_saved + 4)
     pass
+
+
+def sizoef_after_build_dep_test():
+    from paraspace.dex_deptracker import update_offset
+    
+    _install_dexfile_4_deptracker()
+
+    srcdir = os.path.dirname(__file__)
+    srcroot = os.path.join(srcdir, '..', '..')
+    datadir = os.path.join(srcroot, 'data')
+    helloworld_path = os.path.join(datadir, 'helloworld.dex')
+    
+    decls = prepare_dep_decls()
+    
+    hello_dex = dexfile.DEXFile.open(helloworld_path)
+    update_offset(hello_dex, decls)
+    
+    get_sz = lambda x: x.sizeof(x)
+    assert get_sz(hello_dex.header) == 112
+    assert get_sz(hello_dex.stringIds) == 0x168
+    assert get_sz(hello_dex.typeIds) == (0x250-0x1d8)
+    assert get_sz(hello_dex.protoIds) == (0x31c-0x250)
+    assert get_sz(hello_dex.fieldIds) == (0x354-0x31c)
+    assert get_sz(hello_dex.methodIds) == (0x46c-0x354)
+    assert get_sz(hello_dex.classDefs) == (0x58c-0x46c)
+    assert get_sz(hello_dex.annotationSetItems) == (0x5dc-0x58c)
+    assert get_sz(hello_dex.codeItems) == (0x8b8-0x5dc)
+    assert get_sz(hello_dex.annotationsDirectoryItems) == (0x928-0x8b8)
+    assert get_sz(hello_dex.typeLists) == (0x98a-0x928)
+    assert get_sz(hello_dex.stringDataItems) == (0xe7d-0x98a)
+    assert get_sz(hello_dex.debugInfoItems) == (0xf31-0xe7d)
+    assert get_sz(hello_dex.annotationItems) == (0xf82-0xf31)
+    assert get_sz(hello_dex.encodedArrayItems) == (0xf9d-0xf82)
+    assert get_sz(hello_dex.classDatas) == (0x1024-0xf9d-1)
+    assert hello_dex.maps.sizeof(hello_dex.maps) == 0xd0
+
+    hello_dex.compute_size()
+    unlinked_sz = hello_dex.sizeof(hello_dex)
+    assert unlinked_sz == hello_dex.header.fileSize
+
+    hello_linked = dexfile.DEXFile_linked.build_dependencies(hello_dex, decls)
+
+    hello_linked.compute_size()
+    linked_sz = hello_linked.sizeof(hello_linked)
+    
+    assert get_sz(hello_linked.header) == 112
+    assert get_sz(hello_linked.stringIds) == 0x168
+    assert get_sz(hello_linked.typeIds) == (0x250-0x1d8)
+    assert get_sz(hello_linked.protoIds) == (0x31c-0x250)
+    assert get_sz(hello_linked.fieldIds) == (0x354-0x31c)
+    assert get_sz(hello_linked.methodIds) == (0x46c-0x354)
+    assert get_sz(hello_linked.classDefs) == (0x58c-0x46c)
+    assert get_sz(hello_linked.annotationSetItems) == (0x5dc-0x58c)
+    assert get_sz(hello_linked.codeItems) == (0x8b8-0x5dc)
+    assert get_sz(hello_linked.annotationsDirectoryItems) == (0x928-0x8b8)
+    assert get_sz(hello_linked.typeLists) == (0x98a-0x928)
+    assert get_sz(hello_linked.stringDataItems) == (0xe7d-0x98a)
+    assert get_sz(hello_linked.debugInfoItems) == (0xf31-0xe7d)
+    assert get_sz(hello_linked.annotationItems) == (0xf82-0xf31)
+    assert get_sz(hello_linked.encodedArrayItems) == (0xf9d-0xf82)
+
+    assert linked_sz == unlinked_sz
+    
+    first_strid = hello_linked.stringIds.items[0]
+    strid = dexfile._DEX_StringId()
+    strid.stringDataOff = first_strid.stringDataOff
+    hello_linked.stringIds.items.append(strid)
+    
+    hello_linked.compute_size()
+    linked_sz = hello_linked.sizeof(hello_linked)
+    
+    assert get_sz(hello_linked.header) == 112
+    assert get_sz(hello_linked.stringIds) == 0x16c
+    assert get_sz(hello_linked.typeIds) == (0x250-0x1d8)
+    assert get_sz(hello_linked.protoIds) == (0x31c-0x250)
+    assert get_sz(hello_linked.fieldIds) == (0x354-0x31c)
+    assert get_sz(hello_linked.methodIds) == (0x46c-0x354)
+    assert get_sz(hello_linked.classDefs) == (0x58c-0x46c)
+    assert get_sz(hello_linked.annotationSetItems) == (0x5dc-0x58c)
+    assert get_sz(hello_linked.codeItems) == (0x8b8-0x5dc)
+    assert get_sz(hello_linked.annotationsDirectoryItems) == (0x928-0x8b8)
+    assert get_sz(hello_linked.typeLists) == (0x98a-0x928)
+    assert get_sz(hello_linked.stringDataItems) == (0xe7d-0x98a)
+    assert get_sz(hello_linked.debugInfoItems) == (0xf31-0xe7d)
+    assert get_sz(hello_linked.annotationItems) == (0xf82-0xf31)
+    assert get_sz(hello_linked.encodedArrayItems) == (0xf9d-0xf82)
+
+    assert linked_sz == (unlinked_sz + 4)
+    pass
--- a/paraspace/tests/dexfile_test.py	Sat Aug 06 19:09:15 2011 +0800
+++ b/paraspace/tests/dexfile_test.py	Sun Aug 07 22:07:08 2011 +0800
@@ -279,38 +279,6 @@
     pass
 
 
-def update_offset_test():
-    from paraspace.dex_deptracker import collect_all_dep_decls
-    from paraspace.dex_deptracker import build_dependencies
-    from paraspace.dex_deptracker import _install_markers
-    from paraspace.dex_deptracker import _patch_dex_type_markers
-    from paraspace.dex_deptracker import update_offset
-
-    _install_dexfile_4_deptracker()
-
-    all_dep_decls = collect_all_dep_decls()
-    _install_markers(all_dep_decls)
-    _patch_dex_type_markers(all_dep_decls)
-
-    srcdir = os.path.dirname(__file__)
-    srcroot = os.path.join(srcdir, '..', '..')
-    testdatapath = os.path.join(srcroot, 'data', 'testdata1.dex')
-    dex = dexfile.DEXFile.open(testdatapath)
-
-    build_dependencies(dex, all_dep_decls)
-
-    offset0 = dex.typeLists.items[0].value.data_offset
-    dex.typeLists.items[0].value.data_offset = 0
-    offset1 = dex.typeLists.items[1].value.data_offset
-    dex.typeLists.items[1].value.data_offset = 0
-    
-    update_offset(dex, all_dep_decls)
-
-    assert dex.typeLists.items[0].value.data_offset == offset0
-    assert dex.typeLists.items[1].value.data_offset == offset1
-    pass
-
-
 def restore_dependencies_test():
     from paraspace.dex_deptracker import collect_all_dep_decls
     from paraspace.dex_deptracker import build_dependencies