changeset 53:705356005362

Fix bug of install marker through ref
author Thinker K.F. Li <thinker@codemud.net>
date Wed, 22 Jun 2011 20:22:03 +0800
parents 67aa8ca8fff3
children 870312703ba1
files paraspace/dex_deptracker.py paraspace/dexfile.py paraspace/tests/dexfile_test.py
diffstat 3 files changed, 136 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/paraspace/dex_deptracker.py	Tue Jun 21 18:36:45 2011 +0800
+++ b/paraspace/dex_deptracker.py	Wed Jun 22 20:22:03 2011 +0800
@@ -10,6 +10,10 @@
     obj = dexfile
     parent = None
     for name in name_path.split('.'):
+        while isinstance(obj, _marker):
+            obj = obj.back_type
+            pass
+        
         if isinstance(parent, dexfile.array) and obj == list:
             # array.items.<num>
             obj = parent.child_type
@@ -253,6 +257,20 @@
     return dex_types
 
 
+def _all_dex_type_to_names():
+    def check_marker(value, name):
+        while isinstance(value, _marker):
+            value = value.back_type
+            pass
+        return value, name
+    
+    dex_types = dict([check_marker(value, name)
+                      for name, value in dexfile.__dict__.items()
+                      if name.startswith('_DEX_')])
+    dex_types[dexfile.DEXFile] = 'DEXFile'
+    return dex_types
+
+
 def collect_all_dep_decls():
     dex_types = _all_dex_types()
 
@@ -267,6 +285,10 @@
 
 class _marker(dexfile.null_relocatable):
     back_type = None
+
+    def set_marker(self, obj, off):
+        raise NotImplementedError, \
+            'The marker does not implement set_marker()'
     pass
 
 class _uid_marker(_marker):
@@ -283,7 +305,8 @@
             value.data_uid = _uid_marker.uid_seq
         except AttributeError:
             raise AttributeError, \
-                'can not depend on non-instance (%s)' % (self.name_path)
+                'can not depend on non-instance (%s/%s)' % \
+                (self.name_path, repr(value))
         _uid_marker.uid_seq = _uid_marker.uid_seq + 1
         
         return value
@@ -315,6 +338,9 @@
 
     def __call__(self, *args, **kws):
         return self.back_type(*args, **kws)
+
+    def set_marker(self, obj, off):
+        pass
     pass
 
 
@@ -336,6 +362,10 @@
         assert obj.data_offset not in id_item_map
         id_item_map[obj.data_offset] = obj
         pass
+
+    def set_marker(self, obj, off):
+        obj.data_offset = off
+        pass
     pass
 
 
@@ -387,6 +417,10 @@
             pass
         
         raise RuntimeError, 'can not find relative offset depend'
+
+    def set_marker(self, obj, off):
+        obj.data_offset = off
+        pass
     pass
 
 
@@ -411,13 +445,17 @@
             id_item_map[idx] = item
             pass
         pass
+
+    def set_marker(self, obj, off):
+        pass
     pass
 
 
 def _install_offset_marker(name_path):
     obj, parent = _resolve_name_path(name_path)
-    while isinstance(parent, dexfile.ref):
-        obj, parent = _resolve_name_path(parent.target_path)
+    while isinstance(obj, dexfile.ref):
+        name_path = obj.target_path
+        obj, parent = _resolve_name_path(name_path)
         pass
     marker = _offset_marker(obj, name_path)
     name = name_path.split('.')[-1]
@@ -427,8 +465,9 @@
 
 def _install_rel_offset_marker(name_path):
     obj, parent = _resolve_name_path(name_path)
-    while isinstance(parent, dexfile.ref):
-        obj, parent = _resolve_name_path(parent.target_path)
+    while isinstance(obj, dexfile.ref):
+        name_path = obj.target_path
+        obj, parent = _resolve_name_path(name_path)
         pass
     marker = _rel_offset_marker(obj, name_path)
     name = name_path.split('.')[-1]
@@ -438,8 +477,9 @@
 
 def _install_uid_marker(name_path):
     obj, parent = _resolve_name_path(name_path)
