mirror of
https://github.com/revanced/smali.git
synced 2025-05-24 10:32:13 +02:00
Add support for specifying a custom inline method table to use while deodexing
This commit is contained in:
parent
e00d96c438
commit
5967598d01
@ -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();
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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() {
|
||||||
|
@ -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")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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()));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user