changeset 41:c5cfc796af8b

Use value_ref & cond in dexfile.py to avoid 0 offset value Some object would use zero value for an invalid dependency offset, it causes an key error. We use dexfile.cond and add dexfile.value_ref class to build dependencies conditional.
author Thinker K.F. Li <thinker@codemud.net>
date Sun, 19 Jun 2011 13:47:35 +0800
parents 0c0a659187c2
children 8ca4a6bc6b79
files paraspace/dex_deptracker.py paraspace/dexfile.py paraspace/tests/dexfile_test.py
diffstat 3 files changed, 137 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/paraspace/dex_deptracker.py	Sat Jun 18 23:59:37 2011 +0800
+++ b/paraspace/dex_deptracker.py	Sun Jun 19 13:47:35 2011 +0800
@@ -484,8 +484,6 @@
                         if type(attr) == type and
                         issubclass(attr, dexfile.composite) and
                         attr in marked_types]
-    import pprint
-    pprint.pprint(marked_type_refs)
     
     def patch_ref(name_path, depon_path):
         depon, depon_parent = _resolve_name_path(depon_path)
@@ -532,6 +530,16 @@
     pass
 
 
+def _build_refs(root_obj):
+    for obj, parents, name_path in \
+            _travel_dex_relocatable(root_obj):
+        if not isinstance(obj, dexfile.value_ref):
+            continue
+        obj.set_value(parents)
+        pass
+    pass
+
+
 def _link_dependencies(root_obj, all_dep_decls):
     markers_info = {}
     depon_src_map = {}
@@ -562,6 +570,9 @@
         if name_path not in all_dep_decls:
             continue
 
+        if obj is None and isinstance(parents[-1], dexfile.cond):
+            continue
+
         dep = all_dep_decls[name_path]
         dep_type = dep[0]
         if dep_type == dexfile.depend_off_rel:
--- a/paraspace/dexfile.py	Sat Jun 18 23:59:37 2011 +0800
+++ b/paraspace/dexfile.py	Sun Jun 19 13:47:35 2011 +0800
@@ -23,6 +23,26 @@
     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
@@ -404,6 +424,49 @@
     def __init__(self, target_path=None):
         self.target_path = target_path
         pass
+
+    @staticmethod
+    def parse(parent, data, off):
+        pass
+
+    @staticmethod
+    def sizeof(v):
+        return 0
+
+    @staticmethod
+    def compute_size():
+        pass
+
+    @staticmethod
+    def to_str():
+        return ''
+
+    def set_value(self, parents):
+        pass
+    pass
+
+
+## \brief Reference to a value from a given path.
+#
+class value_ref(ref):
+    def set_value(self, parents):
+        pparts = self.target_path.split('.')
+        clazz = pparts[0]
+        
+        rev_parents = list(parents)
+        rev_parents.reverse()
+        
+        for parent in rev_parents:
+            if isinstance(rev_parents, clazz):
+               break
+            pass
+        else:
+            raise ValueError, 'can not find %s' % (self.target_path)
+
+        attr_path = '.'.join(pparts[1:])
+        value = _dex_tree_get_child(parent, attr_path)
+        self.target = value
+        pass
     pass
 
 
@@ -827,9 +890,13 @@
 class _DEX_ProtoId(composite):
     shortyIdx = depend_idx('DEXFile.stringIds')(uint32)
     returnTypeIdx = depend_idx('DEXFile.typeIds')(uint32)
-    parametersOff = depend_off('_DEX_TypeList')(uint32)
+    parametersOff = uint32
+    parametersOffRef = cond((lambda parent, data, off: parent.parametersOff),
+                            depend_off('_DEX_TypeList')
+                            (value_ref('_DEX_ProtoId.parametersOff')))
     
-    child_names = 'shortyIdx returnTypeIdx parametersOff'.split()
+    child_names = 'shortyIdx returnTypeIdx parametersOff ' \
+        'parametersOffRef'.split()
     pass
 
 
