# HG changeset patch # User Thinker K.F. Li # Date 1308462455 -28800 # Node ID c5cfc796af8bb19ab81fa5660db370f33584259b # Parent 0c0a659187c2f53f1d3a433fd72bc7922a7e41ab 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. diff -r 0c0a659187c2 -r c5cfc796af8b paraspace/dex_deptracker.py --- 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: diff -r 0c0a659187c2 -r c5cfc796af8b paraspace/dexfile.py --- 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 diff -r 0c0a659187c2 -r c5cfc796af8b paraspace/tests/dexfile_test.py --- 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