changeset 131:044bfc415577

Fix issue of data map verification. - Dalvik complain that data map generated by inject_redir.py is unexpected. - Test case map_verify_error_test() - Refactor inject_redir.py to paraspace.injection.inject_redir().
author Thinker K.F. Li <thinker@codemud.net>
date Tue, 09 Aug 2011 11:47:43 +0800
parents 117047deda64
children 75a31967ebee
files examples/inject_redir.py paraspace/dexfile.py paraspace/injection.py paraspace/tests/dex_deptracker_test.py paraspace/tests/injection_test.py
diffstat 5 files changed, 165 insertions(+), 43 deletions(-) [+]
line wrap: on
line diff
--- a/examples/inject_redir.py	Tue Aug 09 00:07:04 2011 +0800
+++ b/examples/inject_redir.py	Tue Aug 09 11:47:43 2011 +0800
@@ -7,10 +7,7 @@
 #
 from paraspace.dexfile import DEXFile, DEXFile_linked
 from paraspace.dex_deptracker import prepare_dep_decls
-from paraspace.dex_deptracker import restore_dependencies
-from paraspace.dex_deptracker import dex_sort_sorted_arrays
-from paraspace.injection import inject_classdefs, make_methodidxs_redir_map
-from paraspace.injection import dexfile_redirect_types
+from paraspace.injection import inject_redir
 import sys
 
 if len(sys.argv) != 6:
@@ -21,42 +18,28 @@
     sys.exit(1)
     pass
 
-src_dexname = sys.argv[1]
-inj_classname = sys.argv[2]
-dst_dexname = sys.argv[3]
-redir_classname = sys.argv[4]
-output_name = sys.argv[5]
 
-decls = prepare_dep_decls()
-
-src_dex = DEXFile.open(src_dexname)
-src_linked = DEXFile_linked.build_dependencies(src_dex, decls)
-
-dst_dex = DEXFile.open(dst_dexname)
-dst_linked = DEXFile_linked.build_dependencies(dst_dex, decls)
-
-inj_classdef = src_linked.find_class_name(inj_classname)
-injected_classdefs = inject_classdefs(dst_linked, src_linked, [inj_classdef])
-
-redir_typeid = dst_linked.find_typeid_name(redir_classname)
-redir_typeidx = dst_linked.get_idx_typeid(redir_typeid)
-inj_typeid = dst_linked.find_typeid_name(inj_classname)
-inj_typeidx = dst_linked.get_idx_typeid(inj_typeid)
-typeidxs_redir = {redir_typeidx: inj_typeidx}
-
-methodidxs_redir = \
-    make_methodidxs_redir_map(dst_linked, dst_linked, typeidxs_redir)
-
-injected_typeidxs = [dst_linked.get_idx_classdef(classdef)
-                     for classdef in injected_classdefs]
-dexfile_redirect_types(dst_linked, typeidxs_redir, methodidxs_redir,
-                       excludes=injected_typeidxs)
-
-dex_sort_sorted_arrays(dst_linked)
-restore_dependencies(dst_linked, decls)
-
-restore_raw = dst_linked.to_str()
-
-ofile = open(output_name, 'w')
-ofile.write(restore_raw)
-ofile.close()
+if __name__ == '__main__':
+    src_dexname = sys.argv[1]
+    inj_classname = sys.argv[2]
+    dst_dexname = sys.argv[3]
+    redir_classname = sys.argv[4]
+    output_name = sys.argv[5]
+    
+    decls = prepare_dep_decls()
+    
+    src_dex = DEXFile.open(src_dexname)
+    src_linked = DEXFile_linked.build_dependencies(src_dex, decls)
+    
+    dst_dex = DEXFile.open(dst_dexname)
+    dst_linked = DEXFile_linked.build_dependencies(dst_dex, decls)
+    
+    inject_redir(src_linked, inj_classname,
+                 dst_linked, redir_classname, decls)
+    
+    restore_raw = dst_linked.to_str()
+    
+    ofile = open(output_name, 'w')
+    ofile.write(restore_raw)
+    ofile.close()
+    pass
--- a/paraspace/dexfile.py	Tue Aug 09 00:07:04 2011 +0800
+++ b/paraspace/dexfile.py	Tue Aug 09 11:47:43 2011 +0800
@@ -971,6 +971,9 @@
         0x2005: 'kDexTypeEncodedArrayItem',
         0x2006: 'kDexTypeAnnotationsDirectoryItem'
         }
