changeset 109:835336632aba

Add collect_typeidxs_in_method()
author Thinker K.F. Li <thinker@codemud.net>
date Mon, 01 Aug 2011 14:37:04 +0800
parents 18be67af7f1e
children 6380730a80b4
files paraspace/dexfile.py paraspace/injection.py paraspace/tests/injection_test.py
diffstat 3 files changed, 92 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/paraspace/dexfile.py	Mon Aug 01 12:27:28 2011 +0800
+++ b/paraspace/dexfile.py	Mon Aug 01 14:37:04 2011 +0800
@@ -1902,6 +1902,19 @@
                    for tl_typeid in tl_typeids]
         return typeids
 
+    ## \brief Return code block of given method.
+    #
+    # Code block is a string of byte code instructions for Dalvik VM.
+    #
+    @staticmethod
+    def get_code_block_method(method):
+        if not method.codeOffRef.is_true:
+            return ''
+
+        code = method.codeOffRef.value
+        insns = code.insns.data
+        return insns
+
     ## \brief Dump content of a proto ID.
     @staticmethod
     def dump_protoid(protoid):
--- a/paraspace/injection.py	Mon Aug 01 12:27:28 2011 +0800
+++ b/paraspace/injection.py	Mon Aug 01 14:37:04 2011 +0800
@@ -364,3 +364,55 @@
         class_redirect_types(dex, classdef, types_redir, methods_redir)
         pass
     pass
+
+
+## \brief Collect all type indices mentioned in the code of given method.
+#
+# \param method is a \ref _DEX_Method.
+#
+def collect_typeidxs_in_method(dex, method):
+    from paraspace.dexfile import _DEX_Method, DEXFile_linked
+    from paraspace.dalvik_opcodes import decode_insn_blk, all_opcodes
+    from itertools import chain
+    
+    assert isinstance(method, _DEX_Method)
+
+    def get_typeidx_methodidx(methodidx):
+        methodid = dex.find_methodid_idx(methodidx)
+        method_typeid = methodid.classIdx
+        method_typeidx = dex.get_idx_typeid(method_typeid)
+        return method_typeidx
+
+    def collect_types_in_op_vector(op_vector):
+        code, args = op_vector
+        
+        if code == all_opcodes.OP_NEW_INSTANCE:
+            return (args[1],)
+        
+        if code in (all_opcodes.OP_INVOKE_DIRECT,
+                    all_opcodes.OP_INVOKE_VIRTUAL,
+                    all_opcodes.OP_INVOKE_SUPER,
+                    all_opcodes.OP_INVOKE_STATIC,
+                    all_opcodes.OP_INVOKE_INTERFACE):
+            methodidx = args[2]
+            method_typeidx = get_typeidx_methodidx(methodidx)
+            return (method_typeidx,)
+
+        if code in (all_opcodes.OP_INVOKE_VIRTUAL_RANGE,
+                    all_opcodes.OP_INVOKE_DIRECT_RANGE,
+                    all_opcodes.OP_INVOKE_SUPER_RANGE,
+                    all_opcodes.OP_INVOKE_STATIC_RANGE,
+                    all_opcodes.OP_INVOKE_INTERFACE_RANGE):
+            methodidx = args[1]
+            method_typeidx = get_typeidx_methodidx(methodidx)
+            return (method_typeidx,)
+        
+        return ()
+
+    code_blk = DEXFile_linked.get_code_block_method(method)
+    op_vectors = decode_insn_blk(code_blk)
+    types_insns = [collect_types_in_op_vector(op_vector)
+                   for op_vector in op_vectors]
+    typeidxs = list(chain(*types_insns))
+    
+    return typeidxs
--- a/paraspace/tests/injection_test.py	Mon Aug 01 12:27:28 2011 +0800
+++ b/paraspace/tests/injection_test.py	Mon Aug 01 14:37:04 2011 +0800
@@ -172,3 +172,30 @@
             pass
         pass
     pass
+
+
+def collect_types_in_method_test():
+    from paraspace.dex_deptracker import prepare_dep_decls
+    from paraspace.injection import collect_typeidxs_in_method
+    
+    _install_dexfile_4_deptracker()
+    
+    all_dep_decls = prepare_dep_decls()
+    
+    srcdir = os.path.dirname(__file__)
+    srcroot = os.path.join(srcdir, '..', '..')
+    
+    fakefile_fn = os.path.join(srcroot, 'data', 'fakefile.dex')
+    fakefile_dex = dexfile.DEXFile.open(fakefile_fn)
+    fakefile_linked = \
+        dexfile.DEXFile_linked. \
+        build_dependencies(fakefile_dex, all_dep_decls)
+    
+    fakefile_def = \
+        fakefile_linked.find_class_name('Lcom/codemud/fakefile/fakefile;')
+
+    init_method = fakefile_linked.find_method_name('<init>', fakefile_def)
+
+    typeidxs = collect_typeidxs_in_method(fakefile_linked, init_method)
+    assert len(typeidxs) == 1
+    pass