@@ -855,15 +922,26 @@
     classIdx = depend_idx('DEXFile.typeIds')(uint32)
     accessFlags = uint32
     superclassIdx = depend_idx('DEXFile.typeIds')(uint32)
-    interfacesOff = depend_off('_DEX_TypeList')(uint32)
+    interfacesOff = uint32
+    interfacesOffRef = cond((lambda parent, data, off: parent.interfacesOff),
+                            depend_off('_DEX_TypeList')
+                            (value_ref('_DEX_ClassDef.interfacesOff')))
     sourceFileIdx = depend_idx('DEXFile.stringIds')(uint32)
-    annotationsOff = depend_off('_DEX_AnnotationsDirectoryItem')(uint32)
+    annotationsOff = uint32
+    annotationsOffRef = cond((lambda parent, data, off: parent.annotationsOff),
+                             depend_off('_DEX_AnnotationsDirectoryItem')
+                             (value_ref('_DEX_ClassDef.annotationsOff')))
     classDataOff = uint32
-    staticValuesOff = depend_off('_DEX_EncodedArrayItem')(uint32)
+    staticValuesOff = uint32
+    staticValuesOffRef = cond((lambda parent, data, off:
+                                   parent.staticValuesOff),
+                              depend_off('_DEX_EncodedArrayItem')
+                              (value_ref('_DEX_ClassDef.staticValuesOff')))
     
     child_names = \
-        'classIdx accessFlags superclassIdx interfacesOff ' \
-        'sourceFileIdx annotationsOff classDataOff staticValuesOff'.split()
+        'classIdx accessFlags superclassIdx interfacesOff interfacesOffRef ' \
+        'sourceFileIdx annotationsOff annotationsOffRef ' \
+        'classDataOff staticValuesOff staticValuesOffRef'.split()
     pass
 
 
@@ -890,9 +968,12 @@
 class _DEX_Method(composite):
     methodIdx = depend_idx('DEXFile.methodIds')(uleb128)
     accessFlags = uleb128
-    codeOff = depend_off('_DEX_Code')(uleb128)
+    codeOff = uleb128
+    codeOffRef = cond((lambda parent, data, off: parent.codeOff),
+                      depend_off('_DEX_Code')
+                      (value_ref('_DEX_Method.codeOff')))
 
-    child_names = 'methodIdx accessFlags codeOff'.split()
+    child_names = 'methodIdx accessFlags codeOff codeOffRef'.split()
     pass
 
 
@@ -1012,30 +1093,47 @@
 
 class _DEX_FieldAnnotationsItem(composite):
     fieldIdx = depend_idx('DEXFile.fieldIds')(uint32)
-    annotationsOff = depend_off('_DEX_AnnotationSetItem')(uint32)
+    annotationsOff = uint32
+    annotationsOffRef = cond((lambda parent, data, off: parent.annotationsOff),
+                             depend_off('_DEX_AnnotationSetItem')
+                             (value_ref('_DEX_FieldAnnotationsItem.'
+                                        'annotationsOff')))
     
-    child_names = 'fieldIdx annotationsOff'.split()
+    child_names = 'fieldIdx annotationsOff annotationsOffRef'.split()
     pass
 
 
 class _DEX_MethodAnnotationsItem(composite):
     methodIdx = depend_idx('DEXFile.methodIds')(uint32)
-    annotationsOff = depend_off('_DEX_AnnotationSetItem')(uint32)
+    annotationsOff = uint32
+    annotationsOffRef = cond((lambda parent, data, off: parent.annotationsOff),
+                             depend_off('_DEX_AnnotationSetItem')
+                             (value_ref('_DEX_MethodAnnotationsItem.'
+                                        'annotationsOff')))
 
-    child_names = 'methodIdx annotationsOff'.split()
+    child_names = 'methodIdx annotationsOff annotationsOffRef'.split()
     pass
 
 
 class _DEX_ParameterAnnotationsItem(composite):
     methodIdx = depend_idx('DEXFile.methodIds')(uint32)