+
+    name_to_types = dict([(_name, _typenum)
+                          for _typenum, _name in types.items()])
     
     child_names = \
         'type unused size offset'.split()
--- a/paraspace/injection.py	Tue Aug 09 00:07:04 2011 +0800
+++ b/paraspace/injection.py	Tue Aug 09 11:47:43 2011 +0800
@@ -645,3 +645,37 @@
         dexfile_insert_classdefs_relative(dex_dst, dex_src, classdefs)
     redirect_injected_code(dex_dst, dex_src, classdefs)
     return injected_classdefs
+
+
+## \brief Inject and redirect a _DEX_ClassDef from one linked to another.
+#
+# The _DEX_ClassDef given by inj_classname would be inserted to dst_linked,
+# and redirect all invoking of type, given by redir_classname, to
+# the injected one.
+#
+def inject_redir(src_linked, inj_classname,
+                 dst_linked, redir_classname, decls):
+    from paraspace.dex_deptracker import dex_sort_sorted_arrays
+    from paraspace.dex_deptracker import restore_dependencies
+    
+    inj_classdef = src_linked.find_class_name(inj_classname)
+    injected_classdefs = inject_classdefs(dst_linked, src_linked,
+                                          [inj_classdef])
+    
+    redir_typeid = dst_linked.find_typeid_name(redir_classname)
+    redir_typeidx = dst_linked.get_idx_typeid(redir_typeid)
+    inj_typeid = dst_linked.find_typeid_name(inj_classname)
+    inj_typeidx = dst_linked.get_idx_typeid(inj_typeid)
+    typeidxs_redir = {redir_typeidx: inj_typeidx}
+    
+    methodidxs_redir = \
+        make_methodidxs_redir_map(dst_linked, dst_linked, typeidxs_redir)
+    
+    injected_typeidxs = [dst_linked.get_idx_classdef(classdef)
+                         for classdef in injected_classdefs]
+    dexfile_redirect_types(dst_linked, typeidxs_redir, methodidxs_redir,
+                           excludes=injected_typeidxs)
+    
+    dex_sort_sorted_arrays(dst_linked)
+    restore_dependencies(dst_linked, decls)
+    pass
--- a/paraspace/tests/dex_deptracker_test.py	Tue Aug 09 00:07:04 2011 +0800
+++ b/paraspace/tests/dex_deptracker_test.py	Tue Aug 09 11:47:43 2011 +0800
@@ -59,7 +59,7 @@
     dex.classDatas.items[-1].data_offset = 0
 
     dex.typeIds.items[12].data_idx = 0
-    
+
     update_offset(dex, all_dep_decls)
 
     assert dex.typeLists.items[0].value.data_offset == offset0
@@ -215,8 +215,17 @@
     hello_linked.typeIds.items[0] = last
     hello_linked.typeIds.items[-1] = first
 
+    typeid10 = hello_linked.typeIds.items[10]
+    typeid12 = hello_linked.typeIds.items[12]
+    typeid10.descriptorIdx, typeid12.descriptorIdx = \
+        typeid12.descriptorIdx, typeid10.descriptorIdx
+    
     dex_sort_sorted_arrays(hello_linked)
 
     assert hello_linked.typeIds.items[0] == first
     assert hello_linked.typeIds.items[-1] == last
+    
+    assert typeid10 > typeid12
+    assert hello_linked.typeIds.items[10] == typeid12
+    assert hello_linked.typeIds.items[12] == typeid10
     pass
--- a/paraspace/tests/injection_test.py	Tue Aug 09 00:07:04 2011 +0800
+++ b/paraspace/tests/injection_test.py	Tue Aug 09 11:47:43 2011 +0800
@@ -388,3 +388,96 @@
             pass
         pass
     pass
