changeset 139:0704e23009e4

Fix bug of not dealing encoded method indices. - Becase space optimization, DEX ecnode value for method indices in _DEX_Method. - _deoptimize_classdata() was called at beginning of build_dependencies(). - _optimize_classdata() was called at end of restore_dependencies().
author Thinker K.F. Li <thinker@codemud.net>
date Wed, 10 Aug 2011 20:05:14 +0800
parents 372009418896
children d4e794249b0f
files paraspace/dex_deptracker.py paraspace/tests/injection_test.py
diffstat 2 files changed, 129 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/paraspace/dex_deptracker.py	Wed Aug 10 14:28:24 2011 +0800
+++ b/paraspace/dex_deptracker.py	Wed Aug 10 20:05:14 2011 +0800
@@ -805,7 +805,72 @@
     pass
 
 
+## \brief Deoptimize methods of classdatas.
+#
+# This function must be called at beginning of build_dependencies().
+# For space optimization reason, values of method index in _DEX_Method
+# are related previous item, except first one.  For convenient,
+# this function replcae them with absolute ones.  It should be reversed
+# to relative one when running restore_dependencies().
+#
+def _deoptimize_classdata(dexroot):
+    for classdata in dexroot.classDatas.items:
+        methods = classdata.directMethods.items
+        if len(methods) > 1:
+            firstmethod = methods[0]
+            lastidx = firstmethod.methodIdx
+            for method in methods[1:]:
+                lastidx = lastidx + method.methodIdx
+                method.methodIdx = lastidx
+                pass
+            pass
+        
+        methods = classdata.virtualMethods.items
+        if len(methods) > 1:
+            firstmethod = methods[0]
+            lastidx = firstmethod.methodIdx
+            for method in methods[1:]:
+                lastidx = lastidx + method.methodIdx
+                method.methodIdx = lastidx
+                pass
+            pass
+        pass
+    pass
+
+
+## \biref Optimize methods of classdatas.
+#
+# \see _deoptimize_classdata
+#
+def _optimize_classdata(dexroot):
+    for classdata in dexroot.classDatas.items:
+        methods = classdata.directMethods.items
+        if len(methods) > 1:
+            firstmethod = methods[0]
+            lastidx = firstmethod.methodIdx
+            for method in methods[1:]:
+                save_idx = method.methodIdx
+                method.methodIdx = method.methodIdx - lastidx
+                lastidx = save_idx
+                pass
+            pass
+        
+        methods = classdata.virtualMethods.items
+        if len(methods) > 1:
+            firstmethod = methods[0]
+            lastidx = firstmethod.methodIdx
+            for method in methods[1:]:
+                save_idx = method.methodIdx
+                method.methodIdx = method.methodIdx - lastidx
+                lastidx = save_idx
+                pass
+            pass
+        pass
+    pass
+
+
 def build_dependencies(dexroot, all_dep_decls):
+    _deoptimize_classdata(dexroot)
     _build_associations(dexroot)
     _build_refs(dexroot)
     _link_dependencies(dexroot, all_dep_decls)
@@ -1070,6 +1135,7 @@
         pass
 
     _sync_DEXFile_fields(dexroot)
+    _optimize_classdata(dexroot)
     pass
 
 
--- a/paraspace/tests/injection_test.py	Wed Aug 10 14:28:24 2011 +0800
+++ b/paraspace/tests/injection_test.py	Wed Aug 10 20:05:14 2011 +0800
@@ -641,6 +641,7 @@
         hello_linked.find_methodids_typeid(helloworld_typeid)
     for methodid in helloworld_methodids:
         methodname = hello_linked.get_methodid_name(methodid)
+        print 'TEST', methodname
         if methodname == 'onClick':
             methodidx = hello_linked.get_idx_methodid(methodid)
             method = hello_linked.find_method_idx(methodidx)
@@ -650,6 +651,14 @@
             saved_methodid0 = hello_linked.find_methodid_idx(methodidx)
             methodidx = opvectors[12][1][1]
             saved_methodid1 = hello_linked.find_methodid_idx(methodidx)
+        elif methodname == 'write_file':
+            assert methodid in hello_linked.methodIds.items
+            methodidx = hello_linked.get_idx_methodid(methodid)
+            print 'TEST', dexfile.DEXFile_linked.get_typeid_name(methodid.classIdx)
+            method = hello_linked.find_method_idx(methodidx)
+            blk = dexfile.DEXFile_linked.get_code_block_method(method)
+            opvectors = decode_insn_blk(blk)
+            print opvectors
             pass
         pass
 
@@ -686,5 +695,59 @@
             assert new_methodid1 in hello_linked.methodIds.items
             assert new_methodid1 is saved_methodid1
             pass
+        elif methodname == 'write_file':
+            assert methodid in hello_linked.methodIds.items
+            methodidx = hello_linked.get_idx_methodid(methodid)
+            print dexfile.DEXFile_linked.get_typeid_name(methodid.classIdx)
+            method = hello_linked.find_method_idx(methodidx)
+            blk = dexfile.DEXFile_linked.get_code_block_method(method)
+            opvectors = decode_insn_blk(blk)
+            print opvectors
+            pass
+        pass
+    assert False
+    pass
+
+
+## \brief Test case for checking methods of classdatas are consistent.
+#
+# Becase space optimization, DEX ecnode value for method indices
+# in \ref _DEX_Method.  This test case make sure build_dependencies()
+# decode indices correctly.
+#
+# \see _deoptimize_classdata
+#
+def class_methods_consistent_test():
+    from paraspace.dex_deptracker import prepare_dep_decls
+    
+    _install_dexfile_4_deptracker()
+    
+    all_dep_decls = prepare_dep_decls()
+    
+    srcdir = os.path.dirname(__file__)
+    datapath = os.path.join(srcdir, '..', '..', 'data')
+
+    hello_path = os.path.join(datapath, 'helloworld.dex')
+    
+    hello_dex = dexfile.DEXFile.open(hello_path)
+    
+    hello_linked = dexfile.DEXFile_linked.build_dependencies(hello_dex,
+                                                             all_dep_decls)
+
+    for classdata in hello_linked.classDatas.items:
+        allmethods = classdata.directMethods.items + \
+            classdata.virtualMethods.items
+        if len(allmethods) < 2:
+            continue
+
+        firstmethod = allmethods[0]
+        firstmethodid = firstmethod.methodIdx
+        for idx, method in enumerate(allmethods[1:]):
+            try:
+                assert method.methodIdx.classIdx == firstmethodid.classIdx
+            except:
+                print 'ERROR: method %d' % (idx + 1)
+                raise
+            pass
         pass
     pass