-    annotationsOff = depend_off('_DEX_AnnotationSetItem')(uint32)
+    annotationsOff = uint32
+    annotationsOffRef = cond((lambda parent, data, off: parent.annotationsOff),
+                             depend_off('_DEX_AnnotationSetItem')
+                             (value_ref('_DEX_ParameterAnnotationsItem.'
+                                        'annotationsOff')))
 
-    child_names = 'methodIdx annotationsOff'.split()
+    child_names = 'methodIdx annotationsOff annotationsOffRef'.split()
     pass
 
 
 class _DEX_AnnotationsDirectoryItem(composite):
-    classAnnotationsOff = depend_off('_DEX_AnnotationSetItem')(uint32)
+    classAnnotationsOff = uint32
+    classAnnotationsOffRef = cond((lambda parent, data, off:
+                                       parent.classAnnotationsOff),
+                             depend_off('_DEX_AnnotationSetItem')
+                             (value_ref('_DEX_AnnotationsDirectoryItem.'
+                                        'classAnnotationsOff')))
     fieldsSize = uint32
     methodsSize = uint32
     parametersSize = uint32
@@ -1045,7 +1143,8 @@
     parameterAnnotationsItems = array('parametersSize',
                                       _DEX_ParameterAnnotationsItem)
 
-    child_names = 'classAnnotationsOff fieldsSize methodsSize ' \
+    child_names = 'classAnnotationsOff classAnnotationsOffRef ' \
+        'fieldsSize methodsSize ' \
         'parametersSize fieldAnnotationsItems methodAnnotationsItems ' \
         'parameterAnnotationsItems'.split()
     pass
--- a/paraspace/tests/dexfile_test.py	Sat Jun 18 23:59:37 2011 +0800
+++ b/paraspace/tests/dexfile_test.py	Sun Jun 19 13:47:35 2011 +0800
@@ -32,8 +32,10 @@
     assert deps['_DEX_AnnotationItem.typeIdx'][1] == 'DEXFile.typeIds'
     assert deps['_DEX_FieldId.typeIdx'][0] == dexfile.depend_idx
     assert deps['_DEX_FieldId.typeIdx'][1] == 'DEXFile.typeIds'
-    assert deps['_DEX_ClassDef.staticValuesOff'][0] == dexfile.depend_off
-    assert deps['_DEX_ClassDef.staticValuesOff'][1] == '_DEX_EncodedArrayItem'
+    assert deps['_DEX_ClassDef.staticValuesOffRef.value'][0] == \
+        dexfile.depend_off
+    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'][2] == '_DEX_Code.handlers_size'
@@ -73,7 +75,7 @@
     assert deps['_DEX_ProtoId.shortyIdx'][0] == dexfile.depend_idx
     assert deps['_DEX_ProtoId.shortyIdx'][1] == 'DEXFile.stringIds'
 
-    assert deps['_DEX_ProtoId.parametersOff'][1] == '_DEX_TypeList'
+    assert deps['_DEX_ProtoId.parametersOffRef.value'][1] == '_DEX_TypeList'
     pass
 
 
@@ -199,6 +201,7 @@
 def link_dependencies_test():
     from paraspace.dex_deptracker import collect_all_dep_decls
     from paraspace.dex_deptracker import _build_associations
+    from paraspace.dex_deptracker import _build_refs
     from paraspace.dex_deptracker import _link_dependencies
     from paraspace.dex_deptracker import _install_markers, _idx_marker
     from paraspace.dex_deptracker import _offset_marker, _rel_offset_marker
@@ -217,9 +220,10 @@
     dex = dexfile.DEXFile.open(testdatapath)
 
     _build_associations(dex)
+    _build_refs(dex)
     _link_dependencies(dex, all_dep_decls)
     
     code_item = dex.codeItems.items[0]
     print code_item.debugInfoOff.__class__
-    assert code_item.debugInfoOff.__class__ == dexfile._DEX_DebugInfoItem
+    assert code_item.debugInfoOff.__class__.__name__ == '_DEX_DebugInfoItem'
     pass