+
+
+## \brief Test case for error of verifing data map.
+#
+# The output of inject_redir.py is not accepted by dalvik with following
+# error messages.
+# \pre
+#   E/dalvikvm(  302): Unexpected data map entry @ 0x930: expected 1001, \
+#   found 2006
+#   E/dalvikvm(  302): Trouble with item 0 @ offset 0x25c
+#   E/dalvikvm(  302): Cross-item verify of section type 0003 failed
+#   E/dalvikvm(  302): ERROR: Byte swap + verify failed
+#   E/dalvikvm(  302): Optimization failed
+#
+# The data map printed by paraspace.dexfile is
+# \pre
+#        0x0000(kDexTypeHeaderItem) size=1 offset=0x00000000
+#        0x0001(kDexTypeStringIdItem) size=92 offset=0x00000070
+#        0x0002(kDexTypeTypeIdItem) size=31 offset=0x000001e0
+#        0x0003(kDexTypeProtoIdItem) size=18 offset=0x0000025c
+#        0x0004(kDexTypeFieldIdItem) size=7 offset=0x00000334
+#        0x0005(kDexTypeMethodIdItem) size=36 offset=0x0000036c
+#        0x0006(kDexTypeClassDefItem) size=10 offset=0x0000048c
+#        0x1003(kDexTypeAnnotationSetItem) size=7 offset=0x000005cc
+#        0x2001(kDexTypeCodeItem) size=17 offset=0x0000061c
+#        0x2006(kDexTypeAnnotationsDirectoryItem) size=7 offset=0x00000910
+#        0x1001(kDexTypeTypeList) size=12 offset=0x00000980
+#        0x2002(kDexTypeStringDataItem) size=92 offset=0x000009e2
+#        0x2003(kDexTypeDebugInfoItem) size=17 offset=0x00000f05
+#        0x2004(kDexTypeAnnotationItem) size=9 offset=0x00000fc1
+#        0x2005(kDexTypeEncodedArrayItem) size=5 offset=0x00001012
+#        0x2000(kDexTypeClassDataItem) size=10 offset=0x0000102d
+#        0x1000(kDexTypeMapList) size=1 offset=0x000010c0
+#
+# It is possible restore_dependencies() does not following \ref ref
+# object to set offset value on referenced attribute.
+#
+def map_verify_error_test():
+    from paraspace.dex_deptracker import prepare_dep_decls
+    from paraspace.injection import inject_redir
+    
+    _install_dexfile_4_deptracker()
+    
+    all_dep_decls = prepare_dep_decls()
+    
+    srcdir = os.path.dirname(__file__)
+    datapath = os.path.join(srcdir, '..', '..', 'data')
+
+    fake_path = os.path.join(datapath, 'fakefile.dex')
+    hello_path = os.path.join(datapath, 'helloworld.dex')
+    
+    fake_dex = dexfile.DEXFile.open(fake_path)
+    fake_linked = dexfile.DEXFile_linked.build_dependencies(fake_dex,
+                                                            all_dep_decls)
+
+    hello_dex = dexfile.DEXFile.open(hello_path)
+    hello_linked = dexfile.DEXFile_linked.build_dependencies(hello_dex,
+                                                             all_dep_decls)
+
+    inject_redir(fake_linked, 'Lcom/codemud/fakefile/fakefile;',
+                 hello_linked, 'Ljava/io/File;', all_dep_decls)
+
+    for idx, item in enumerate(hello_linked.maps.items.items):
+        if item.type != dexfile._DEX_MapItem.name_to_types['kDexTypeTypeList']:
+            break
+        pass
+    else:
+        assert False
+        pass
+    typelist_start = item.offset
+    next_item = hello_linked.maps.items.items[idx + 1]
+    typelist_stop = next_item.offset
+    
+    for idx, protoid in enumerate(hello_linked.protoIds.items):
+        off = protoid.parametersOff
+        try:
+            assert off >= typelist_start
+            assert off < typelist_stop
+        except:
+            print 'ERROR: protoid idx @', idx, protoid
+            raise
+        pass
+
+    for idx, classdef in enumerate(hello_linked.classDefs.items):
+        off = classdef.interfacesOff
+        try:
+            assert off >= typelist_start
+            assert off < typelist_stop
+        except:
+            print 'ERROR: classdef idx @', idx, classdef
+            raise
+        pass
+    pass