changeset 43:5cea19126a11

Fix issue of _build_refs() - _build_refs() does not handle dexfile.cond well when traveling. - fix it - Move from ref.get_value() to ref.set_value().
author Thinker K.F. Li <thinker@codemud.net>
date Sun, 19 Jun 2011 19:36:36 +0800
parents 8ca4a6bc6b79
children 8fc294b06e22
files paraspace/dex_deptracker.py paraspace/dexfile.py paraspace/tests/dexfile_test.py
diffstat 3 files changed, 120 insertions(+), 38 deletions(-) [+]
line wrap: on
line diff
--- a/paraspace/dex_deptracker.py	Sun Jun 19 14:26:09 2011 +0800
+++ b/paraspace/dex_deptracker.py	Sun Jun 19 19:36:36 2011 +0800
@@ -175,14 +175,30 @@
 
 
 def _dex_tree_set_child(obj, child_name, value):
+    child_parts = child_name.split('.')
+    for child_part in child_parts[:-1]:
+        if isinstance(obj, list):
+            idx = int(child_part)
+            obj = obj[idx]
+            continue
+        
+        if isinstance(obj, dexfile.switch):
+            assert obj.map[eval(child_part)] == obj.child_type
+            obj = obj.value
+            continue
+        
+        obj = getattr(obj, child_part)
+        pass
+    
+    last_part = child_parts[-1]
     if isinstance(obj, list):
-        idx = int(child_name)
+        idx = int(last_part)
         obj[idx] = value
     elif isinstance(obj, dexfile.switch):
-        assert obj.map[eval(child_name)] == obj.child_type
+        assert obj.map[eval(last_part)] == obj.child_type
         obj.value = value
     else:
-        setattr(obj, child_name, value)
+        setattr(obj, last_part, value)
         pass
     pass
 
@@ -530,12 +546,58 @@
     pass
 
 
+## \brief Find a parent that is an instance of given clazz from a list.
+#
+def _find_parent_of_clazz(clazz, parents):
+    rev_parents = list(parents)
+    rev_parents.reverse()
+    for parent in rev_parents:
+        if isinstance(parent, clazz):
+            return parent
+        pass
+    raise TypeError, 'can not find a prent of %s type' % (repr(clazz))
+
+
+def _split_name_path_clazz_attr(name_path):
+    idx = name_path.index('.')
+    if idx >= 0:
+        clazz = name_path[:idx]
+        attr = name_path[idx + 1:]
+    else:
+        clazz = name_path
+        attr = None
+        pass
+    return clazz, attr
+
+
+## \brief Setup value of refs.
+#
 def _build_refs(root_obj):
     for obj, parents, name_path in \
             _travel_dex_relocatable(root_obj):
-        if not isinstance(obj, dexfile.value_ref):
+        if not parents:
+            continue
+
+        imm_parent = parents[-1]
+        if isinstance(imm_parent, dexfile.cond) and not imm_parent.is_true:
             continue
-        obj.set_value(parents)
+        
+        clazz, pclazz = _resolve_name_path(name_path)
+        while isinstance(clazz, dexfile.depend):
+            clazz = clazz.child_type
+            pass
+        
+        if isinstance(clazz, dexfile.ref):
+            pclazz_name, attr_name = _split_name_path_clazz_attr(name_path)
+            if not attr_name:
+                raise ValueError, \
+                    'not attribute name in name path (%s)' % (name_path)
+            
+            parent = _find_parent_of_clazz(dexfile.composite, parents)
+            
+            value = clazz.get_value(parents)
+            _dex_tree_set_child(parent, attr_name, value)
+            pass
         pass
     pass
 
@@ -570,7 +632,8 @@
         if name_path not in all_dep_decls:
             continue
 
-        if obj is None and isinstance(parents[-1], dexfile.cond):
+        imm_parent = parents[-1]
+        if isinstance(imm_parent, dexfile.cond) and not imm_parent.is_true:
             continue
 
         dep = all_dep_decls[name_path]
@@ -579,21 +642,18 @@
             depon1 = _rel_offset_marker.find_depon(dep[1], parents)
             depon2 = _rel_offset_marker.find_depon(dep[2], parents)
 
-            parent = parents[-1]
             name = name_path.split('.')[-1]
-            _dex_tree_set_child(parent, name, (depon1, depon2))
+            _dex_tree_set_child(imm_parent, name, (depon1, depon2))
         elif dep_type == dexfile.depend_off:
             depon_name_path = dep[1]
             depon = markers_info[depon_name_path][obj]