-    while isinstance(parent, dexfile.ref):
-        obj, parent = _resolve_name_path(parent.target_path)
+    while isinstance(obj, dexfile.ref):
+        name_path = obj.target_path
+        obj, parent = _resolve_name_path(name_path)
         pass
     marker = _uid_marker(obj, name_path)
     name = name_path.split('.')[-1]
@@ -449,8 +489,9 @@
 
 def _install_idx_marker(name_path):
     obj, parent = _resolve_name_path(name_path)
-    while isinstance(parent, dexfile.ref):
-        obj, parent = _resolve_name_path(parent.target_path)
+    while isinstance(obj, dexfile.ref):
+        name_path = obj.target_path
+        obj, parent = _resolve_name_path(name_path)
         pass
     marker = _idx_marker(obj, name_path)
     name = name_path.split('.')[-1]
@@ -630,6 +671,9 @@
             continue
         
         marker, dummy_parent = _resolve_name_path(name_path)
+        while isinstance(marker, dexfile.ref):
+            marker, dummy = _resolve_name_path(marker.target_path)
+            pass
         marker.link_prepare(obj, name_path, parents, markers_info)
         pass
 
@@ -677,6 +721,8 @@
 
 
 def _build_depon_dep_map(all_dep_decls):
+    from itertools import chain
+    
     def _build_sub_depon_dep(from_path, dep):
         depon1 = dep[1]
         sub = [(depon1, from_path)]
@@ -692,32 +738,55 @@
                       for from_path, dep in all_dep_decls.items()]
     depon_dep_lst = chain(*depon_dep_lsts)
     depon_dep_map = dict(depon_dep_lst)
-    pass
+    return depon_dep_map
 
 
 def update_offset(dexroot, all_dep_decls):
     from dexfile import man_off
+
+    depon_dep_map = _build_depon_dep_map(all_dep_decls)
+    dex_type_names = _all_dex_type_to_names()
+
+    def make_path(obj, path_parts, obj_name):
+        if isinstance(obj, dexfile.composite):
+            type_name = dex_type_names[obj.__class__]
+            return [type_name]
+        return path_parts + [obj_name]
     
     moff = man_off(0)
-    queue = [dexroot]
+    queue = [(dexroot, ['DEXFile'])]
     
     while queue:
-        obj = queue.pop()
-        if isinstance(obj, _marker):
-            obj.set_marker(moff())
+        obj, path_parts = queue.pop()
+        name_path = '.'.join(path_parts)
+        
+        if name_path in depon_dep_map:
+            marker, dummy = _resolve_name_path(name_path)
+            marker.set_marker(obj, moff())
             pass
-        if isinstance(obj, dexfile.relocatable):
-            moff(obj.sizeof())
-            pass
+
+        if isinstance(obj, (tuple, list)):
+            attrs = [(elt, path_parts + [str(idx)])
+                     for idx, elt in enumerate(obj)]
+            attrs.reverse()
+            queue = queue + attrs
+            continue
         
         if isinstance(obj, dexfile.ref):
             continue
+
         if not isinstance(obj, dexfile.relocatable):
+            clazz, parent = _resolve_name_path(name_path)
+            moff(clazz.sizeof(obj))
             continue
         
-        children = list(obj.children())
-        attrs = [_dex_tree_get_child(obj, child)
-                 for child in children]
+        moff(obj.sizeof(obj))
+        
+        children = obj.children()
+        attr_n_names = [(_dex_tree_get_child(obj, child_name), child_name)
+                      for child_name in children]
+        attrs = [(attr, make_path(attr, path_parts, attr_name))
+                 for attr, attr_name in attr_n_names]
         attrs.reverse()
         queue = queue + attrs
         pass
--- a/paraspace/dexfile.py	Tue Jun 21 18:36:45 2011 +0800
+++ b/paraspace/dexfile.py	Wed Jun 22 20:22:03 2011 +0800
@@ -427,7 +427,6 @@
 #
 class ref(_dex_type):
     target_path = None
-    target = None
 
     def __init__(self, target_path=None):
         self.target_path = target_path
@@ -638,7 +637,9 @@
         return data
 
     def children(self):
