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) {
methodAnalyzer = new MethodAnalyzer(encodedMethod, baksmali.deodex);
methodAnalyzer = new MethodAnalyzer(encodedMethod, baksmali.deodex, baksmali.inlineResolver);
methodAnalyzer.analyze();

View File

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

View File

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

View File

@ -593,7 +593,12 @@ public class ClassPath {
private final int classDepth;
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;
@ -601,6 +606,8 @@ public class ClassPath {
public final static int PrimitiveClassDef = 1;
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
@ -629,7 +636,7 @@ public class ClassPath {
isInterface = false;
vtable = superclass.vtable;
virtualMethodLookup = superclass.virtualMethodLookup;
methodLookup = superclass.methodLookup;
instanceFields = superclass.instanceFields;
classDepth = 1; //1 off from java.lang.Object
@ -645,7 +652,7 @@ public class ClassPath {
implementedInterfaces = null;
isInterface = false;
vtable = null;
virtualMethodLookup = null;
methodLookup = null;
instanceFields = null;
classDepth = 0; //TODO: maybe use -1 to indicate not applicable?
@ -659,7 +666,7 @@ public class ClassPath {
isInterface = false;
vtable = superclass.vtable;
virtualMethodLookup = superclass.virtualMethodLookup;
methodLookup = superclass.methodLookup;
instanceFields = superclass.instanceFields;
classDepth = 1; //1 off from java.lang.Object
@ -686,9 +693,23 @@ public class ClassPath {
interfaceTable = loadInterfaceTable(classInfo);
virtualMethods = classInfo.virtualMethods;
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++) {
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);
@ -745,7 +766,28 @@ public class ClassPath {
}
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) {
@ -1141,6 +1183,8 @@ public class ClassPath {
public final boolean isInterface;
public final String superclassType;
public final String[] interfaces;
public final boolean[] staticMethods;
public final String[] directMethods;
public final String[] virtualMethods;
public final String[][] instanceFields;
@ -1162,9 +1206,14 @@ public class ClassPath {
ClassDataItem classDataItem = classDefItem.getClassData();
if (classDataItem != null) {
boolean[][] _staticMethods = new boolean[1][];
directMethods = loadDirectMethods(classDataItem, _staticMethods);
staticMethods = _staticMethods[0];
virtualMethods = loadVirtualMethods(classDataItem);
instanceFields = loadInstanceFields(classDataItem);
} else {
staticMethods = null;
directMethods = null;
virtualMethods = null;
instanceFields = null;
}
@ -1185,6 +1234,26 @@ public class ClassPath {
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) {
EncodedMethod[] encodedMethods = classDataItem.getVirtualMethods();
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);
}
public DeodexUtil(DexFile dexFile, InlineMethodResolver inlineMethodResolver) {
this.dexFile = dexFile;
this.inlineMethodResolver = inlineMethodResolver;
}
public InlineMethod lookupInlineMethod(AnalyzedInstruction instruction) {
return inlineMethodResolver.resolveExecuteInline(instruction);
}
@ -246,7 +251,7 @@ public class DeodexUtil {
return null;
}
public class InlineMethod {
public static class InlineMethod {
public final int methodType;
public final String classType;
public final String methodName;
@ -264,17 +269,17 @@ public class DeodexUtil {
this.returnType = returnType;
}
public MethodIdItem getMethodIdItem() {
public MethodIdItem getMethodIdItem(DeodexUtil deodexUtil) {
if (methodIdItem == null) {
loadMethod();
loadMethod(deodexUtil);
}
return methodIdItem;
}
private void loadMethod() {
private void loadMethod(DeodexUtil deodexUtil) {
ClassPath.ClassDef classDef = ClassPath.getClassDef(classType);
this.methodIdItem = parseAndResolveMethod(classDef, methodName, parameters, returnType);
this.methodIdItem = deodexUtil.parseAndResolveMethod(classDef, methodName, parameters, returnType);
}
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.Direct;
abstract class InlineMethodResolver {
public abstract class InlineMethodResolver {
public static InlineMethodResolver createInlineMethodResolver(DeodexUtil deodexUtil, int odexVersion) {
if (odexVersion == 35) {
return new InlineMethodResolver_version35(deodexUtil);
@ -46,7 +46,7 @@ abstract class InlineMethodResolver {
}
}
private InlineMethodResolver() {
protected InlineMethodResolver() {
}
public abstract DeodexUtil.InlineMethod resolveExecuteInline(AnalyzedInstruction instruction);
@ -57,20 +57,20 @@ abstract class InlineMethodResolver {
public InlineMethodResolver_version35(DeodexUtil deodexUtil) {
inlineMethods = new DeodexUtil.InlineMethod[] {
deodexUtil.new InlineMethod(Static, "Lorg/apache/harmony/dalvik/NativeTestTarget;", "emptyInlineMethod", "", "V"),
deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "charAt", "I", "C"),
deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "compareTo", "Ljava/lang/String;", "I"),
deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "equals", "Ljava/lang/Object;", "Z"),
deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "length", "", "I"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "abs", "I", "I"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "abs", "J", "J"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "abs", "F", "F"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "abs", "D", "D"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "min", "II", "I"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "max", "II", "I"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "sqrt", "D", "D"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "cos", "D", "D"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "sin", "D", "D")
new DeodexUtil.InlineMethod(Static, "Lorg/apache/harmony/dalvik/NativeTestTarget;", "emptyInlineMethod", "", "V"),
new DeodexUtil.InlineMethod(Virtual, "Ljava/lang/String;", "charAt", "I", "C"),
new DeodexUtil.InlineMethod(Virtual, "Ljava/lang/String;", "compareTo", "Ljava/lang/String;", "I"),
new DeodexUtil.InlineMethod(Virtual, "Ljava/lang/String;", "equals", "Ljava/lang/Object;", "Z"),
new DeodexUtil.InlineMethod(Virtual, "Ljava/lang/String;", "length", "", "I"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "abs", "I", "I"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "abs", "J", "J"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "abs", "F", "F"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "abs", "D", "D"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "min", "II", "I"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "max", "II", "I"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "sqrt", "D", "D"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "cos", "D", "D"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "sin", "D", "D")
};
}
@ -102,40 +102,40 @@ abstract class InlineMethodResolver {
//passed to distinguish between them.
//froyo
indexOfIMethod = deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "indexOf", "I", "I");
indexOfIIMethod = deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "indexOf", "II", "I");
indexOfIMethod = new DeodexUtil.InlineMethod(Virtual, "Ljava/lang/String;", "indexOf", "I", "I");
indexOfIIMethod = new DeodexUtil.InlineMethod(Virtual, "Ljava/lang/String;", "indexOf", "II", "I");
//gingerbread
fastIndexOfMethod = deodexUtil.new InlineMethod(Direct, "Ljava/lang/String;", "fastIndexOf", "II", "I");
isEmptyMethod = deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "isEmpty", "", "Z");
fastIndexOfMethod = new DeodexUtil.InlineMethod(Direct, "Ljava/lang/String;", "fastIndexOf", "II", "I");
isEmptyMethod = new DeodexUtil.InlineMethod(Virtual, "Ljava/lang/String;", "isEmpty", "", "Z");
inlineMethods = new DeodexUtil.InlineMethod[] {
deodexUtil.new InlineMethod(Static, "Lorg/apache/harmony/dalvik/NativeTestTarget;", "emptyInlineMethod", "", "V"),
deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "charAt", "I", "C"),
deodexUtil.new 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(Static, "Lorg/apache/harmony/dalvik/NativeTestTarget;", "emptyInlineMethod", "", "V"),
new DeodexUtil.InlineMethod(Virtual, "Ljava/lang/String;", "charAt", "I", "C"),
new DeodexUtil.InlineMethod(Virtual, "Ljava/lang/String;", "compareTo", "Ljava/lang/String;", "I"),
new DeodexUtil.InlineMethod(Virtual, "Ljava/lang/String;", "equals", "Ljava/lang/Object;", "Z"),
//froyo: deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "indexOf", "I", "I"),
//gingerbread: deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "fastIndexOf", "II", "I"),
null,
//froyo: deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "indexOf", "II", "I"),
//gingerbread: deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "isEmpty", "", "Z"),
null,
deodexUtil.new InlineMethod(Virtual, "Ljava/lang/String;", "length", "", "I"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "abs", "I", "I"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "abs", "J", "J"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "abs", "F", "F"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "abs", "D", "D"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "min", "II", "I"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "max", "II", "I"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "sqrt", "D", "D"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "cos", "D", "D"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Math;", "sin", "D", "D"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Float;", "floatToIntBits", "F", "I"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Float;", "floatToRawIntBits", "F", "I"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Float;", "intBitsToFloat", "I", "F"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Double;", "doubleToLongBits", "D", "J"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Double;", "doubleToRawLongBits", "D", "J"),
deodexUtil.new InlineMethod(Static, "Ljava/lang/Double;", "longBitsToDouble", "J", "D")
new DeodexUtil.InlineMethod(Virtual, "Ljava/lang/String;", "length", "", "I"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "abs", "I", "I"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "abs", "J", "J"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "abs", "F", "F"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "abs", "D", "D"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "min", "II", "I"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "max", "II", "I"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "sqrt", "D", "D"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "cos", "D", "D"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Math;", "sin", "D", "D"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Float;", "floatToIntBits", "F", "I"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Float;", "floatToRawIntBits", "F", "I"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Float;", "intBitsToFloat", "I", "F"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Double;", "doubleToLongBits", "D", "J"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Double;", "doubleToRawLongBits", "D", "J"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Double;", "longBitsToDouble", "J", "D")
};
}

View File

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