-            parent = parents[-1]
             name = name_path.split('.')[-1]
-            _dex_tree_set_child(parent, name, depon)
+            _dex_tree_set_child(imm_parent, name, depon)
         elif dep_type == dexfile.depend_idx:
             depon_name_path = dep[1]
             depon = markers_info[depon_name_path][obj]
-            parent = parents[-1]
             name = name_path.split('.')[-1]
-            _dex_tree_set_child(parent, name, depon)
+            _dex_tree_set_child(imm_parent, name, depon)
         else:
             raise TypeError, 'invalid depend type %s' % (repr(dep_type))
         pass
--- a/paraspace/dexfile.py	Sun Jun 19 14:26:09 2011 +0800
+++ b/paraspace/dexfile.py	Sun Jun 19 19:36:36 2011 +0800
@@ -23,26 +23,6 @@
     pass
 
 
-## \brief Get attribute of an object for a given path.
-#
-def _dex_tree_get_child(obj, child_name):
-    child_parts = child_name.split('.')
-    for child_part in child_parts:
-        if isinstance(obj, list):
-            idx = int(child_part)
-            obj = obj[idx]
-            continue
-        
-        if isinstance(obj, dexfile.switch):
-            assert obj.map[eval(child_part)] == obj.child_type
-            obj = obj.value
-            continue
-        
-        obj = getattr(obj, child_part)
-        pass
-    return obj
-
-
 def _to_uint(data):
     v = 0
     sh = 0
@@ -441,7 +421,7 @@
     def to_str():
         return ''
 
-    def set_value(self, parents):
+    def get_value(self, parents):
         pass
     pass
 
@@ -449,15 +429,19 @@
 ## \brief Reference to a value from a given path.
 #
 class value_ref(ref):
-    def set_value(self, parents):
+    def get_value(self, parents):
+        from paraspace.dex_deptracker import _resolve_name_path
+        from paraspace.dex_deptracker import _dex_tree_get_child
+        
         pparts = self.target_path.split('.')
-        clazz = pparts[0]
+        clazz_name = pparts[0]
+        clazz, dummy = _resolve_name_path(clazz_name)
         
         rev_parents = list(parents)
         rev_parents.reverse()
         
         for parent in rev_parents:
-            if isinstance(rev_parents, clazz):
+            if isinstance(parent, clazz):
                break
             pass
         else:
@@ -465,8 +449,7 @@
 
         attr_path = '.'.join(pparts[1:])
         value = _dex_tree_get_child(parent, attr_path)
-        self.target = value
-        pass
+        return value
     pass
 
 
@@ -603,6 +586,7 @@
     condition = None
     child_type = None
     value = None
+    is_true = None
     
     def __init__(self, cond, child_type):
         self.condition = cond
@@ -612,13 +596,17 @@
     def parse(self, parent, data, off):
         if self.condition(parent, data, off):
             value = self.child_type.parse(parent, data, off)
+            is_true = True
         else:
             value = None
+            is_true = False
             pass
 
         obj = cond(self.condition, self.child_type)
         obj.value = value
         obj.data_size = self.sizeof(obj)
+        obj.is_true = is_true
+        
         return obj
 
     def sizeof(self, v):
--- a/paraspace/tests/dexfile_test.py	Sun Jun 19 14:26:09 2011 +0800
+++ b/paraspace/tests/dexfile_test.py	Sun Jun 19 19:36:36 2011 +0800
@@ -222,3 +222,37 @@
     code_item = dex.codeItems.items[0]
     assert code_item.debugInfoOff.__class__.__name__ == '_DEX_DebugInfoItem'
     pass
+
+
+def link_dependencies_cond_value_ref_test():
+    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()
+
+    all_dep_decls = collect_all_dep_decls()
+    _install_markers(all_dep_decls)
+    assert isinstance(dexfile.DEXFile.typeIds, _idx_marker)
+    _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)
+    
+    code_item = dex.codeItems.items[0]
+    assert code_item.debugInfoOff.__class__.__name__ == '_DEX_DebugInfoItem'
+    
+    anno_dir_item = dex.annotationsDirectoryItems.items[0]
+    assert isinstance(anno_dir_item.classAnnotationsOffRef.value,
+                      dexfile._DEX_AnnotationSetItem)
+    
+    anno_dir_item = dex.annotationsDirectoryItems.items[1]
+    assert isinstance(anno_dir_item.classAnnotationsOffRef.value,
+                      dexfile._DEX_AnnotationSetItem)
+    pass