Add support for specifying a custom inline method table to use while deodexing

This commit is contained in:
Ben Gruver 2011-11-17 00:26:41 -08:00 committed by =
parent e00d96c438
commit 5967598d01
8 changed files with 271 additions and 63 deletions

View File

@ -373,7 +373,7 @@ public class MethodDefinition {
} }
private void addAnalyzedInstructionMethodItems(List<MethodItem> methodItems) { private void addAnalyzedInstructionMethodItems(List<MethodItem> methodItems) {
methodAnalyzer = new MethodAnalyzer(encodedMethod, baksmali.deodex); methodAnalyzer = new MethodAnalyzer(encodedMethod, baksmali.deodex, baksmali.inlineResolver);
methodAnalyzer.analyze(); methodAnalyzer.analyze();

View File

@ -30,8 +30,7 @@ package org.jf.baksmali;
import org.jf.baksmali.Adaptors.ClassDefinition; import org.jf.baksmali.Adaptors.ClassDefinition;
import org.jf.dexlib.ClassDefItem; import org.jf.dexlib.ClassDefItem;
import org.jf.dexlib.Code.Analysis.ClassPath; import org.jf.dexlib.Code.Analysis.*;
import org.jf.dexlib.Code.Analysis.SyntheticAccessorResolver;
import org.jf.dexlib.DexFile; import org.jf.dexlib.DexFile;
import org.jf.util.ClassFileNameHandler; import org.jf.util.ClassFileNameHandler;
import org.jf.util.IndentingWriter; import org.jf.util.IndentingWriter;
@ -52,6 +51,7 @@ public class baksmali {
public static boolean noAccessorComments = false; public static boolean noAccessorComments = false;
public static boolean deodex = false; public static boolean deodex = false;
public static boolean verify = false; public static boolean verify = false;
public static InlineMethodResolver inlineResolver = null;
public static int registerInfo = 0; public static int registerInfo = 0;
public static String bootClassPath; public static String bootClassPath;
@ -62,7 +62,7 @@ public class baksmali {
boolean noParameterRegisters, boolean useLocalsDirective, boolean noParameterRegisters, boolean useLocalsDirective,
boolean useSequentialLabels, boolean outputDebugInfo, boolean addCodeOffsets, boolean useSequentialLabels, boolean outputDebugInfo, boolean addCodeOffsets,
boolean noAccessorComments, int registerInfo, boolean verify, boolean noAccessorComments, int registerInfo, boolean verify,
boolean ignoreErrors) boolean ignoreErrors, String inlineTable)
{ {
baksmali.noParameterRegisters = noParameterRegisters; baksmali.noParameterRegisters = noParameterRegisters;
baksmali.useLocalsDirective = useLocalsDirective; baksmali.useLocalsDirective = useLocalsDirective;
@ -111,6 +111,10 @@ public class baksmali {
ClassPath.InitializeClassPath(classPathDirs, bootClassPathArray, extraBootClassPathArray, ClassPath.InitializeClassPath(classPathDirs, bootClassPathArray, extraBootClassPathArray,
dexFilePath, dexFile, classPathErrorHandler); dexFilePath, dexFile, classPathErrorHandler);
} }
if (inlineTable != null) {
inlineResolver = new CustomInlineMethodResolver(inlineTable);
}
} catch (Exception ex) { } catch (Exception ex) {
System.err.println("\n\nError occured while loading boot class path files. Aborting."); System.err.println("\n\nError occured while loading boot class path files. Aborting.");
ex.printStackTrace(System.err); ex.printStackTrace(System.err);

View File

@ -121,7 +121,7 @@ public class main {
StringBuffer extraBootClassPathEntries = new StringBuffer(); StringBuffer extraBootClassPathEntries = new StringBuffer();
List<String> bootClassPathDirs = new ArrayList<String>(); List<String> bootClassPathDirs = new ArrayList<String>();
bootClassPathDirs.add("."); bootClassPathDirs.add(".");
String inlineTable = null;
String[] remainingArgs = commandLine.getArgs(); String[] remainingArgs = commandLine.getArgs();
@ -237,6 +237,9 @@ public class main {
case 'V': case 'V':
verify = true; verify = true;
break; break;
case 'T':
inlineTable = commandLine.getOptionValue("T");
break;
default: default:
assert false; assert false;
} }
@ -290,7 +293,7 @@ public class main {
baksmali.disassembleDexFile(dexFileFile.getPath(), dexFile, deodex, outputDirectory, baksmali.disassembleDexFile(dexFileFile.getPath(), dexFile, deodex, outputDirectory,
bootClassPathDirsArray, bootClassPath, extraBootClassPathEntries.toString(), bootClassPathDirsArray, bootClassPath, extraBootClassPathEntries.toString(),
noParameterRegisters, useLocalsDirective, useSequentialLabels, outputDebugInfo, addCodeOffsets, noParameterRegisters, useLocalsDirective, useSequentialLabels, outputDebugInfo, addCodeOffsets,
noAccessorComments, registerInfo, verify, ignoreErrors); noAccessorComments, registerInfo, verify, ignoreErrors, inlineTable);
} }
if ((doDump || write) && !dexFile.isOdex()) { if ((doDump || write) && !dexFile.isOdex()) {
@ -443,6 +446,7 @@ public class main {
" behavior is to stop disassembling and exit once an error is encountered") " behavior is to stop disassembling and exit once an error is encountered")
.create("I"); .create("I");
Option noDisassemblyOption = OptionBuilder.withLongOpt("no-disassembly") Option noDisassemblyOption = OptionBuilder.withLongOpt("no-disassembly")
.withDescription("suppresses the output of the disassembly") .withDescription("suppresses the output of the disassembly")
.create("N"); .create("N");
@ -466,6 +470,12 @@ public class main {
.withDescription("perform bytecode verification") .withDescription("perform bytecode verification")
.create("V"); .create("V");
Option inlineTableOption = OptionBuilder.withLongOpt("inline-table")
.withDescription("specify a file containing a custom inline method table to use for deodexing")
.hasArg()
.withArgName("FILE")
.create("T");
basicOptions.addOption(versionOption); basicOptions.addOption(versionOption);
basicOptions.addOption(helpOption); basicOptions.addOption(helpOption);
basicOptions.addOption(outputDirOption); basicOptions.addOption(outputDirOption);
@ -488,7 +498,7 @@ public class main {
debugOptions.addOption(sortOption); debugOptions.addOption(sortOption);
debugOptions.addOption(fixSignedRegisterOption); debugOptions.addOption(fixSignedRegisterOption);
debugOptions.addOption(verifyDexOption); debugOptions.addOption(verifyDexOption);
debugOptions.addOption(inlineTableOption);
for (Object option: basicOptions.getOptions()) { for (Object option: basicOptions.getOptions()) {
options.addOption((Option)option); options.addOption((Option)option);

View File

@ -593,7 +593,12 @@ public class ClassPath {
private final int classDepth; private final int classDepth;
private final String[] vtable; private final String[] vtable;
private final HashMap<String, Integer> virtualMethodLookup;
//this maps a method name of the form method(III)Ljava/lang/String; to an integer
//If the value is non-negative, it is a vtable index
//If it is -1, it is a non-static direct method,
//If it is -2, it is a static method
private final HashMap<String, Integer> methodLookup;
private final SparseArray<FieldDef> instanceFields; private final SparseArray<FieldDef> instanceFields;
@ -601,6 +606,8 @@ public class ClassPath {
public final static int PrimitiveClassDef = 1; public final static int PrimitiveClassDef = 1;
public final static int UnresolvedClassDef = 2; public final static int UnresolvedClassDef = 2;
private final static int DirectMethod = -1;
private final static int StaticMethod = -2;
/** /**
* The following fields are used only during the initial loading of classes, and are set to null afterwards * The following fields are used only during the initial loading of classes, and are set to null afterwards
@ -629,7 +636,7 @@ public class ClassPath {
isInterface = false; isInterface = false;
vtable = superclass.vtable; vtable = superclass.vtable;
virtualMethodLookup = superclass.virtualMethodLookup; methodLookup = superclass.methodLookup;
instanceFields = superclass.instanceFields; instanceFields = superclass.instanceFields;
classDepth = 1; //1 off from java.lang.Object classDepth = 1; //1 off from java.lang.Object
@ -645,7 +652,7 @@ public class ClassPath {
implementedInterfaces = null; implementedInterfaces = null;
isInterface = false; isInterface = false;
vtable = null; vtable = null;
virtualMethodLookup = null; methodLookup = null;
instanceFields = null; instanceFields = null;
classDepth = 0; //TODO: maybe use -1 to indicate not applicable? classDepth = 0; //TODO: maybe use -1 to indicate not applicable?
@ -659,7 +666,7 @@ public class ClassPath {
isInterface = false; isInterface = false;
vtable = superclass.vtable; vtable = superclass.vtable;
virtualMethodLookup = superclass.virtualMethodLookup; methodLookup = superclass.methodLookup;
instanceFields = superclass.instanceFields; instanceFields = superclass.instanceFields;
classDepth = 1; //1 off from java.lang.Object classDepth = 1; //1 off from java.lang.Object
@ -686,9 +693,23 @@ public class ClassPath {
interfaceTable = loadInterfaceTable(classInfo); interfaceTable = loadInterfaceTable(classInfo);
virtualMethods = classInfo.virtualMethods; virtualMethods = classInfo.virtualMethods;
vtable = loadVtable(classInfo); vtable = loadVtable(classInfo);
virtualMethodLookup = new HashMap<String, Integer>((int)Math.ceil(vtable.length / .7f), .75f);
int directMethodCount = 0;
if (classInfo.directMethods != null) {
directMethodCount = classInfo.directMethods.length;
}
methodLookup = new HashMap<String, Integer>((int)Math.ceil(((vtable.length + directMethodCount)/ .7f)), .75f);
for (int i=0; i<vtable.length; i++) { for (int i=0; i<vtable.length; i++) {
virtualMethodLookup.put(vtable[i], i); methodLookup.put(vtable[i], i);
}
if (directMethodCount > 0) {
for (int i=0; i<classInfo.directMethods.length; i++) {
if (classInfo.staticMethods[i]) {
methodLookup.put(classInfo.directMethods[i], StaticMethod);
} else {
methodLookup.put(classInfo.directMethods[i], DirectMethod);
}
}
} }
instanceFields = loadFields(classInfo); instanceFields = loadFields(classInfo);
@ -745,7 +766,28 @@ public class ClassPath {
} }
public boolean hasVirtualMethod(String method) { public boolean hasVirtualMethod(String method) {
return virtualMethodLookup.containsKey(method); Integer val = methodLookup.get(method);
if (val == null || val < 0) {
return false;
}
return true;
}
public int getMethodType(String method) {
Integer val = methodLookup.get(method);
if (val == null) {
return -1;
}
if (val >= 0) {
return DeodexUtil.Virtual;
}
if (val == DirectMethod) {
return DeodexUtil.Direct;
}
if (val == StaticMethod) {
return DeodexUtil.Static;
}
throw new RuntimeException("Unexpected method type");
} }
public FieldDef getInstanceField(int fieldOffset) { public FieldDef getInstanceField(int fieldOffset) {
@ -1141,6 +1183,8 @@ public class ClassPath {
public final boolean isInterface; public final boolean isInterface;
public final String superclassType; public final String superclassType;
public final String[] interfaces; public final String[] interfaces;
public final boolean[] staticMethods;
public final String[] directMethods;
public final String[] virtualMethods; public final String[] virtualMethods;
public final String[][] instanceFields; public final String[][] instanceFields;
@ -1162,9 +1206,14 @@ public class ClassPath {
ClassDataItem classDataItem = classDefItem.getClassData(); ClassDataItem classDataItem = classDefItem.getClassData();
if (classDataItem != null) { if (classDataItem != null) {
boolean[][] _staticMethods = new boolean[1][];
directMethods = loadDirectMethods(classDataItem, _staticMethods);
staticMethods = _staticMethods[0];
virtualMethods = loadVirtualMethods(classDataItem); virtualMethods = loadVirtualMethods(classDataItem);
instanceFields = loadInstanceFields(classDataItem); instanceFields = loadInstanceFields(classDataItem);
} else { } else {
staticMethods = null;
directMethods = null;
virtualMethods = null; virtualMethods = null;
instanceFields = null; instanceFields = null;
} }
@ -1185,6 +1234,26 @@ public class ClassPath {
return null; return null;
} }
private String[] loadDirectMethods(ClassDataItem classDataItem, boolean[][] _staticMethods) {
EncodedMethod[] encodedMethods = classDataItem.getDirectMethods();
if (encodedMethods != null && encodedMethods.length > 0) {
boolean[] staticMethods = new boolean[encodedMethods.length];
String[] directMethods = new String[encodedMethods.length];
for (int i=0; i<encodedMethods.length; i++) {
EncodedMethod encodedMethod = encodedMethods[i];
if ((encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) != 0) {
staticMethods[i] = true;
}
directMethods[i] = encodedMethods[i].method.getVirtualMethodString();
}
_staticMethods[0] = staticMethods;
return directMethods;
}
return null;
}
private String[] loadVirtualMethods(ClassDataItem classDataItem) { private String[] loadVirtualMethods(ClassDataItem classDataItem) {
EncodedMethod[] encodedMethods = classDataItem.getVirtualMethods(); EncodedMethod[] encodedMethods = classDataItem.getVirtualMethods();
if (encodedMethods != null && encodedMethods.length > 0) { if (encodedMethods != null && encodedMethods.length > 0) {

View File

@ -0,0 +1,115 @@
/*
* Copyright 2011, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib.Code.Analysis;
import org.jf.dexlib.Code.OdexedInvokeInline;
import org.jf.dexlib.Code.OdexedInvokeVirtual;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CustomInlineMethodResolver extends InlineMethodResolver {
private DeodexUtil.InlineMethod[] inlineMethods;
public CustomInlineMethodResolver(String inlineTable) {
FileReader fr = null;
try {
fr = new FileReader(inlineTable);
} catch (FileNotFoundException ex) {
throw new RuntimeException("Could not find inline table file: " + inlineTable);
}
List<String> lines = new ArrayList<String>();
BufferedReader br = new BufferedReader(fr);
try {
String line = br.readLine();
while (line != null) {
if (line.length() > 0) {
lines.add(line);
}
line = br.readLine();
}
} catch (IOException ex) {
throw new RuntimeException("Error while reading file: " + inlineTable, ex);
}
inlineMethods = new DeodexUtil.InlineMethod[lines.size()];
for (int i=0; i<inlineMethods.length; i++) {
inlineMethods[i] = parseAndResolveInlineMethod(lines.get(i));
}
}
@Override
public DeodexUtil.InlineMethod resolveExecuteInline(AnalyzedInstruction analyzedInstruction) {
assert analyzedInstruction.instruction instanceof OdexedInvokeInline;
OdexedInvokeInline instruction = (OdexedInvokeInline)analyzedInstruction.instruction;
int methodIndex = instruction.getInlineIndex();
if (methodIndex < 0 || methodIndex >= inlineMethods.length) {
throw new RuntimeException("Invalid method index: " + methodIndex);
}
return inlineMethods[methodIndex];
}
private static final Pattern longMethodPattern = Pattern.compile("(L[^;]+;)->([^(]+)\\(([^)]*)\\)(.+)");
private DeodexUtil.InlineMethod parseAndResolveInlineMethod(String inlineMethod) {
Matcher m = longMethodPattern.matcher(inlineMethod);
if (!m.matches()) {
assert false;
throw new RuntimeException("Invalid method descriptor: " + inlineMethod);
}
String className = m.group(1);
String methodName = m.group(2);
String methodParams = m.group(3);
String methodRet = m.group(4);
ClassPath.ClassDef classDef = ClassPath.getClassDef(className, false);
int methodType = classDef.getMethodType(String.format("%s(%s)%s", methodName, methodParams, methodRet));
if (methodType == -1) {
throw new RuntimeException("Cannot resolve inline method: " + inlineMethod);
}
return new DeodexUtil.InlineMethod(methodType, className, methodName, methodParams, methodRet);
}
}

View File

@ -55,6 +55,11 @@ public class DeodexUtil {
inlineMethodResolver = InlineMethodResolver.createInlineMethodResolver(this, odexHeader.version); inlineMethodResolver = InlineMethodResolver.createInlineMethodResolver(this, odexHeader.version);
} }
public DeodexUtil(DexFile dexFile, InlineMethodResolver inlineMethodResolver) {
this.dexFile = dexFile;
this.inlineMethodResolver = inlineMethodResolver;
}
public InlineMethod lookupInlineMethod(AnalyzedInstruction instruction) { public InlineMethod lookupInlineMethod(AnalyzedInstruction instruction) {
return inlineMethodResolver.resolveExecuteInline(instruction); return inlineMethodResolver.resolveExecuteInline(instruction);
} }
@ -246,7 +251,7 @@ public class DeodexUtil {
return null; return null;
} }
public class InlineMethod { public static class InlineMethod {
public final int methodType; public final int methodType;
public final String classType; public final String classType;
public final String methodName; public final String methodName;
@ -264,17 +269,17 @@ public class DeodexUtil {
this.returnType = returnType; this.returnType = returnType;
} }
public MethodIdItem getMethodIdItem() { public MethodIdItem getMethodIdItem(DeodexUtil deodexUtil) {
if (methodIdItem == null) { if (methodIdItem == null) {
loadMethod(); loadMethod(deodexUtil);
} }
return methodIdItem; return methodIdItem;
} }
private void loadMethod() { private void loadMethod(DeodexUtil deodexUtil) {
ClassPath.ClassDef classDef = ClassPath.getClassDef(classType); ClassPath.ClassDef classDef = ClassPath.getClassDef(classType);
this.methodIdItem = parseAndResolveMethod(classDef, methodName, parameters, returnType); this.methodIdItem = deodexUtil.parseAndResolveMethod(classDef, methodName, parameters, returnType);
} }
public String getMethodString() { public String getMethodString() {

View File

@ -35,7 +35,7 @@ import static org.jf.dexlib.Code.Analysis.DeodexUtil.Static;
import static org.jf.dexlib.Code.Analysis.DeodexUtil.Virtual; import static org.jf.dexlib.Code.Analysis.DeodexUtil.Virtual;
import static org.jf.dexlib.Code.Analysis.DeodexUtil.Direct; import static org.jf.dexlib.Code.Analysis.DeodexUtil.Direct;
abstract class InlineMethodResolver { public abstract class InlineMethodResolver {
public static InlineMethodResolver createInlineMethodResolver(DeodexUtil deodexUtil, int odexVersion) { public static InlineMethodResolver createInlineMethodResolver(DeodexUtil deodexUtil, int odexVersion) {
if (odexVersion == 35) { if (odexVersion == 35) {
return new InlineMethodResolver_version35(deodexUtil); return new InlineMethodResolver_version35(deodexUtil);
@ -46,7 +46,7 @@ abstract class InlineMethodResolver {
} }
} }
private InlineMethodResolver() { protected InlineMethodResolver() {
} }
public abstract DeodexUtil.InlineMethod resolveExecuteInline(AnalyzedInstruction instruction); public abstract DeodexUtil.InlineMethod resolveExecuteInline(AnalyzedInstruction instruction);
@ -57,20 +57,20 @@ abstract class InlineMethodResolver {
public InlineMethodResolver_version35(DeodexUtil deodexUtil) { public InlineMethodResolver_version35(DeodexUtil deodexUtil) {
inlineMethods = new DeodexUtil.InlineMethod[] { inlineMethods = new DeodexUtil.InlineMethod[] {
deodexUtil.new InlineMethod(Static, "Lorg/apache/harmony/dalvik/NativeTestTarget;", "emptyInlineMethod", "", "V"), new DeodexUtil.InlineMethod(Static, "Lorg/apache/harmony/dalvik/NativeTestTarget;", "emptyInlineMethod", "", "V"),
deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "charAt", "I", "C"), new DeodexUtil.InlineMethod(Virtual, "Ljava/lang/String;", "charAt", "I", "C"),
deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "compareTo", "Ljava/lang/String;", "I"), new DeodexUtil.InlineMethod(Virtual, "Ljava/lang/String;", "compareTo", "Ljava/lang/String;", "I"),
deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "equals", "Ljava/lang/Object;", "Z"), new DeodexUtil.InlineMethod(Virtual, "Ljava/lang/String;", "equals", "Ljava/lang/Object;", "Z"),
deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "length", "", "I"), new DeodexUtil.InlineMethod(Virtual, "Ljava/lang/String;", "length", "", "I"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "abs", "I", "I"), new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "abs", "I", "I"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "abs", "J", "J"), new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "abs", "J", "J"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "abs", "F", "F"), new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "abs", "F", "F"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "abs", "D", "D"), new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "abs", "D", "D"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "min", "II", "I"), new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "min", "II", "I"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "max", "II", "I"), new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "max", "II", "I"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "sqrt", "D", "D"), new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "sqrt", "D", "D"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "cos", "D", "D"), new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "cos", "D", "D"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "sin", "D", "D") new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "sin", "D", "D")
}; };
} }
@ -102,40 +102,40 @@ abstract class InlineMethodResolver {
//passed to distinguish between them. //passed to distinguish between them.
//froyo //froyo
indexOfIMethod = deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "indexOf", "I", "I"); indexOfIMethod = new DeodexUtil.InlineMethod(Virtual, "Ljava/lang/String;", "indexOf", "I", "I");
indexOfIIMethod = deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "indexOf", "II", "I"); indexOfIIMethod = new DeodexUtil.InlineMethod(Virtual, "Ljava/lang/String;", "indexOf", "II", "I");
//gingerbread //gingerbread
fastIndexOfMethod = deodexUtil.new InlineMethod(Direct, "Ljava/lang/String;", "fastIndexOf", "II", "I"); fastIndexOfMethod = new DeodexUtil.InlineMethod(Direct, "Ljava/lang/String;", "fastIndexOf", "II", "I");
isEmptyMethod = deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "isEmpty", "", "Z"); isEmptyMethod = new DeodexUtil.InlineMethod(Virtual, "Ljava/lang/String;", "isEmpty", "", "Z");
inlineMethods = new DeodexUtil.InlineMethod[] { inlineMethods = new DeodexUtil.InlineMethod[] {
deodexUtil.new InlineMethod(Static, "Lorg/apache/harmony/dalvik/NativeTestTarget;", "emptyInlineMethod", "", "V"), new DeodexUtil.InlineMethod(Static, "Lorg/apache/harmony/dalvik/NativeTestTarget;", "emptyInlineMethod", "", "V"),
deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "charAt", "I", "C"), new DeodexUtil.InlineMethod(Virtual, "Ljava/lang/String;", "charAt", "I", "C"),
deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "compareTo", "Ljava/lang/String;", "I"), new DeodexUtil.InlineMethod(Virtual, "Ljava/lang/String;", "compareTo", "Ljava/lang/String;", "I"),
deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "equals", "Ljava/lang/Object;", "Z"), new DeodexUtil.InlineMethod(Virtual, "Ljava/lang/String;", "equals", "Ljava/lang/Object;", "Z"),
//froyo: deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "indexOf", "I", "I"), //froyo: deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "indexOf", "I", "I"),
//gingerbread: deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "fastIndexOf", "II", "I"), //gingerbread: deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "fastIndexOf", "II", "I"),
null, null,
//froyo: deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "indexOf", "II", "I"), //froyo: deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "indexOf", "II", "I"),
//gingerbread: deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "isEmpty", "", "Z"), //gingerbread: deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "isEmpty", "", "Z"),
null, null,
deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "length", "", "I"), new DeodexUtil.InlineMethod(Virtual, "Ljava/lang/String;", "length", "", "I"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "abs", "I", "I"), new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "abs", "I", "I"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "abs", "J", "J"), new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "abs", "J", "J"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "abs", "F", "F"), new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "abs", "F", "F"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "abs", "D", "D"), new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "abs", "D", "D"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "min", "II", "I"), new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "min", "II", "I"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "max", "II", "I"), new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "max", "II", "I"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "sqrt", "D", "D"), new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "sqrt", "D", "D"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "cos", "D", "D"), new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "cos", "D", "D"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "sin", "D", "D"), new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "sin", "D", "D"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Float;", "floatToIntBits", "F", "I"), new DeodexUtil.InlineMethod(Static, "Ljava/lang/Float;", "floatToIntBits", "F", "I"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Float;", "floatToRawIntBits", "F", "I"), new DeodexUtil.InlineMethod(Static, "Ljava/lang/Float;", "floatToRawIntBits", "F", "I"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Float;", "intBitsToFloat", "I", "F"), new DeodexUtil.InlineMethod(Static, "Ljava/lang/Float;", "intBitsToFloat", "I", "F"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Double;", "doubleToLongBits", "D", "J"), new DeodexUtil.InlineMethod(Static, "Ljava/lang/Double;", "doubleToLongBits", "D", "J"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Double;", "doubleToRawLongBits", "D", "J"), new DeodexUtil.InlineMethod(Static, "Ljava/lang/Double;", "doubleToRawLongBits", "D", "J"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Double;", "longBitsToDouble", "J", "D") new DeodexUtil.InlineMethod(Static, "Ljava/lang/Double;", "longBitsToDouble", "J", "D")
}; };
} }

View File

@ -71,7 +71,8 @@ public class MethodAnalyzer {
//instruction, etc. //instruction, etc.
private AnalyzedInstruction startOfMethod; private AnalyzedInstruction startOfMethod;
public MethodAnalyzer(ClassDataItem.EncodedMethod encodedMethod, boolean deodex) { public MethodAnalyzer(ClassDataItem.EncodedMethod encodedMethod, boolean deodex,
InlineMethodResolver inlineResolver) {
if (encodedMethod == null) { if (encodedMethod == null) {
throw new IllegalArgumentException("encodedMethod cannot be null"); throw new IllegalArgumentException("encodedMethod cannot be null");
} }
@ -81,7 +82,11 @@ public class MethodAnalyzer {
this.encodedMethod = encodedMethod; this.encodedMethod = encodedMethod;
if (deodex) { if (deodex) {
if (inlineResolver != null) {
this.deodexUtil = new DeodexUtil(encodedMethod.method.getDexFile(), inlineResolver);
} else {
this.deodexUtil = new DeodexUtil(encodedMethod.method.getDexFile()); this.deodexUtil = new DeodexUtil(encodedMethod.method.getDexFile());
}
} else { } else {
this.deodexUtil = null; this.deodexUtil = null;
} }
@ -3386,7 +3391,7 @@ public class MethodAnalyzer {
Instruction35mi instruction = (Instruction35mi)analyzedInstruction.instruction; Instruction35mi instruction = (Instruction35mi)analyzedInstruction.instruction;
DeodexUtil.InlineMethod inlineMethod = deodexUtil.lookupInlineMethod(analyzedInstruction); DeodexUtil.InlineMethod inlineMethod = deodexUtil.lookupInlineMethod(analyzedInstruction);
MethodIdItem inlineMethodIdItem = inlineMethod.getMethodIdItem(); MethodIdItem inlineMethodIdItem = inlineMethod.getMethodIdItem(deodexUtil);
if (inlineMethodIdItem == null) { if (inlineMethodIdItem == null) {
throw new ValidationException(String.format("Cannot load inline method with index %d", throw new ValidationException(String.format("Cannot load inline method with index %d",
instruction.getInlineIndex())); instruction.getInlineIndex()));
@ -3424,7 +3429,7 @@ public class MethodAnalyzer {
Instruction3rmi instruction = (Instruction3rmi)analyzedInstruction.instruction; Instruction3rmi instruction = (Instruction3rmi)analyzedInstruction.instruction;
DeodexUtil.InlineMethod inlineMethod = deodexUtil.lookupInlineMethod(analyzedInstruction); DeodexUtil.InlineMethod inlineMethod = deodexUtil.lookupInlineMethod(analyzedInstruction);
MethodIdItem inlineMethodIdItem = inlineMethod.getMethodIdItem(); MethodIdItem inlineMethodIdItem = inlineMethod.getMethodIdItem(deodexUtil);
if (inlineMethodIdItem == null) { if (inlineMethodIdItem == null) {
throw new ValidationException(String.format("Cannot load inline method with index %d", throw new ValidationException(String.format("Cannot load inline method with index %d",
instruction.getInlineIndex())); instruction.getInlineIndex()));