# HG changeset patch # User Thinker K.F. Li # Date 1308412777 -28800 # Node ID 0c0a659187c2f53f1d3a433fd72bc7922a7e41ab # Parent aa05cc7ccd0d7431946cbafa4285511db7b94914 Use _objs_asso to define association between two set of items. Derivation of _objs_asso define a rule to assocate elements from first set to another element in second set. diff -r aa05cc7ccd0d -r 0c0a659187c2 paraspace/dex_deptracker.py --- a/paraspace/dex_deptracker.py Thu Jun 16 08:03:50 2011 +0800 +++ b/paraspace/dex_deptracker.py Sat Jun 18 23:59:37 2011 +0800 @@ -157,15 +157,21 @@ def _dex_tree_get_child(obj, child_name): - if isinstance(obj, list): - idx = int(child_name) - return obj[idx] - - if isinstance(obj, dexfile.switch): - assert obj.map[eval(child_name)] == obj.child_type - return obj.value - - return getattr(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 _dex_tree_set_child(obj, child_name, value): @@ -330,17 +336,26 @@ @staticmethod def find_depon(name_path, parents): + name_parts = name_path.split('.') + dex_types = _all_dex_types() + comp_type_name = name_parts[0] + comp_type = dex_types[comp_type_name] + rev_parents = list(parents) rev_parents.reverse() for parent in rev_parents: + if isinstance(parent, comp_type): + attr_name = '.'.join(name_parts[1:]) + depon = _dex_tree_get_child(parent, attr_name) + return depon + try: rel_marker_info = parent.rel_marker_info except: continue if name_path in rel_marker_info: depons = rel_marker_info[name_path] - print parent, depons assert len(depons) == 1 depon = depons[0] return depon @@ -361,12 +376,24 @@ return array def link_prepare(self, obj, name_path, parents, markers_info): + try: + id_item_map = markers_info[name_path] + except KeyError: + id_item_map = [] + markers_info[name_path] = id_item_map + pass + for idx, item in enumerate(obj.items): + id_item_map[idx] = item + pass 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) + pass marker = _offset_marker(obj, name_path) name = name_path.split('.')[-1] _dex_tree_set_child(parent, name, marker) @@ -375,6 +402,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) + pass marker = _rel_offset_marker(obj, name_path) name = name_path.split('.')[-1] _dex_tree_set_child(parent, name, marker) @@ -383,6 +413,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) + pass marker = _uid_marker(obj, name_path) name = name_path.split('.')[-1] _dex_tree_set_child(parent, name, marker) @@ -391,6 +424,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) + pass marker = _idx_marker(obj, name_path) name = name_path.split('.')[-1] _dex_tree_set_child(parent, name, marker) @@ -479,6 +515,23 @@ pass +def _build_associations(root_obj): + for obj, parents, name_path in \ + _travel_dex_relocatable(root_obj): + if isinstance(obj, dexfile._objs_asso): + for parent in parents: + if isinstance(parent, dexfile.composite): + break + pass + + left_elts = _dex_tree_get_child(parent, obj.left) + right_elts = _dex_tree_get_child(parent, obj.right) + obj.build_associations() + pass + pass + pass + + def _link_dependencies(root_obj, all_dep_decls): markers_info = {} depon_src_map = {} @@ -520,13 +573,13 @@ _dex_tree_set_child(parent, name, (depon1, depon2)) elif dep_type == dexfile.depend_off: depon_name_path = dep[1] - depon = markers_info[depon_name_path] + depon = markers_info[depon_name_path][obj] parent = parents[-1] name = name_path.split('.')[-1] _dex_tree_set_child(parent, name, depon) elif dep_type == dexfile.depend_idx: depon_name_path = dep[1] - depon = markers_info[depon_name_path] + depon = markers_info[depon_name_path][obj] parent = parents[-1] name = name_path.split('.')[-1] _dex_tree_set_child(parent, name, depon) diff -r aa05cc7ccd0d -r 0c0a659187c2 paraspace/dexfile.py --- a/paraspace/dexfile.py Thu Jun 16 08:03:50 2011 +0800 +++ b/paraspace/dexfile.py Sat Jun 18 23:59:37 2011 +0800 @@ -175,7 +175,7 @@ class tap(_dex_type): @staticmethod def parse(parent, data, off): - pass + return tap() @staticmethod def sizeof(v): @@ -329,6 +329,84 @@ return o.__class__.sizeof(o) +## \biref Associate objects from two set of objects. +# +class _objs_asso(_dex_type): + left = None + left_ref = None + right = None + right_ref = None + + ## \brief Update references for a element pair from left and right. + # + # This method must be called by derivation to associate a pair of + # elements. + # + def _update_refs(self, left_elt, right_elt): + lref = getattr(left_elt, self.left_ref) + if not isinstance(right_elt, lref.target_path): + raise TypeError, 'invalid target_path in left %s' % (repr(le)) + + rref = getattr(right_elt, self.right_ref) + if not isinstance(left_elt, rref.target_path): + raise TypeError, 'invalid target_path in right %s' % (repr(re)) + + new_lref = ref(lref.target_path) + new_lref.target = right_elt + setattr(left_elt, self.left_ref, new_lref) + + new_rref = ref(rref.target_path) + new_rref.target = left_elt + setattr(right_elt, self.right_ref, new_rref) + pass + + ## \brief Assocate elements from left list to a respective right element. + # + # This method must be called before linking dependencies. + # + def build_associations(self, left, right): + raise NotImplementedError, 'build_associations is not implemented' + pass + + +## \brief One to one association. +# +# Associate nth element from left sequence to nth element in right +# sequence. +# +class one2one(_objs_asso): + def __init__(self, left, left_ref, right, right_ref): + self.left = left + self.left_ref = left_ref + self.right = right + self.right_ref = right_ref + pass + + ## \brief Associate elements from left list to elements from right list + # + def build_associations(self, left, right): + assert len(left) == len(right) + for le, re in map(None, left, right): + self._update_refs(le, re) + pass + pass + pass + + +## \brief Implicit reference to a target. +# +# It is a placeholder for storing relationship defined by an association. +# +class ref(_dex_type): + target_path = None + target = None + + def __init__(self, target_path=None): + self.target_path = target_path + pass + pass + + class relocatable(_dex_type): data_size = None @@ -832,11 +910,18 @@ class _DEX_TypeList(composite): - padding = auto_align(2) # 2 bits alignment num = uint32 typeItems = array('num', uint16) - child_names = 'padding num typeItems'.split() + child_names = 'num typeItems'.split() + pass + + +class _DEX_TypeList_align(composite): + padding = auto_align(2) # 2 bits alignment + value = _DEX_TypeList + + child_names = 'padding value'.split() pass @@ -844,7 +929,8 @@ startAddr = uint32 insnCount = uint16 handlerOff = depend_off_rel('_DEX_Code.handlers_size', - '_DEX_Catch')(uint16) + '_DEX_Try.catch_ref.target')(uint16) + catch_ref = ref('_DEX_Catch') child_names = 'startAddr insnCount handlerOff'.split() pass @@ -870,6 +956,7 @@ handlers = array('count', _DEX_CatchHandler) catchAllHandler = cond((lambda parent, data, off: parent.catchesAll), _DEX_CatchAllHandler) + try_ref = ref('_DEX_Try') child_names = 'size handlers catchAllHandler'.split() @@ -903,6 +990,8 @@ handlers_size = cond(_has_tries, uleb128) catch_handler_items = cond(_has_tries, array('handlers_size.value', _DEX_Catch)) + try_catch_asso = one2one('try_items.value.items', 'catch_ref', + 'catch_handler_items.value.items', 'try_ref') padding2 = auto_align(2) @@ -1326,7 +1415,7 @@ methodIds = array(None, _DEX_MethodId) classDefs = array(None, _DEX_ClassDef) classDatas = array(None, _DEX_ClassData) - typeLists = array(None, _DEX_TypeList) + typeLists = array(None, _DEX_TypeList_align) codeItems = array(None, _DEX_Code) annotationSetItems = array(None, _DEX_AnnotationSetItem) annotationsDirectoryItems = array(None, _DEX_AnnotationsDirectoryItem) diff -r aa05cc7ccd0d -r 0c0a659187c2 paraspace/tests/dexfile_test.py --- a/paraspace/tests/dexfile_test.py Thu Jun 16 08:03:50 2011 +0800 +++ b/paraspace/tests/dexfile_test.py Sat Jun 18 23:59:37 2011 +0800 @@ -35,7 +35,7 @@ assert deps['_DEX_ClassDef.staticValuesOff'][0] == dexfile.depend_off assert deps['_DEX_ClassDef.staticValuesOff'][1] == '_DEX_EncodedArrayItem' assert deps['_DEX_Try.handlerOff'][0] == dexfile.depend_off_rel - assert deps['_DEX_Try.handlerOff'][1] == '_DEX_Catch' + assert deps['_DEX_Try.handlerOff'][1] == '_DEX_Try.catch_ref.target' assert deps['_DEX_Try.handlerOff'][2] == '_DEX_Code.handlers_size' pass @@ -101,13 +101,12 @@ srcroot = os.path.join(srcdir, '..', '..') testdatapath = os.path.join(srcroot, 'data', 'testdata1.dex') dex = dexfile.DEXFile.open(testdatapath) - dexroot = dex.typeLists.items[0] + dexroot = dex.typeLists.items[0].value itr = _travel_dex_relocatable(dexroot) pathes = [v[2] for v in itr] - assert len(pathes) == 6 + assert len(pathes) == 5 assert '_DEX_TypeList' in pathes - assert '_DEX_TypeList.padding' in pathes assert '_DEX_TypeList.num' in pathes assert '_DEX_TypeList.typeItems' in pathes assert '_DEX_TypeList.typeItems.items' in pathes @@ -192,12 +191,14 @@ _patch_dex_type_markers(all_dep_decls) assert isinstance(dexfile._DEX_TypeList, _offset_marker) - assert isinstance(dexfile.DEXFile.typeLists.child_type, _offset_marker) + assert isinstance(dexfile.DEXFile.typeLists.child_type.value, + _offset_marker) pass 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 _link_dependencies from paraspace.dex_deptracker import _install_markers, _idx_marker from paraspace.dex_deptracker import _offset_marker, _rel_offset_marker @@ -215,6 +216,7 @@ testdatapath = os.path.join(srcroot, 'data', 'testdata1.dex') dex = dexfile.DEXFile.open(testdatapath) + _build_associations(dex) _link_dependencies(dex, all_dep_decls) code_item = dex.codeItems.items[0]