-        return ('value',)
+        if self.is_true:
+            return ('value',)
+        return ()
     pass
 
 
@@ -702,7 +703,7 @@
     pass
 
 
-class abs_value(relocatable):
+class abs_value(_dex_type):
     value = None
     
     def __init__(self, value):
@@ -710,9 +711,8 @@
         pass
 
     def parse(self, parse, data, off):
-        obj = abs_value(self.value)
-        return obj
-
+        return self.value
+    
     def sizeof(self, v):
         return 0
 
@@ -720,7 +720,7 @@
         return ''
 
     def children(self):
-        return ('value',)
+        return ()
     pass
 
 
@@ -992,10 +992,10 @@
     startAddr = uint32
     insnCount = uint16
     handlerOff = depend_off_rel('_DEX_Code.handlers_size',
-                                '_DEX_Try.catch_ref.target')(uint16)
+                                '_DEX_Try.catch_ref')(uint16)
     catch_ref = ref('_DEX_Catch')
 
-    child_names = 'startAddr insnCount handlerOff'.split()
+    child_names = 'startAddr insnCount handlerOff catch_ref'.split()
     pass
 
 
@@ -1021,7 +1021,7 @@
                            _DEX_CatchAllHandler)
     try_ref = ref('_DEX_Try')
 
-    child_names = 'size handlers catchAllHandler'.split()
+    child_names = 'size handlers catchAllHandler try_ref'.split()
 
     @property
     def catchesAll(self):
@@ -1431,7 +1431,7 @@
         return ''.join(opcodebins)
 
     def children(self):
-        return ('opcodes',)
+        return ()
     pass
 
 
@@ -1587,7 +1587,6 @@
         map_items = [self.block_defs[map_item.type]
                      for map_item in self.maps.items.items]
         children = map_items + ['maps']
-        print children
         return children
     pass
 
--- a/paraspace/tests/dexfile_test.py	Tue Jun 21 18:36:45 2011 +0800
+++ b/paraspace/tests/dexfile_test.py	Wed Jun 22 20:22:03 2011 +0800
@@ -37,7 +37,7 @@
     assert deps['_DEX_ClassDef.staticValuesOffRef.value'][1] == \
         '_DEX_EncodedArrayItem'
     assert deps['_DEX_Try.handlerOff'][0] == dexfile.depend_off_rel
-    assert deps['_DEX_Try.handlerOff'][1] == '_DEX_Try.catch_ref.target'
+    assert deps['_DEX_Try.handlerOff'][1] == '_DEX_Try.catch_ref'
     assert deps['_DEX_Try.handlerOff'][2] == '_DEX_Code.handlers_size'
     pass
 
@@ -179,6 +179,7 @@
 def install_markers_test():
     from paraspace.dex_deptracker import collect_all_dep_decls
     from paraspace.dex_deptracker import _install_markers, _idx_marker
+    from paraspace.dex_deptracker import _marker
     from paraspace.dex_deptracker import _offset_marker, _rel_offset_marker
     from paraspace.dex_deptracker import _patch_dex_type_markers
 
@@ -195,6 +196,7 @@
     assert isinstance(dexfile._DEX_TypeList, _offset_marker)
     assert isinstance(dexfile.DEXFile.typeLists.child_type.value,
                       _offset_marker)
+    assert isinstance(dexfile._DEX_Catch, _marker)
     pass
 
 
@@ -228,7 +230,6 @@
     from paraspace.dex_deptracker import collect_all_dep_decls
     from paraspace.dex_deptracker import build_dependencies
     from paraspace.dex_deptracker import _install_markers, _idx_marker
-    from paraspace.dex_deptracker import _offset_marker, _rel_offset_marker
     from paraspace.dex_deptracker import _patch_dex_type_markers
 
     _install_dexfile_4_deptracker()
@@ -260,3 +261,36 @@
     assert isinstance(clazz_def.annotationsOffRef.value,
                       dexfile._DEX_AnnotationsDirectoryItem)
     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)
+
+    print dex.typeLists.items[0].value.data_offset
+    assert dex.typeLists.items[0].value.data_offset == offset0
+    assert dex.typeLists.items[1].value.data_offset == offset1
+    pass