Updating JesusFreke smali/baksmali to v1.4.1 (API17 changes)

This commit is contained in:
Connor Tumbleson 2012-11-19 07:24:16 -06:00
parent 6b31aeb7c4
commit 9e7ccc5112
28 changed files with 1142 additions and 119 deletions

View File

@ -34,6 +34,7 @@ import org.jf.util.IndentingWriter;
import org.jf.dexlib.*; import org.jf.dexlib.*;
import org.jf.dexlib.Code.Analysis.ValidationException; import org.jf.dexlib.Code.Analysis.ValidationException;
import org.jf.dexlib.Code.Format.Instruction21c; import org.jf.dexlib.Code.Format.Instruction21c;
import org.jf.dexlib.Code.Format.Instruction41c;
import org.jf.dexlib.Code.Instruction; import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.EncodedValue.EncodedValue; import org.jf.dexlib.EncodedValue.EncodedValue;
import org.jf.dexlib.Util.AccessFlags; import org.jf.dexlib.Util.AccessFlags;
@ -86,6 +87,18 @@ public class ClassDefinition {
fieldsSetInStaticConstructor.put(fieldIdItem.getIndex(), fieldIdItem); fieldsSetInStaticConstructor.put(fieldIdItem.getIndex(), fieldIdItem);
break; break;
} }
case SPUT_JUMBO:
case SPUT_BOOLEAN_JUMBO:
case SPUT_BYTE_JUMBO:
case SPUT_CHAR_JUMBO:
case SPUT_OBJECT_JUMBO:
case SPUT_SHORT_JUMBO:
case SPUT_WIDE_JUMBO: {
Instruction41c ins = (Instruction41c)instruction;
FieldIdItem fieldIdItem = (FieldIdItem)ins.getReferencedItem();
fieldsSetInStaticConstructor.put(fieldIdItem.getIndex(), fieldIdItem);
break;
}
} }
} }
} }

View File

@ -106,6 +106,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
return true; return true;
case Format21c: case Format21c:
case Format31c: case Format31c:
case Format41c:
writeOpcode(writer); writeOpcode(writer);
writer.write(' '); writer.write(' ');
writeFirstRegister(writer); writeFirstRegister(writer);
@ -141,6 +142,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
writeLiteral(writer); writeLiteral(writer);
return true; return true;
case Format22c: case Format22c:
case Format52c:
writeOpcode(writer); writeOpcode(writer);
writer.write(' '); writer.write(' ');
writeFirstRegister(writer); writeFirstRegister(writer);
@ -206,6 +208,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
writeVtableIndex(writer); writeVtableIndex(writer);
return true; return true;
case Format3rc: case Format3rc:
case Format5rc:
writeOpcode(writer); writeOpcode(writer);
writer.write(' '); writer.write(' ');
writeInvokeRangeRegisters(writer); writeInvokeRangeRegisters(writer);

View File

@ -49,14 +49,14 @@ public class SyntheticAccessCommentMethodItem extends MethodItem {
public boolean writeTo(IndentingWriter writer) throws IOException { public boolean writeTo(IndentingWriter writer) throws IOException {
writer.write('#'); writer.write('#');
if (accessedMember.getAccessedMemberType() == SyntheticAccessorResolver.METHOD) { if (accessedMember.accessedMemberType == SyntheticAccessorResolver.METHOD) {
writer.write("calls: "); writer.write("calls: ");
} else if (accessedMember.getAccessedMemberType() == SyntheticAccessorResolver.GETTER) { } else if (accessedMember.accessedMemberType == SyntheticAccessorResolver.GETTER) {
writer.write("getter for: "); writer.write("getter for: ");
} else { } else {
writer.write("setter for: "); writer.write("setter for: ");
} }
ReferenceFormatter.writeReference(writer, accessedMember.getAccessedMember()); ReferenceFormatter.writeReference(writer, accessedMember.accessedMember);
return true; return true;
} }
} }

View File

@ -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, String inlineTable) boolean ignoreErrors, String inlineTable, boolean checkPackagePrivateAccess)
{ {
baksmali.noParameterRegisters = noParameterRegisters; baksmali.noParameterRegisters = noParameterRegisters;
baksmali.useLocalsDirective = useLocalsDirective; baksmali.useLocalsDirective = useLocalsDirective;
@ -91,14 +91,15 @@ public class baksmali {
if (extraBootClassPathArray == null && isExtJar(dexFilePath)) { if (extraBootClassPathArray == null && isExtJar(dexFilePath)) {
extraBootClassPathArray = new String[] {"framework.jar"}; extraBootClassPathArray = new String[] {"framework.jar"};
} }
ClassPath.InitializeClassPathFromOdex(classPathDirs, extraBootClassPathArray, dexFilePath, dexFile); ClassPath.InitializeClassPathFromOdex(classPathDirs, extraBootClassPathArray, dexFilePath, dexFile,
checkPackagePrivateAccess);
} else { } else {
String[] bootClassPathArray = null; String[] bootClassPathArray = null;
if (bootClassPath != null) { if (bootClassPath != null) {
bootClassPathArray = bootClassPath.split(":"); bootClassPathArray = bootClassPath.split(":");
} }
ClassPath.InitializeClassPath(classPathDirs, bootClassPathArray, extraBootClassPathArray, ClassPath.InitializeClassPath(classPathDirs, bootClassPathArray, extraBootClassPathArray,
dexFilePath, dexFile); dexFilePath, dexFile, checkPackagePrivateAccess);
} }
if (inlineTable != null) { if (inlineTable != null) {

View File

@ -114,6 +114,7 @@ public class main {
boolean deodex = false; boolean deodex = false;
boolean verify = false; boolean verify = false;
boolean ignoreErrors = false; boolean ignoreErrors = false;
boolean checkPackagePrivateAccess = false;
int apiLevel = 14; int apiLevel = 14;
@ -128,6 +129,7 @@ public class main {
List<String> bootClassPathDirs = new ArrayList<String>(); List<String> bootClassPathDirs = new ArrayList<String>();
bootClassPathDirs.add("."); bootClassPathDirs.add(".");
String inlineTable = null; String inlineTable = null;
boolean jumboInstructions = false;
String[] remainingArgs = commandLine.getArgs(); String[] remainingArgs = commandLine.getArgs();
@ -219,6 +221,9 @@ public class main {
break; break;
case 'a': case 'a':
apiLevel = Integer.parseInt(commandLine.getOptionValue("a")); apiLevel = Integer.parseInt(commandLine.getOptionValue("a"));
if (apiLevel >= 17) {
checkPackagePrivateAccess = true;
}
break; break;
case 'N': case 'N':
disassemble = false; disassemble = false;
@ -230,6 +235,9 @@ public class main {
case 'I': case 'I':
ignoreErrors = true; ignoreErrors = true;
break; break;
case 'J':
jumboInstructions = true;
break;
case 'W': case 'W':
write = true; write = true;
outputDexFileName = commandLine.getOptionValue("W"); outputDexFileName = commandLine.getOptionValue("W");
@ -246,6 +254,9 @@ public class main {
case 'T': case 'T':
inlineTable = commandLine.getOptionValue("T"); inlineTable = commandLine.getOptionValue("T");
break; break;
case 'K':
checkPackagePrivateAccess = true;
break;
default: default:
assert false; assert false;
} }
@ -265,7 +276,7 @@ public class main {
System.exit(1); System.exit(1);
} }
Opcode.updateMapsForApiLevel(apiLevel); Opcode.updateMapsForApiLevel(apiLevel, jumboInstructions);
//Read in and parse the dex file //Read in and parse the dex file
DexFile dexFile = new DexFile(dexFileFile, !fixRegisters, false); DexFile dexFile = new DexFile(dexFileFile, !fixRegisters, false);
@ -299,7 +310,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, inlineTable); noAccessorComments, registerInfo, verify, ignoreErrors, inlineTable, checkPackagePrivateAccess);
} }
if ((doDump || write) && !dexFile.isOdex()) { if ((doDump || write) && !dexFile.isOdex()) {
@ -448,6 +459,12 @@ 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 jumboInstructionsOption = OptionBuilder.withLongOpt("jumbo-instructions")
.withDescription("adds support for the jumbo opcodes that were temporarily available around the" +
" ics timeframe. Note that support for these opcodes was removed from newer version of" +
" dalvik. You shouldn't use this option unless you know the dex file contains these jumbo" +
" opcodes.")
.create("J");
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")
@ -495,6 +512,7 @@ public class main {
debugOptions.addOption(dumpOption); debugOptions.addOption(dumpOption);
debugOptions.addOption(ignoreErrorsOption); debugOptions.addOption(ignoreErrorsOption);
debugOptions.addOption(jumboInstructionsOption);
debugOptions.addOption(noDisassemblyOption); debugOptions.addOption(noDisassemblyOption);
debugOptions.addOption(writeDexOption); debugOptions.addOption(writeDexOption);
debugOptions.addOption(sortOption); debugOptions.addOption(sortOption);

View File

@ -1 +1 @@
application.version=1.4.0 application.version=1.4.1

View File

@ -431,10 +431,9 @@ public class ClassDataItem extends Item<ClassDataItem> {
* Returns the parent type for a non-empty ClassDataItem, or null for an empty one (which could be referenced by * Returns the parent type for a non-empty ClassDataItem, or null for an empty one (which could be referenced by
* multiple ClassDefItem parents) * multiple ClassDefItem parents)
* *
* Specifically, the AnnotationDirectoryItem may be referenced by multiple classes if it has only class annotations, * Only an empty ClassDataItem may have multiple parents.
* but not field/method/parameter annotations.
* *
* @return The parent type for this AnnotationDirectoryItem, or null if it may have multiple parents * @return The parent type for this ClassDefItem, or null if it may have multiple parents
*/ */
@Nullable @Nullable
public TypeIdItem getParentType() { public TypeIdItem getParentType() {

View File

@ -48,6 +48,13 @@ public class ClassPath {
private static ClassPath theClassPath = null; private static ClassPath theClassPath = null;
/**
* The current version of dalvik in master(AOSP) has a slight change to the way the
* virtual tables are computed. This should be set to true to use the new logic.
* TODO: set this based on api level, once it's present in a released version of Android
*/
private boolean checkPackagePrivateAccess;
private final HashMap<String, ClassDef> classDefs; private final HashMap<String, ClassDef> classDefs;
protected ClassDef javaLangObjectClassDef; //cached ClassDef for Ljava/lang/Object; protected ClassDef javaLangObjectClassDef; //cached ClassDef for Ljava/lang/Object;
@ -65,7 +72,8 @@ public class ClassPath {
* @param dexFile The DexFile to load - it must represents an odex file * @param dexFile The DexFile to load - it must represents an odex file
*/ */
public static void InitializeClassPathFromOdex(String[] classPathDirs, String[] extraBootClassPathEntries, public static void InitializeClassPathFromOdex(String[] classPathDirs, String[] extraBootClassPathEntries,
String dexFilePath, DexFile dexFile) { String dexFilePath, DexFile dexFile,
boolean checkPackagePrivateAccess) {
if (!dexFile.isOdex()) { if (!dexFile.isOdex()) {
throw new ExceptionWithContext("Cannot use InitialiazeClassPathFromOdex with a non-odex DexFile"); throw new ExceptionWithContext("Cannot use InitialiazeClassPathFromOdex with a non-odex DexFile");
} }
@ -102,7 +110,8 @@ public class ClassPath {
} }
theClassPath = new ClassPath(); theClassPath = new ClassPath();
theClassPath.initClassPath(classPathDirs, bootClassPath, extraBootClassPathEntries, dexFilePath, dexFile); theClassPath.initClassPath(classPathDirs, bootClassPath, extraBootClassPathEntries, dexFilePath, dexFile,
checkPackagePrivateAccess);
} }
/** /**
@ -111,17 +120,18 @@ public class ClassPath {
* @param bootClassPath A list of the boot class path entries to search for and load * @param bootClassPath A list of the boot class path entries to search for and load
* @param dexFilePath The path of the dex file (used for error reporting purposes only) * @param dexFilePath The path of the dex file (used for error reporting purposes only)
* @param dexFile the DexFile to load * @param dexFile the DexFile to load
* @param errorHandler a ClassPathErrorHandler object to receive and handle any errors that occur while loading
* classes * classes
*/ */
public static void InitializeClassPath(String[] classPathDirs, String[] bootClassPath, public static void InitializeClassPath(String[] classPathDirs, String[] bootClassPath,
String[] extraBootClassPathEntries, String dexFilePath, DexFile dexFile) { String[] extraBootClassPathEntries, String dexFilePath, DexFile dexFile,
boolean checkPackagePrivateAccess) {
if (theClassPath != null) { if (theClassPath != null) {
throw new ExceptionWithContext("Cannot initialize ClassPath multiple times"); throw new ExceptionWithContext("Cannot initialize ClassPath multiple times");
} }
theClassPath = new ClassPath(); theClassPath = new ClassPath();
theClassPath.initClassPath(classPathDirs, bootClassPath, extraBootClassPathEntries, dexFilePath, dexFile); theClassPath.initClassPath(classPathDirs, bootClassPath, extraBootClassPathEntries, dexFilePath, dexFile,
checkPackagePrivateAccess);
} }
private ClassPath() { private ClassPath() {
@ -129,7 +139,8 @@ public class ClassPath {
} }
private void initClassPath(String[] classPathDirs, String[] bootClassPath, String[] extraBootClassPathEntries, private void initClassPath(String[] classPathDirs, String[] bootClassPath, String[] extraBootClassPathEntries,
String dexFilePath, DexFile dexFile) { String dexFilePath, DexFile dexFile, boolean checkPackagePrivateAccess) {
this.checkPackagePrivateAccess = checkPackagePrivateAccess;
unloadedClasses = new LinkedHashMap<String, UnresolvedClassInfo>(); unloadedClasses = new LinkedHashMap<String, UnresolvedClassInfo>();
if (bootClassPath != null) { if (bootClassPath != null) {
@ -588,7 +599,7 @@ public class ClassPath {
private final int classDepth; private final int classDepth;
private final String[] vtable; private final VirtualMethod[] vtable;
//this maps a method name of the form method(III)Ljava/lang/String; to an integer //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 the value is non-negative, it is a vtable index
@ -611,7 +622,7 @@ public class ClassPath {
*/ */
//This is only the virtual methods that this class declares itself. //This is only the virtual methods that this class declares itself.
private String[] virtualMethods; private VirtualMethod[] virtualMethods;
//this is a list of all the interfaces that the class implements directory, or any super interfaces of those //this is a list of all the interfaces that the class implements directory, or any super interfaces of those
//interfaces. It is generated in such a way that it is ordered in the same way as dalvik's ClassObject.iftable, //interfaces. It is generated in such a way that it is ordered in the same way as dalvik's ClassObject.iftable,
private LinkedHashMap<String, ClassDef> interfaceTable; private LinkedHashMap<String, ClassDef> interfaceTable;
@ -696,7 +707,7 @@ public class ClassPath {
} }
methodLookup = new HashMap<String, Integer>((int)Math.ceil(((vtable.length + directMethodCount)/ .7f)), .75f); 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++) {
methodLookup.put(vtable[i], i); methodLookup.put(vtable[i].method, i);
} }
if (directMethodCount > 0) { if (directMethodCount > 0) {
for (int i=0; i<classInfo.directMethods.length; i++) { for (int i=0; i<classInfo.directMethods.length; i++) {
@ -794,7 +805,7 @@ public class ClassPath {
if (vtableIndex < 0 || vtableIndex >= vtable.length) { if (vtableIndex < 0 || vtableIndex >= vtable.length) {
return null; return null;
} }
return this.vtable[vtableIndex]; return this.vtable[vtableIndex].method;
} }
private void swap(byte[] fieldTypes, FieldDef[] fields, int position1, int position2) { private void swap(byte[] fieldTypes, FieldDef[] fields, int position1, int position2) {
@ -912,19 +923,16 @@ public class ClassPath {
return interfaceTable; return interfaceTable;
} }
private String[] loadVtable(UnresolvedClassInfo classInfo) { //TODO: check the case when we have a package private method that overrides an interface method
private VirtualMethod[] loadVtable(UnresolvedClassInfo classInfo) {
//TODO: it might be useful to keep track of which class's implementation is used for each virtual method. In other words, associate the implementing class type with each vtable entry //TODO: it might be useful to keep track of which class's implementation is used for each virtual method. In other words, associate the implementing class type with each vtable entry
List<String> virtualMethodList = new LinkedList<String>(); List<VirtualMethod> virtualMethodList = new LinkedList<VirtualMethod>();
//use a temp hash table, so that we can construct the final lookup with an appropriate
//capacity, based on the number of virtual methods
HashMap<String, Integer> tempVirtualMethodLookup = new HashMap<String, Integer>();
//copy the virtual methods from the superclass //copy the virtual methods from the superclass
int methodIndex = 0; int methodIndex = 0;
if (superclass != null) { if (superclass != null) {
for (String method: superclass.vtable) { for (int i=0; i<superclass.vtable.length; i++) {
virtualMethodList.add(method); virtualMethodList.add(superclass.vtable[i]);
tempVirtualMethodLookup.put(method, methodIndex++);
} }
assert superclass.instanceFields != null; assert superclass.instanceFields != null;
@ -935,12 +943,7 @@ public class ClassPath {
//method (i.e. if it was implemented by the superclass) //method (i.e. if it was implemented by the superclass)
if (!this.isInterface) { if (!this.isInterface) {
if (classInfo.virtualMethods != null) { if (classInfo.virtualMethods != null) {
for (String virtualMethod: classInfo.virtualMethods) { addToVtable(classInfo.virtualMethods, virtualMethodList);
if (tempVirtualMethodLookup.get(virtualMethod) == null) {
virtualMethodList.add(virtualMethod);
tempVirtualMethodLookup.put(virtualMethod, methodIndex++);
}
}
} }
if (interfaceTable != null) { if (interfaceTable != null) {
@ -949,17 +952,12 @@ public class ClassPath {
continue; continue;
} }
for (String virtualMethod: interfaceDef.virtualMethods) { addToVtable(interfaceDef.virtualMethods, virtualMethodList);
if (tempVirtualMethodLookup.get(virtualMethod) == null) {
virtualMethodList.add(virtualMethod);
tempVirtualMethodLookup.put(virtualMethod, methodIndex++);
}
}
} }
} }
} }
String[] vtable = new String[virtualMethodList.size()]; VirtualMethod[] vtable = new VirtualMethod[virtualMethodList.size()];
for (int i=0; i<virtualMethodList.size(); i++) { for (int i=0; i<virtualMethodList.size(); i++) {
vtable[i] = virtualMethodList.get(i); vtable[i] = virtualMethodList.get(i);
} }
@ -967,6 +965,43 @@ public class ClassPath {
return vtable; return vtable;
} }
private void addToVtable(VirtualMethod[] localMethods, List<VirtualMethod> vtable) {
for (VirtualMethod virtualMethod: localMethods) {
boolean found = false;
for (int i=0; i<vtable.size(); i++) {
VirtualMethod superMethod = vtable.get(i);
if (superMethod.method.equals(virtualMethod.method)) {
if (!ClassPath.theClassPath.checkPackagePrivateAccess || this.canAccess(superMethod)) {
found = true;
vtable.set(i, virtualMethod);
break;
}
}
}
if (!found) {
vtable.add(virtualMethod);
}
}
}
private boolean canAccess(VirtualMethod virtualMethod) {
if (!virtualMethod.isPackagePrivate) {
return true;
}
String otherPackage = getPackage(virtualMethod.containingClass);
String ourPackage = getPackage(this.classType);
return otherPackage.equals(ourPackage);
}
private String getPackage(String classType) {
int lastSlash = classType.lastIndexOf('/');
if (lastSlash < 0) {
return "";
}
return classType.substring(1, lastSlash);
}
private int getNextFieldOffset() { private int getNextFieldOffset() {
if (instanceFields == null || instanceFields.size() == 0) { if (instanceFields == null || instanceFields.size() == 0) {
return 8; return 8;
@ -1178,6 +1213,12 @@ public class ClassPath {
} }
} }
private static class VirtualMethod {
public String containingClass;
public String method;
public boolean isPackagePrivate;
}
/** /**
* This aggregates the basic information about a class in an easy-to-use format, without requiring references * This aggregates the basic information about a class in an easy-to-use format, without requiring references
* to any other class. * to any other class.
@ -1190,7 +1231,7 @@ public class ClassPath {
public final String[] interfaces; public final String[] interfaces;
public final boolean[] staticMethods; public final boolean[] staticMethods;
public final String[] directMethods; public final String[] directMethods;
public final String[] virtualMethods; public final VirtualMethod[] virtualMethods;
public final String[][] instanceFields; public final String[][] instanceFields;
public UnresolvedClassInfo(String dexFilePath, ClassDefItem classDefItem) { public UnresolvedClassInfo(String dexFilePath, ClassDefItem classDefItem) {
@ -1259,18 +1300,29 @@ public class ClassPath {
return null; return null;
} }
private String[] loadVirtualMethods(ClassDataItem classDataItem) { private VirtualMethod[] loadVirtualMethods(ClassDataItem classDataItem) {
List<EncodedMethod> encodedMethods = classDataItem.getVirtualMethods(); List<EncodedMethod> encodedMethods = classDataItem.getVirtualMethods();
if (encodedMethods.size() > 0) { if (encodedMethods.size() > 0) {
String[] virtualMethods = new String[encodedMethods.size()]; VirtualMethod[] virtualMethods = new VirtualMethod[encodedMethods.size()];
for (int i=0; i<encodedMethods.size(); i++) { for (int i=0; i<encodedMethods.size(); i++) {
virtualMethods[i] = encodedMethods.get(i).method.getShortMethodString(); virtualMethods[i] = new VirtualMethod();
EncodedMethod encodedMethod = encodedMethods.get(i);
virtualMethods[i].isPackagePrivate = methodIsPackagePrivate(encodedMethod.accessFlags);
virtualMethods[i].containingClass = classDataItem.getParentType().getTypeDescriptor();
virtualMethods[i].method = encodedMethods.get(i).method.getShortMethodString();
} }
return virtualMethods; return virtualMethods;
} }
return null; return null;
} }
private static boolean methodIsPackagePrivate(int accessFlags) {
return (accessFlags & (AccessFlags.PRIVATE.getValue() |
AccessFlags.PROTECTED.getValue() |
AccessFlags.PUBLIC.getValue())) == 0;
}
private String[][] loadInstanceFields(ClassDataItem classDataItem) { private String[][] loadInstanceFields(ClassDataItem classDataItem) {
List<EncodedField> encodedFields = classDataItem.getInstanceFields(); List<EncodedField> encodedFields = classDataItem.getInstanceFields();
if (encodedFields.size() > 0) { if (encodedFields.size() > 0) {

View File

@ -135,7 +135,14 @@ public abstract class InlineMethodResolver {
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Float;", "intBitsToFloat", "I", "F"), 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;", "doubleToLongBits", "D", "J"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Double;", "doubleToRawLongBits", "D", "J"), new DeodexUtil.InlineMethod(Static, "Ljava/lang/Double;", "doubleToRawLongBits", "D", "J"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/Double;", "longBitsToDouble", "J", "D") new DeodexUtil.InlineMethod(Static, "Ljava/lang/Double;", "longBitsToDouble", "J", "D"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/StrictMath;", "abs", "I", "I"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/StrictMath;", "abs", "J", "J"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/StrictMath;", "abs", "F", "F"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/StrictMath;", "abs", "D", "D"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/StrictMath;", "min", "II", "I"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/StrictMath;", "max", "II", "I"),
new DeodexUtil.InlineMethod(Static, "Ljava/lang/StrictMath;", "sqrt", "D", "D"),
}; };
} }

View File

@ -703,28 +703,34 @@ public class MethodAnalyzer {
analyzeConstString(analyzedInstruction); analyzeConstString(analyzedInstruction);
return true; return true;
case CONST_CLASS: case CONST_CLASS:
case CONST_CLASS_JUMBO:
analyzeConstClass(analyzedInstruction); analyzeConstClass(analyzedInstruction);
return true; return true;
case MONITOR_ENTER: case MONITOR_ENTER:
case MONITOR_EXIT: case MONITOR_EXIT:
return true; return true;
case CHECK_CAST: case CHECK_CAST:
case CHECK_CAST_JUMBO:
analyzeCheckCast(analyzedInstruction); analyzeCheckCast(analyzedInstruction);
return true; return true;
case INSTANCE_OF: case INSTANCE_OF:
case INSTANCE_OF_JUMBO:
analyzeInstanceOf(analyzedInstruction); analyzeInstanceOf(analyzedInstruction);
return true; return true;
case ARRAY_LENGTH: case ARRAY_LENGTH:
analyzeArrayLength(analyzedInstruction); analyzeArrayLength(analyzedInstruction);
return true; return true;
case NEW_INSTANCE: case NEW_INSTANCE:
case NEW_INSTANCE_JUMBO:
analyzeNewInstance(analyzedInstruction); analyzeNewInstance(analyzedInstruction);
return true; return true;
case NEW_ARRAY: case NEW_ARRAY:
case NEW_ARRAY_JUMBO:
analyzeNewArray(analyzedInstruction); analyzeNewArray(analyzedInstruction);
return true; return true;
case FILLED_NEW_ARRAY: case FILLED_NEW_ARRAY:
case FILLED_NEW_ARRAY_RANGE: case FILLED_NEW_ARRAY_RANGE:
case FILLED_NEW_ARRAY_JUMBO:
return true; return true;
case FILL_ARRAY_DATA: case FILL_ARRAY_DATA:
analyzeArrayDataOrSwitch(analyzedInstruction); analyzeArrayDataOrSwitch(analyzedInstruction);
@ -787,58 +793,86 @@ public class MethodAnalyzer {
case APUT_OBJECT: case APUT_OBJECT:
return true; return true;
case IGET: case IGET:
case IGET_JUMBO:
analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Integer); analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Integer);
return true; return true;
case IGET_BOOLEAN: case IGET_BOOLEAN:
case IGET_BOOLEAN_JUMBO:
analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Boolean); analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Boolean);
return true; return true;
case IGET_BYTE: case IGET_BYTE:
case IGET_BYTE_JUMBO:
analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Byte); analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Byte);
return true; return true;
case IGET_CHAR: case IGET_CHAR:
case IGET_CHAR_JUMBO:
analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Char); analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Char);
return true; return true;
case IGET_SHORT: case IGET_SHORT:
case IGET_SHORT_JUMBO:
analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Short); analyze32BitPrimitiveIget(analyzedInstruction, RegisterType.Category.Short);
return true; return true;
case IGET_WIDE: case IGET_WIDE:
case IGET_WIDE_JUMBO:
case IGET_OBJECT: case IGET_OBJECT:
case IGET_OBJECT_JUMBO:
analyzeIgetWideObject(analyzedInstruction); analyzeIgetWideObject(analyzedInstruction);
return true; return true;
case IPUT: case IPUT:
case IPUT_JUMBO:
case IPUT_BOOLEAN: case IPUT_BOOLEAN:
case IPUT_BOOLEAN_JUMBO:
case IPUT_BYTE: case IPUT_BYTE:
case IPUT_BYTE_JUMBO:
case IPUT_CHAR: case IPUT_CHAR:
case IPUT_CHAR_JUMBO:
case IPUT_SHORT: case IPUT_SHORT:
case IPUT_SHORT_JUMBO:
case IPUT_WIDE: case IPUT_WIDE:
case IPUT_WIDE_JUMBO:
case IPUT_OBJECT: case IPUT_OBJECT:
case IPUT_OBJECT_JUMBO:
return true; return true;
case SGET: case SGET:
case SGET_JUMBO:
analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Integer); analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Integer);
return true; return true;
case SGET_BOOLEAN: case SGET_BOOLEAN:
case SGET_BOOLEAN_JUMBO:
analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Boolean); analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Boolean);
return true; return true;
case SGET_BYTE: case SGET_BYTE:
case SGET_BYTE_JUMBO:
analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Byte); analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Byte);
return true; return true;
case SGET_CHAR: case SGET_CHAR:
case SGET_CHAR_JUMBO:
analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Char); analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Char);
return true; return true;
case SGET_SHORT: case SGET_SHORT:
case SGET_SHORT_JUMBO:
analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Short); analyze32BitPrimitiveSget(analyzedInstruction, RegisterType.Category.Short);
return true; return true;
case SGET_WIDE: case SGET_WIDE:
case SGET_WIDE_JUMBO:
case SGET_OBJECT: case SGET_OBJECT:
case SGET_OBJECT_JUMBO:
analyzeSgetWideObject(analyzedInstruction); analyzeSgetWideObject(analyzedInstruction);
return true; return true;
case SPUT: case SPUT:
case SPUT_JUMBO:
case SPUT_BOOLEAN: case SPUT_BOOLEAN:
case SPUT_BOOLEAN_JUMBO:
case SPUT_BYTE: case SPUT_BYTE:
case SPUT_BYTE_JUMBO:
case SPUT_CHAR: case SPUT_CHAR:
case SPUT_CHAR_JUMBO:
case SPUT_SHORT: case SPUT_SHORT:
case SPUT_SHORT_JUMBO:
case SPUT_WIDE: case SPUT_WIDE:
case SPUT_WIDE_JUMBO:
case SPUT_OBJECT: case SPUT_OBJECT:
case SPUT_OBJECT_JUMBO:
return true; return true;
case INVOKE_VIRTUAL: case INVOKE_VIRTUAL:
case INVOKE_SUPER: case INVOKE_SUPER:
@ -849,13 +883,18 @@ public class MethodAnalyzer {
case INVOKE_STATIC: case INVOKE_STATIC:
case INVOKE_INTERFACE: case INVOKE_INTERFACE:
case INVOKE_VIRTUAL_RANGE: case INVOKE_VIRTUAL_RANGE:
case INVOKE_VIRTUAL_JUMBO:
case INVOKE_SUPER_RANGE: case INVOKE_SUPER_RANGE:
case INVOKE_SUPER_JUMBO:
return true; return true;
case INVOKE_DIRECT_RANGE: case INVOKE_DIRECT_RANGE:
case INVOKE_DIRECT_JUMBO:
analyzeInvokeDirectRange(analyzedInstruction); analyzeInvokeDirectRange(analyzedInstruction);
return true; return true;
case INVOKE_STATIC_RANGE: case INVOKE_STATIC_RANGE:
case INVOKE_STATIC_JUMBO:
case INVOKE_INTERFACE_RANGE: case INVOKE_INTERFACE_RANGE:
case INVOKE_INTERFACE_JUMBO:
return true; return true;
case NEG_INT: case NEG_INT:
case NOT_INT: case NOT_INT:
@ -1076,6 +1115,23 @@ public class MethodAnalyzer {
case SPUT_OBJECT_VOLATILE: case SPUT_OBJECT_VOLATILE:
analyzePutGetVolatile(analyzedInstruction); analyzePutGetVolatile(analyzedInstruction);
return true; return true;
case INVOKE_OBJECT_INIT_JUMBO:
analyzeInvokeObjectInitJumbo(analyzedInstruction);
return true;
case IGET_VOLATILE_JUMBO:
case IGET_WIDE_VOLATILE_JUMBO:
case IGET_OBJECT_VOLATILE_JUMBO:
case IPUT_VOLATILE_JUMBO:
case IPUT_WIDE_VOLATILE_JUMBO:
case IPUT_OBJECT_VOLATILE_JUMBO:
case SGET_VOLATILE_JUMBO:
case SGET_WIDE_VOLATILE_JUMBO:
case SGET_OBJECT_VOLATILE_JUMBO:
case SPUT_VOLATILE_JUMBO:
case SPUT_WIDE_VOLATILE_JUMBO:
case SPUT_OBJECT_VOLATILE_JUMBO:
analyzePutGetVolatile(analyzedInstruction);
return true;
default: default:
assert false; assert false;
return true; return true;
@ -1141,6 +1197,7 @@ public class MethodAnalyzer {
case CONST_STRING_JUMBO: case CONST_STRING_JUMBO:
return; return;
case CONST_CLASS: case CONST_CLASS:
case CONST_CLASS_JUMBO:
verifyConstClass(analyzedInstruction); verifyConstClass(analyzedInstruction);
return; return;
case MONITOR_ENTER: case MONITOR_ENTER:
@ -1148,15 +1205,18 @@ public class MethodAnalyzer {
verifyMonitor(analyzedInstruction); verifyMonitor(analyzedInstruction);
return; return;
case CHECK_CAST: case CHECK_CAST:
case CHECK_CAST_JUMBO:
verifyCheckCast(analyzedInstruction); verifyCheckCast(analyzedInstruction);
return; return;
case INSTANCE_OF: case INSTANCE_OF:
case INSTANCE_OF_JUMBO:
verifyInstanceOf(analyzedInstruction); verifyInstanceOf(analyzedInstruction);
return; return;
case ARRAY_LENGTH: case ARRAY_LENGTH:
verifyArrayLength(analyzedInstruction); verifyArrayLength(analyzedInstruction);
return; return;
case NEW_INSTANCE: case NEW_INSTANCE:
case NEW_INSTANCE_JUMBO:
verifyNewInstance(analyzedInstruction); verifyNewInstance(analyzedInstruction);
return; return;
case NEW_ARRAY: case NEW_ARRAY:
@ -1566,6 +1626,19 @@ public class MethodAnalyzer {
case IPUT_OBJECT_VOLATILE: case IPUT_OBJECT_VOLATILE:
case SGET_OBJECT_VOLATILE: case SGET_OBJECT_VOLATILE:
case SPUT_OBJECT_VOLATILE: case SPUT_OBJECT_VOLATILE:
case INVOKE_OBJECT_INIT_JUMBO:
case IGET_VOLATILE_JUMBO:
case IGET_WIDE_VOLATILE_JUMBO:
case IGET_OBJECT_VOLATILE_JUMBO:
case IPUT_VOLATILE_JUMBO:
case IPUT_WIDE_VOLATILE_JUMBO:
case IPUT_OBJECT_VOLATILE_JUMBO:
case SGET_VOLATILE_JUMBO:
case SGET_WIDE_VOLATILE_JUMBO:
case SGET_OBJECT_VOLATILE_JUMBO:
case SPUT_VOLATILE_JUMBO:
case SPUT_WIDE_VOLATILE_JUMBO:
case SPUT_OBJECT_VOLATILE_JUMBO:
//TODO: throw validation exception? //TODO: throw validation exception?
default: default:
assert false; assert false;
@ -3622,12 +3695,23 @@ public class MethodAnalyzer {
if (analyzedInstruction.instruction.opcode.isOdexedStaticVolatile()) { if (analyzedInstruction.instruction.opcode.isOdexedStaticVolatile()) {
SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction; SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
deodexedInstruction = new Instruction21c(opcode, (byte)instruction.getRegisterA(), fieldIdItem); if (analyzedInstruction.instruction.opcode.format == Format.Format21c) {
deodexedInstruction = new Instruction21c(opcode, (byte)instruction.getRegisterA(), fieldIdItem);
} else {
assert(analyzedInstruction.instruction.opcode.format == Format.Format41c);
deodexedInstruction = new Instruction41c(opcode, (byte)instruction.getRegisterA(), fieldIdItem);
}
} else { } else {
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction; TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
deodexedInstruction = new Instruction22c(opcode, (byte)instruction.getRegisterA(), if (analyzedInstruction.instruction.opcode.format == Format.Format22c) {
(byte)instruction.getRegisterB(), fieldIdItem); deodexedInstruction = new Instruction22c(opcode, (byte)instruction.getRegisterA(),
(byte)instruction.getRegisterB(), fieldIdItem);
} else {
assert(analyzedInstruction.instruction.opcode.format == Format.Format52c);
deodexedInstruction = new Instruction52c(opcode, (byte)instruction.getRegisterA(),
(byte)instruction.getRegisterB(), fieldIdItem);
}
} }
analyzedInstruction.setDeodexedInstruction(deodexedInstruction); analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
@ -3638,6 +3722,17 @@ public class MethodAnalyzer {
return true; return true;
} }
private void analyzeInvokeObjectInitJumbo(AnalyzedInstruction analyzedInstruction) {
Instruction5rc instruction = (Instruction5rc)analyzedInstruction.instruction;
Instruction5rc deodexedInstruction = new Instruction5rc(Opcode.INVOKE_DIRECT_JUMBO,
instruction.getRegCount(), instruction.getStartRegister(), instruction.getReferencedItem());
analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
analyzeInstruction(analyzedInstruction);
}
private static boolean checkArrayFieldAssignment(RegisterType.Category arrayFieldCategory, private static boolean checkArrayFieldAssignment(RegisterType.Category arrayFieldCategory,
RegisterType.Category instructionCategory) { RegisterType.Category instructionCategory) {
if (arrayFieldCategory == instructionCategory) { if (arrayFieldCategory == instructionCategory) {

View File

@ -178,6 +178,107 @@ public class OdexedFieldInstructionMapper {
} }
}; };
private static Opcode[][][][] jumboOpcodeMap = new Opcode[][][][] {
//get opcodes
new Opcode[][][] {
//iget volatile
new Opcode[][] {
//odexed
new Opcode[] {
/*Z*/ Opcode.IGET_VOLATILE_JUMBO,
/*B*/ Opcode.IGET_VOLATILE_JUMBO,
/*S*/ Opcode.IGET_VOLATILE_JUMBO,
/*C*/ Opcode.IGET_VOLATILE_JUMBO,
/*I,F*/ Opcode.IGET_VOLATILE_JUMBO,
/*J,D*/ Opcode.IGET_WIDE_VOLATILE_JUMBO,
/*L,[*/ Opcode.IGET_OBJECT_VOLATILE_JUMBO
},
//deodexed
new Opcode[] {
/*Z*/ Opcode.IGET_BOOLEAN_JUMBO,
/*B*/ Opcode.IGET_BYTE_JUMBO,
/*S*/ Opcode.IGET_SHORT_JUMBO,
/*C*/ Opcode.IGET_CHAR_JUMBO,
/*I,F*/ Opcode.IGET_JUMBO,
/*J,D*/ Opcode.IGET_WIDE_JUMBO,
/*L,[*/ Opcode.IGET_OBJECT_JUMBO
}
},
//sget volatile
new Opcode[][] {
//odexed
new Opcode[] {
/*Z*/ Opcode.SGET_VOLATILE_JUMBO,
/*B*/ Opcode.SGET_VOLATILE_JUMBO,
/*S*/ Opcode.SGET_VOLATILE_JUMBO,
/*C*/ Opcode.SGET_VOLATILE_JUMBO,
/*I,F*/ Opcode.SGET_VOLATILE_JUMBO,
/*J,D*/ Opcode.SGET_WIDE_VOLATILE_JUMBO,
/*L,[*/ Opcode.SGET_OBJECT_VOLATILE_JUMBO
},
//deodexed
new Opcode[] {
/*Z*/ Opcode.SGET_BOOLEAN_JUMBO,
/*B*/ Opcode.SGET_BYTE_JUMBO,
/*S*/ Opcode.SGET_SHORT_JUMBO,
/*C*/ Opcode.SGET_CHAR_JUMBO,
/*I,F*/ Opcode.SGET_JUMBO,
/*J,D*/ Opcode.SGET_WIDE_JUMBO,
/*L,[*/ Opcode.SGET_OBJECT_JUMBO
}
}
},
//put opcodes
new Opcode[][][] {
//iput volatile
new Opcode[][] {
//odexed
new Opcode[] {
/*Z*/ Opcode.IPUT_VOLATILE_JUMBO,
/*B*/ Opcode.IPUT_VOLATILE_JUMBO,
/*S*/ Opcode.IPUT_VOLATILE_JUMBO,
/*C*/ Opcode.IPUT_VOLATILE_JUMBO,
/*I,F*/ Opcode.IPUT_VOLATILE_JUMBO,
/*J,D*/ Opcode.IPUT_WIDE_VOLATILE_JUMBO,
/*L,[*/ Opcode.IPUT_OBJECT_VOLATILE_JUMBO
},
//deodexed
new Opcode[] {
/*Z*/ Opcode.IPUT_BOOLEAN_JUMBO,
/*B*/ Opcode.IPUT_BYTE_JUMBO,
/*S*/ Opcode.IPUT_SHORT_JUMBO,
/*C*/ Opcode.IPUT_CHAR_JUMBO,
/*I,F*/ Opcode.IPUT_JUMBO,
/*J,D*/ Opcode.IPUT_WIDE_JUMBO,
/*L,[*/ Opcode.IPUT_OBJECT_JUMBO
}
},
//sput volatile
new Opcode[][] {
//odexed
new Opcode[] {
/*Z*/ Opcode.SPUT_VOLATILE_JUMBO,
/*B*/ Opcode.SPUT_VOLATILE_JUMBO,
/*S*/ Opcode.SPUT_VOLATILE_JUMBO,
/*C*/ Opcode.SPUT_VOLATILE_JUMBO,
/*I,F*/ Opcode.SPUT_VOLATILE_JUMBO,
/*J,D*/ Opcode.SPUT_WIDE_VOLATILE_JUMBO,
/*L,[*/ Opcode.SPUT_OBJECT_VOLATILE_JUMBO
},
//deodexed
new Opcode[] {
/*Z*/ Opcode.SPUT_BOOLEAN_JUMBO,
/*B*/ Opcode.SPUT_BYTE_JUMBO,
/*S*/ Opcode.SPUT_SHORT_JUMBO,
/*C*/ Opcode.SPUT_CHAR_JUMBO,
/*I,F*/ Opcode.SPUT_JUMBO,
/*J,D*/ Opcode.SPUT_WIDE_JUMBO,
/*L,[*/ Opcode.SPUT_OBJECT_JUMBO
}
}
}
};
private static int getTypeIndex(char type) { private static int getTypeIndex(char type) {
switch (type) { switch (type) {
case 'Z': case 'Z':
@ -214,14 +315,20 @@ public class OdexedFieldInstructionMapper {
} }
static Opcode getAndCheckDeodexedOpcodeForOdexedOpcode(String fieldType, Opcode odexedOpcode) { static Opcode getAndCheckDeodexedOpcodeForOdexedOpcode(String fieldType, Opcode odexedOpcode) {
boolean jumbo = odexedOpcode.isJumboOpcode();
int opcodeType = odexedOpcode.setsRegister()?0:1; int opcodeType = odexedOpcode.setsRegister()?0:1;
int opcodeSubType = getOpcodeSubtype(odexedOpcode); int opcodeSubType = getOpcodeSubtype(odexedOpcode);
int typeIndex = getTypeIndex(fieldType.charAt(0)); int typeIndex = getTypeIndex(fieldType.charAt(0));
Opcode correctOdexedOpcode, deodexedOpcode; Opcode correctOdexedOpcode, deodexedOpcode;
correctOdexedOpcode = opcodeMap[opcodeType][opcodeSubType][0][typeIndex]; if (jumbo) {
deodexedOpcode = opcodeMap[opcodeType][opcodeSubType][1][typeIndex]; correctOdexedOpcode = jumboOpcodeMap[opcodeType][opcodeSubType-1][0][typeIndex];
deodexedOpcode = jumboOpcodeMap[opcodeType][opcodeSubType-1][1][typeIndex];
} else {
correctOdexedOpcode = opcodeMap[opcodeType][opcodeSubType][0][typeIndex];
deodexedOpcode = opcodeMap[opcodeType][opcodeSubType][1][typeIndex];
}
if (correctOdexedOpcode != odexedOpcode) { if (correctOdexedOpcode != odexedOpcode) {
throw new ValidationException(String.format("Incorrect field type \"%s\" for %s", fieldType, throw new ValidationException(String.format("Incorrect field type \"%s\" for %s", fieldType,

View File

@ -90,7 +90,11 @@ public class SyntheticAccessorResolver {
return null; return null;
} }
InstructionWithReference instruction = (InstructionWithReference)instructions[0]; InstructionWithReference instruction = (InstructionWithReference)instructions[0];
MethodIdItem referencedMethodIdItem = (MethodIdItem)instruction.getReferencedItem(); Item referencedItem = instruction.getReferencedItem();
if (!(referencedItem instanceof MethodIdItem)) {
return null;
}
MethodIdItem referencedMethodIdItem = (MethodIdItem)referencedItem;
accessedMember = new AccessedMember(METHOD, referencedMethodIdItem); accessedMember = new AccessedMember(METHOD, referencedMethodIdItem);
resolvedAccessors.put(methodIdItem, accessedMember); resolvedAccessors.put(methodIdItem, accessedMember);
@ -102,9 +106,15 @@ public class SyntheticAccessorResolver {
return null; return null;
} }
Instruction22c instruction = (Instruction22c)instructions[0]; Instruction22c instruction = (Instruction22c)instructions[0];
FieldIdItem referencedFieldIdItem = (FieldIdItem)instruction.getReferencedItem(); Item referencedItem = instruction.getReferencedItem();
if (!(referencedItem instanceof FieldIdItem)) {
return null;
}
FieldIdItem referencedFieldIdItem = (FieldIdItem)referencedItem;
if (instruction.opcode.setsRegister() || instruction.opcode.setsWideRegister()) { if (instruction.opcode.setsRegister() || instruction.opcode.setsWideRegister()) {
//If the instruction sets a register, that means it is a getter - it gets the field value and
//stores it in the register
accessedMember = new AccessedMember(GETTER, referencedFieldIdItem); accessedMember = new AccessedMember(GETTER, referencedFieldIdItem);
} else { } else {
accessedMember = new AccessedMember(SETTER, referencedFieldIdItem); accessedMember = new AccessedMember(SETTER, referencedFieldIdItem);
@ -119,20 +129,12 @@ public class SyntheticAccessorResolver {
} }
public static class AccessedMember { public static class AccessedMember {
private final int accessedMemberType; public final int accessedMemberType;
private final Item accessedMember; public final Item accessedMember;
public AccessedMember(int accessedMemberType, Item accessedMember) { public AccessedMember(int accessedMemberType, Item accessedMember) {
this.accessedMemberType = accessedMemberType; this.accessedMemberType = accessedMemberType;
this.accessedMember = accessedMember; this.accessedMember = accessedMember;
} }
public int getAccessedMemberType() {
return accessedMemberType;
}
public Item getAccessedMember() {
return accessedMember;
}
} }
} }

View File

@ -60,7 +60,10 @@ public enum Format {
Format3rc(Instruction3rc.Factory, 6), Format3rc(Instruction3rc.Factory, 6),
Format3rmi(Instruction3rmi.Factory, 6), Format3rmi(Instruction3rmi.Factory, 6),
Format3rms(Instruction3rms.Factory, 6), Format3rms(Instruction3rms.Factory, 6),
Format41c(Instruction41c.Factory, 8),
Format51l(Instruction51l.Factory, 10), Format51l(Instruction51l.Factory, 10),
Format52c(Instruction52c.Factory, 10),
Format5rc(Instruction5rc.Factory, 10),
ArrayData(null, -1, true), ArrayData(null, -1, true),
PackedSwitchData(null, -1, true), PackedSwitchData(null, -1, true),
SparseSwitchData(null, -1, true), SparseSwitchData(null, -1, true),

View File

@ -100,7 +100,11 @@ public class Instruction21c extends InstructionWithReference implements SingleRe
return null; return null;
} }
return new Instruction31c(jumboOpcode, (short)getRegisterA(), getReferencedItem()); if (jumboOpcode.format == Format.Format31c) {
return new Instruction31c(jumboOpcode, (short)getRegisterA(), getReferencedItem());
}
return new Instruction41c(jumboOpcode, getRegisterA(), getReferencedItem());
} }
private static class Factory implements Instruction.InstructionFactory { private static class Factory implements Instruction.InstructionFactory {

View File

@ -37,7 +37,8 @@ import org.jf.dexlib.Item;
import org.jf.dexlib.Util.AnnotatedOutput; import org.jf.dexlib.Util.AnnotatedOutput;
import org.jf.dexlib.Util.NumberUtils; import org.jf.dexlib.Util.NumberUtils;
public class Instruction22c extends InstructionWithReference implements TwoRegisterInstruction { public class Instruction22c extends InstructionWithReference implements TwoRegisterInstruction,
InstructionWithJumboVariant {
public static final Instruction.InstructionFactory Factory = new Factory(); public static final Instruction.InstructionFactory Factory = new Factory();
private byte regA; private byte regA;
private byte regB; private byte regB;
@ -88,6 +89,15 @@ public class Instruction22c extends InstructionWithReference implements TwoRegis
return regB; return regB;
} }
public Instruction makeJumbo() {
Opcode jumboOpcode = opcode.getJumboOpcode();
if (jumboOpcode == null) {
return null;
}
return new Instruction52c(jumboOpcode, getRegisterA(), getRegisterB(), getReferencedItem());
}
private static class Factory implements Instruction.InstructionFactory { private static class Factory implements Instruction.InstructionFactory {
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
return new Instruction22c(dexFile, opcode, buffer, bufferIndex); return new Instruction22c(dexFile, opcode, buffer, bufferIndex);

View File

@ -41,7 +41,8 @@ import org.jf.dexlib.Util.NumberUtils;
import static org.jf.dexlib.Code.Opcode.*; import static org.jf.dexlib.Code.Opcode.*;
public class Instruction3rc extends InstructionWithReference implements RegisterRangeInstruction { public class Instruction3rc extends InstructionWithReference implements RegisterRangeInstruction,
InstructionWithJumboVariant {
public static final Instruction.InstructionFactory Factory = new Factory(); public static final Instruction.InstructionFactory Factory = new Factory();
private byte regCount; private byte regCount;
private short startReg; private short startReg;
@ -130,6 +131,15 @@ public class Instruction3rc extends InstructionWithReference implements Register
} }
} }
public Instruction makeJumbo() {
Opcode jumboOpcode = opcode.getJumboOpcode();
if (jumboOpcode == null) {
return null;
}
return new Instruction5rc(jumboOpcode, getRegCount(), getStartRegister(), getReferencedItem());
}
private static class Factory implements Instruction.InstructionFactory { private static class Factory implements Instruction.InstructionFactory {
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
return new Instruction3rc(dexFile, opcode, buffer, bufferIndex); return new Instruction3rc(dexFile, opcode, buffer, bufferIndex);

View File

@ -0,0 +1,97 @@
/*
* 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.Format;
import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.InstructionWithReference;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.Code.SingleRegisterInstruction;
import org.jf.dexlib.DexFile;
import org.jf.dexlib.Item;
import org.jf.dexlib.TypeIdItem;
import org.jf.dexlib.Util.AnnotatedOutput;
import org.jf.dexlib.Util.NumberUtils;
public class Instruction41c extends InstructionWithJumboReference implements SingleRegisterInstruction {
public static final InstructionFactory Factory = new Factory();
private short regA;
public Instruction41c(Opcode opcode, int regA, Item referencedItem) {
super(opcode, referencedItem);
if (regA >= 1 << 16) {
throw new RuntimeException("The register number must be less than v65536");
}
if (opcode == Opcode.NEW_INSTANCE_JUMBO) {
assert referencedItem instanceof TypeIdItem;
if (((TypeIdItem)referencedItem).getTypeDescriptor().charAt(0) != 'L') {
throw new RuntimeException("Only class references can be used with the new-instance/jumbo opcode");
}
}
this.regA = (short)regA;
}
private Instruction41c(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
super(dexFile, opcode, buffer, bufferIndex);
if (opcode == Opcode.NEW_INSTANCE_JUMBO &&
((TypeIdItem)this.getReferencedItem()).getTypeDescriptor().charAt(0) != 'L') {
throw new RuntimeException("Only class references can be used with the new-instance/jumbo opcode");
}
this.regA = (short)NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 6);
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(0xFF);
out.writeByte(opcode.value);
out.writeInt(getReferencedItem().getIndex());
out.writeShort(getRegisterA());
}
public Format getFormat() {
return Format.Format41c;
}
public int getRegisterA() {
return regA & 0xFFFF;
}
private static class Factory implements InstructionFactory {
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
return new Instruction41c(dexFile, opcode, buffer, bufferIndex);
}
}
}

View File

@ -0,0 +1,94 @@
/*
* 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.Format;
import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.Code.TwoRegisterInstruction;
import org.jf.dexlib.DexFile;
import org.jf.dexlib.Item;
import org.jf.dexlib.Util.AnnotatedOutput;
import org.jf.dexlib.Util.NumberUtils;
public class Instruction52c extends InstructionWithJumboReference implements TwoRegisterInstruction {
public static final InstructionFactory Factory = new Factory();
private short regA;
private short regB;
public Instruction52c(Opcode opcode, int regA, int regB, Item referencedItem) {
super(opcode, referencedItem);
if (regA >= 1 << 16) {
throw new RuntimeException("The register number must be less than v65536");
}
if (regB >= 1 << 16) {
throw new RuntimeException("The register number must be less than v65536");
}
this.regA = (short)regA;
this.regB = (short)regB;
}
private Instruction52c(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
super(dexFile, opcode, buffer, bufferIndex);
this.regA = (short)NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 6);
this.regB = (short)NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 8);
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(0xFF);
out.writeByte(opcode.value);
out.writeInt(getReferencedItem().getIndex());
out.writeShort(getRegisterA());
out.writeShort(getRegisterB());
}
public Format getFormat() {
return Format.Format52c;
}
public int getRegisterA() {
return regA & 0xFFFF;
}
public int getRegisterB() {
return regB & 0xFFFF;
}
private static class Factory implements InstructionFactory {
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
return new Instruction52c(dexFile, opcode, buffer, bufferIndex);
}
}
}

View File

@ -0,0 +1,133 @@
/*
* 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.Format;
import org.jf.dexlib.Code.Instruction;
import org.jf.dexlib.Code.InstructionWithReference;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.Code.RegisterRangeInstruction;
import org.jf.dexlib.DexFile;
import org.jf.dexlib.Item;
import org.jf.dexlib.MethodIdItem;
import org.jf.dexlib.TypeIdItem;
import org.jf.dexlib.Util.AnnotatedOutput;
import org.jf.dexlib.Util.NumberUtils;
import static org.jf.dexlib.Code.Opcode.*;
public class Instruction5rc extends InstructionWithJumboReference implements RegisterRangeInstruction {
public static final InstructionFactory Factory = new Factory();
private short regCount;
private short startReg;
public Instruction5rc(Opcode opcode, int regCount, int startReg, Item referencedItem) {
super(opcode, referencedItem);
if (regCount >= 1 << 16) {
throw new RuntimeException("regCount must be less than 65536");
}
if (regCount < 0) {
throw new RuntimeException("regCount cannot be negative");
}
if (startReg >= 1 << 16) {
throw new RuntimeException("The beginning register of the range must be less than 65536");
}
if (startReg < 0) {
throw new RuntimeException("The beginning register of the range cannot be negative");
}
this.regCount = (short)regCount;
this.startReg = (short)startReg;
checkItem(opcode, referencedItem, regCount);
}
private Instruction5rc(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
super(dexFile, opcode, buffer, bufferIndex);
this.regCount = (short)NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 6);
this.startReg = (short)NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 8);
checkItem(opcode, getReferencedItem(), getRegCount());
}
protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) {
out.writeByte(0xff);
out.writeByte(opcode.value);
out.writeInt(this.getReferencedItem().getIndex());
out.writeShort(regCount);
out.writeShort(startReg);
}
public Format getFormat() {
return Format.Format5rc;
}
public int getRegCount() {
return regCount & 0xFFFF;
}
public int getStartRegister() {
return startReg & 0xFFFF;
}
private static void checkItem(Opcode opcode, Item item, int regCount) {
if (opcode == FILLED_NEW_ARRAY_JUMBO) {
//check data for filled-new-array/jumbo opcode
String type = ((TypeIdItem) item).getTypeDescriptor();
if (type.charAt(0) != '[') {
throw new RuntimeException("The type must be an array type");
}
if (type.charAt(1) == 'J' || type.charAt(1) == 'D') {
throw new RuntimeException("The type cannot be an array of longs or doubles");
}
} else if (opcode.value >= INVOKE_VIRTUAL_JUMBO.value && opcode.value <= INVOKE_INTERFACE_JUMBO.value ||
opcode == INVOKE_OBJECT_INIT_JUMBO) {
//check data for invoke-*/range opcodes
MethodIdItem methodIdItem = (MethodIdItem) item;
int parameterRegisterCount = methodIdItem.getPrototype().getParameterRegisterCount();
if (opcode != INVOKE_STATIC_JUMBO) {
parameterRegisterCount++;
}
if (parameterRegisterCount != regCount) {
throw new RuntimeException("regCount does not match the number of arguments of the method");
}
}
}
private static class Factory implements InstructionFactory {
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
return new Instruction5rc(dexFile, opcode, buffer, bufferIndex);
}
}
}

View File

@ -62,16 +62,16 @@ public enum Opcode
CONST_WIDE_HIGH16((short)0x19, "const-wide/high16", ReferenceType.none, Format.Format21h, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), CONST_WIDE_HIGH16((short)0x19, "const-wide/high16", ReferenceType.none, Format.Format21h, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
CONST_STRING((short)0x1a, "const-string", ReferenceType.string, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0x1b), CONST_STRING((short)0x1a, "const-string", ReferenceType.string, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0x1b),
CONST_STRING_JUMBO((short)0x1b, "const-string/jumbo", ReferenceType.string, Format.Format31c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), CONST_STRING_JUMBO((short)0x1b, "const-string/jumbo", ReferenceType.string, Format.Format31c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
CONST_CLASS((short)0x1c, "const-class", ReferenceType.type, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), CONST_CLASS((short)0x1c, "const-class", ReferenceType.type, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff00),
MONITOR_ENTER((short)0x1d, "monitor-enter", ReferenceType.none, Format.Format11x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), MONITOR_ENTER((short)0x1d, "monitor-enter", ReferenceType.none, Format.Format11x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
MONITOR_EXIT((short)0x1e, "monitor-exit", ReferenceType.none, Format.Format11x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), MONITOR_EXIT((short)0x1e, "monitor-exit", ReferenceType.none, Format.Format11x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
CHECK_CAST((short)0x1f, "check-cast", ReferenceType.type, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), CHECK_CAST((short)0x1f, "check-cast", ReferenceType.type, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff01),
INSTANCE_OF((short)0x20, "instance-of", ReferenceType.type, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), INSTANCE_OF((short)0x20, "instance-of", ReferenceType.type, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff02),
ARRAY_LENGTH((short)0x21, "array-length", ReferenceType.none, Format.Format12x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), ARRAY_LENGTH((short)0x21, "array-length", ReferenceType.none, Format.Format12x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
NEW_INSTANCE((short)0x22, "new-instance", ReferenceType.type, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), NEW_INSTANCE((short)0x22, "new-instance", ReferenceType.type, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff03),
NEW_ARRAY((short)0x23, "new-array", ReferenceType.type, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), NEW_ARRAY((short)0x23, "new-array", ReferenceType.type, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff04),
FILLED_NEW_ARRAY((short)0x24, "filled-new-array", ReferenceType.type, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), FILLED_NEW_ARRAY((short)0x24, "filled-new-array", ReferenceType.type, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
FILLED_NEW_ARRAY_RANGE((short)0x25, "filled-new-array/range", ReferenceType.type, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), FILLED_NEW_ARRAY_RANGE((short)0x25, "filled-new-array/range", ReferenceType.type, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT, (short)0xff05),
FILL_ARRAY_DATA((short)0x26, "fill-array-data", ReferenceType.none, Format.Format31t, Opcode.CAN_CONTINUE), FILL_ARRAY_DATA((short)0x26, "fill-array-data", ReferenceType.none, Format.Format31t, Opcode.CAN_CONTINUE),
THROW((short)0x27, "throw", ReferenceType.none, Format.Format11x, Opcode.CAN_THROW), THROW((short)0x27, "throw", ReferenceType.none, Format.Format11x, Opcode.CAN_THROW),
GOTO((short)0x28, "goto", ReferenceType.none, Format.Format10t), GOTO((short)0x28, "goto", ReferenceType.none, Format.Format10t),
@ -110,44 +110,44 @@ public enum Opcode
APUT_BYTE((short)0x4f, "aput-byte", ReferenceType.none, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), APUT_BYTE((short)0x4f, "aput-byte", ReferenceType.none, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
APUT_CHAR((short)0x50, "aput-char", ReferenceType.none, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), APUT_CHAR((short)0x50, "aput-char", ReferenceType.none, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
APUT_SHORT((short)0x51, "aput-short", ReferenceType.none, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), APUT_SHORT((short)0x51, "aput-short", ReferenceType.none, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
IGET((short)0x52, "iget", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), IGET((short)0x52, "iget", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff06),
IGET_WIDE((short)0x53, "iget-wide", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), IGET_WIDE((short)0x53, "iget-wide", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER, (short)0xff07),
IGET_OBJECT((short)0x54, "iget-object", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), IGET_OBJECT((short)0x54, "iget-object", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff08),
IGET_BOOLEAN((short)0x55, "iget-boolean", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), IGET_BOOLEAN((short)0x55, "iget-boolean", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff09),
IGET_BYTE((short)0x56, "iget-byte", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), IGET_BYTE((short)0x56, "iget-byte", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff0a),
IGET_CHAR((short)0x57, "iget-char", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), IGET_CHAR((short)0x57, "iget-char", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff0b),
IGET_SHORT((short)0x58, "iget-short", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), IGET_SHORT((short)0x58, "iget-short", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff0c),
IPUT((short)0x59, "iput", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), IPUT((short)0x59, "iput", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff0d),
IPUT_WIDE((short)0x5a, "iput-wide", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), IPUT_WIDE((short)0x5a, "iput-wide", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff0e),
IPUT_OBJECT((short)0x5b, "iput-object", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), IPUT_OBJECT((short)0x5b, "iput-object", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff0f),
IPUT_BOOLEAN((short)0x5c, "iput-boolean", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), IPUT_BOOLEAN((short)0x5c, "iput-boolean", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff10),
IPUT_BYTE((short)0x5d, "iput-byte", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), IPUT_BYTE((short)0x5d, "iput-byte", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff11),
IPUT_CHAR((short)0x5e, "iput-char", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), IPUT_CHAR((short)0x5e, "iput-char", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff12),
IPUT_SHORT((short)0x5f, "iput-short", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), IPUT_SHORT((short)0x5f, "iput-short", ReferenceType.field, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff13),
SGET((short)0x60, "sget", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), SGET((short)0x60, "sget", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff14),
SGET_WIDE((short)0x61, "sget-wide", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), SGET_WIDE((short)0x61, "sget-wide", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER, (short)0xff15),
SGET_OBJECT((short)0x62, "sget-object", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), SGET_OBJECT((short)0x62, "sget-object", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff16),
SGET_BOOLEAN((short)0x63, "sget-boolean", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), SGET_BOOLEAN((short)0x63, "sget-boolean", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff17),
SGET_BYTE((short)0x64, "sget-byte", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), SGET_BYTE((short)0x64, "sget-byte", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff18),
SGET_CHAR((short)0x65, "sget-char", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), SGET_CHAR((short)0x65, "sget-char", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff19),
SGET_SHORT((short)0x66, "sget-short", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), SGET_SHORT((short)0x66, "sget-short", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0xff1a),
SPUT((short)0x67, "sput", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), SPUT((short)0x67, "sput", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff1b),
SPUT_WIDE((short)0x68, "sput-wide", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), SPUT_WIDE((short)0x68, "sput-wide", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff1c),
SPUT_OBJECT((short)0x69, "sput-object", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), SPUT_OBJECT((short)0x69, "sput-object", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff1d),
SPUT_BOOLEAN((short)0x6a, "sput-boolean", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), SPUT_BOOLEAN((short)0x6a, "sput-boolean", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff1e),
SPUT_BYTE((short)0x6b, "sput-byte", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), SPUT_BYTE((short)0x6b, "sput-byte", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff1f),
SPUT_CHAR((short)0x6c, "sput-char", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), SPUT_CHAR((short)0x6c, "sput-char", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff20),
SPUT_SHORT((short)0x6d, "sput-short", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE), SPUT_SHORT((short)0x6d, "sput-short", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE, (short)0xff21),
INVOKE_VIRTUAL((short)0x6e, "invoke-virtual", ReferenceType.method, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_VIRTUAL((short)0x6e, "invoke-virtual", ReferenceType.method, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
INVOKE_SUPER((short)0x6f, "invoke-super", ReferenceType.method, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_SUPER((short)0x6f, "invoke-super", ReferenceType.method, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
INVOKE_DIRECT((short)0x70, "invoke-direct", ReferenceType.method, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.CAN_INITIALIZE_REFERENCE), INVOKE_DIRECT((short)0x70, "invoke-direct", ReferenceType.method, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.CAN_INITIALIZE_REFERENCE),
INVOKE_STATIC((short)0x71, "invoke-static", ReferenceType.method, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_STATIC((short)0x71, "invoke-static", ReferenceType.method, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
INVOKE_INTERFACE((short)0x72, "invoke-interface", ReferenceType.method, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_INTERFACE((short)0x72, "invoke-interface", ReferenceType.method, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
INVOKE_VIRTUAL_RANGE((short)0x74, "invoke-virtual/range", ReferenceType.method, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_VIRTUAL_RANGE((short)0x74, "invoke-virtual/range", ReferenceType.method, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT, (short)0xff22),
INVOKE_SUPER_RANGE((short)0x75, "invoke-super/range", ReferenceType.method, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_SUPER_RANGE((short)0x75, "invoke-super/range", ReferenceType.method, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT, (short)0xff23),
INVOKE_DIRECT_RANGE((short)0x76, "invoke-direct/range", ReferenceType.method, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.CAN_INITIALIZE_REFERENCE), INVOKE_DIRECT_RANGE((short)0x76, "invoke-direct/range", ReferenceType.method, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.CAN_INITIALIZE_REFERENCE, (short)0xff24),
INVOKE_STATIC_RANGE((short)0x77, "invoke-static/range", ReferenceType.method, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_STATIC_RANGE((short)0x77, "invoke-static/range", ReferenceType.method, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT, (short)0xff25),
INVOKE_INTERFACE_RANGE((short)0x78, "invoke-interface/range", ReferenceType.method, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_INTERFACE_RANGE((short)0x78, "invoke-interface/range", ReferenceType.method, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT, (short)0xff26),
NEG_INT((short)0x7b, "neg-int", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), NEG_INT((short)0x7b, "neg-int", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
NOT_INT((short)0x7c, "not-int", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), NOT_INT((short)0x7c, "not-int", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
NEG_LONG((short)0x7d, "neg-long", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), NEG_LONG((short)0x7d, "neg-long", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
@ -282,7 +282,61 @@ public enum Opcode
IPUT_OBJECT_VOLATILE((short)0xfc, "iput-object-volatile", ReferenceType.field, Format.Format22c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE), IPUT_OBJECT_VOLATILE((short)0xfc, "iput-object-volatile", ReferenceType.field, Format.Format22c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
SGET_OBJECT_VOLATILE((short)0xfd, "sget-object-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), SGET_OBJECT_VOLATILE((short)0xfd, "sget-object-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
SPUT_OBJECT_VOLATILE((short)0xfe, "sput-object-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE); SPUT_OBJECT_VOLATILE((short)0xfe, "sput-object-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
CONST_CLASS_JUMBO((short)0xff00, "const-class/jumbo", ReferenceType.type, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
CHECK_CAST_JUMBO((short)0xff01, "check-cast/jumbo", ReferenceType.type, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
INSTANCE_OF_JUMBO((short)0xff02, "instance-of/jumbo", ReferenceType.type, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
NEW_INSTANCE_JUMBO((short)0xff03, "new-instance/jumbo", ReferenceType.type, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
NEW_ARRAY_JUMBO((short)0xff04, "new-array/jumbo", ReferenceType.type, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
FILLED_NEW_ARRAY_JUMBO((short)0xff05, "filled-new-array/jumbo", ReferenceType.type, Format.Format5rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.JUMBO_OPCODE),
IGET_JUMBO((short)0xff06, "iget/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
IGET_WIDE_JUMBO((short)0xff07, "iget-wide/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER | Opcode.JUMBO_OPCODE),
IGET_OBJECT_JUMBO((short)0xff08, "iget-object/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
IGET_BOOLEAN_JUMBO((short)0xff09, "iget-boolean/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
IGET_BYTE_JUMBO((short)0xff0a, "iget-byte/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
IGET_CHAR_JUMBO((short)0xff0b, "iget-char/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
IGET_SHORT_JUMBO((short)0xff0c, "iget-short/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
IPUT_JUMBO((short)0xff0d, "iput/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
IPUT_WIDE_JUMBO((short)0xff0e, "iput-wide/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
IPUT_OBJECT_JUMBO((short)0xff0f, "iput-object/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
IPUT_BOOLEAN_JUMBO((short)0xff10, "iput-boolean/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
IPUT_BYTE_JUMBO((short)0xff11, "iput-byte/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
IPUT_CHAR_JUMBO((short)0xff12, "iput-char/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
IPUT_SHORT_JUMBO((short)0xff13, "iput-short/jumbo", ReferenceType.field, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
SGET_JUMBO((short)0xff14, "sget/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
SGET_WIDE_JUMBO((short)0xff15, "sget-wide/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER | Opcode.JUMBO_OPCODE),
SGET_OBJECT_JUMBO((short)0xff16, "sget-object/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
SGET_BOOLEAN_JUMBO((short)0xff17, "sget-boolean/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
SGET_BYTE_JUMBO((short)0xff18, "sget-byte/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
SGET_CHAR_JUMBO((short)0xff19, "sget-char/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
SGET_SHORT_JUMBO((short)0xff1a, "sget-short/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
SPUT_JUMBO((short)0xff1b, "sput/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
SPUT_WIDE_JUMBO((short)0xff1c, "sput-wide/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
SPUT_OBJECT_JUMBO((short)0xff1d, "sput-object/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
SPUT_BOOLEAN_JUMBO((short)0xff1e, "sput-boolean/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
SPUT_BYTE_JUMBO((short)0xff1f, "sput-byte/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
SPUT_CHAR_JUMBO((short)0xff20, "sput-char/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
SPUT_SHORT_JUMBO((short)0xff21, "sput-short/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
INVOKE_VIRTUAL_JUMBO((short)0xff22, "invoke-virtual/jumbo", ReferenceType.method, Format.Format5rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.JUMBO_OPCODE),
INVOKE_SUPER_JUMBO((short)0xff23, "invoke-super/jumbo", ReferenceType.method, Format.Format5rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.JUMBO_OPCODE),
INVOKE_DIRECT_JUMBO((short)0xff24, "invoke-direct/jumbo", ReferenceType.method, Format.Format5rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.JUMBO_OPCODE | Opcode.CAN_INITIALIZE_REFERENCE),
INVOKE_STATIC_JUMBO((short)0xff25, "invoke-static/jumbo", ReferenceType.method, Format.Format5rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.JUMBO_OPCODE),
INVOKE_INTERFACE_JUMBO((short)0xff26, "invoke-interface/jumbo", ReferenceType.method, Format.Format5rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.JUMBO_OPCODE),
INVOKE_OBJECT_INIT_JUMBO((short)0xfff2, "invoke-object-init/jumbo", ReferenceType.method, Format.Format5rc, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.JUMBO_OPCODE | Opcode.CAN_INITIALIZE_REFERENCE),
IGET_VOLATILE_JUMBO((short)0xfff3, "iget-volatile/jumbo", ReferenceType.field, Format.Format52c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
IGET_WIDE_VOLATILE_JUMBO((short)0xfff4, "iget-wide-volatile/jumbo", ReferenceType.field, Format.Format52c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER | Opcode.JUMBO_OPCODE),
IGET_OBJECT_VOLATILE_JUMBO((short)0xfff5, "iget-object-volatile/jumbo", ReferenceType.field, Format.Format52c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
IPUT_VOLATILE_JUMBO((short)0xfff6, "iput-volatile/jumbo", ReferenceType.field, Format.Format52c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
IPUT_WIDE_VOLATILE_JUMBO((short)0xfff7, "iput-wide-volatile/jumbo", ReferenceType.field, Format.Format52c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
IPUT_OBJECT_VOLATILE_JUMBO((short)0xfff8, "iput-object-volatile/jumbo", ReferenceType.field, Format.Format52c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
SGET_VOLATILE_JUMBO((short)0xfff9, "sget-volatile/jumbo", ReferenceType.field, Format.Format41c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
SGET_WIDE_VOLATILE_JUMBO((short)0xfffa, "sget-wide-volatile/jumbo", ReferenceType.field, Format.Format41c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER | Opcode.JUMBO_OPCODE),
SGET_OBJECT_VOLATILE_JUMBO((short)0xfffb, "sget-object-volatile/jumbo", ReferenceType.field, Format.Format41c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.JUMBO_OPCODE),
SPUT_VOLATILE_JUMBO((short)0xfffc, "sput-volatile/jumbo", ReferenceType.field, Format.Format41c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
SPUT_WIDE_VOLATILE_JUMBO((short)0xfffd, "sput-wide-volatile/jumbo", ReferenceType.field, Format.Format41c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE),
SPUT_OBJECT_VOLATILE_JUMBO((short)0xfffe, "sput-object-volatile/jumbo", ReferenceType.field, Format.Format41c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.JUMBO_OPCODE);
private static Opcode[] opcodesByValue; private static Opcode[] opcodesByValue;
private static Opcode[] expandedOpcodesByValue; private static Opcode[] expandedOpcodesByValue;
@ -372,7 +426,7 @@ public enum Opcode
* based on the idiosyncrasies of that api level * based on the idiosyncrasies of that api level
* @param apiLevel * @param apiLevel
*/ */
public static void updateMapsForApiLevel(int apiLevel) { public static void updateMapsForApiLevel(int apiLevel, boolean includeJumbo) {
if (apiLevel < 5) { if (apiLevel < 5) {
removeOpcodes(THROW_VERIFICATION_ERROR); removeOpcodes(THROW_VERIFICATION_ERROR);
} }
@ -391,6 +445,21 @@ public enum Opcode
removeOpcodes(INVOKE_OBJECT_INIT_RANGE); removeOpcodes(INVOKE_OBJECT_INIT_RANGE);
addOpcodes(INVOKE_DIRECT_EMPTY); addOpcodes(INVOKE_DIRECT_EMPTY);
} }
if (apiLevel < 14 || !includeJumbo) {
removeOpcodes(CONST_CLASS_JUMBO, CHECK_CAST_JUMBO, INSTANCE_OF_JUMBO, NEW_INSTANCE_JUMBO,
NEW_ARRAY_JUMBO, FILLED_NEW_ARRAY_JUMBO, IGET_JUMBO, IGET_WIDE_JUMBO, IGET_OBJECT_JUMBO,
IGET_BOOLEAN_JUMBO, IGET_BYTE_JUMBO, IGET_CHAR_JUMBO, IGET_SHORT_JUMBO, IPUT_JUMBO, IPUT_WIDE_JUMBO,
IPUT_OBJECT_JUMBO, IPUT_BOOLEAN_JUMBO, IPUT_BYTE_JUMBO, IPUT_CHAR_JUMBO, IPUT_SHORT_JUMBO,
SGET_JUMBO, SGET_WIDE_JUMBO, SGET_OBJECT_JUMBO, SGET_BOOLEAN_JUMBO, SGET_BYTE_JUMBO,
SGET_CHAR_JUMBO, SGET_SHORT_JUMBO, SPUT_JUMBO, SPUT_WIDE_JUMBO, SPUT_OBJECT_JUMBO,
SPUT_BOOLEAN_JUMBO, SPUT_BYTE_JUMBO, SPUT_CHAR_JUMBO, SPUT_SHORT_JUMBO, INVOKE_VIRTUAL_JUMBO,
INVOKE_SUPER_JUMBO, INVOKE_DIRECT_JUMBO, INVOKE_STATIC_JUMBO, INVOKE_INTERFACE_JUMBO,
INVOKE_OBJECT_INIT_JUMBO, IGET_VOLATILE_JUMBO, IGET_WIDE_VOLATILE_JUMBO,
IGET_OBJECT_VOLATILE_JUMBO, IPUT_VOLATILE_JUMBO, IPUT_WIDE_VOLATILE_JUMBO,
IPUT_OBJECT_VOLATILE_JUMBO, SGET_VOLATILE_JUMBO, SGET_WIDE_VOLATILE_JUMBO,
SGET_OBJECT_VOLATILE_JUMBO, SPUT_VOLATILE_JUMBO, SPUT_WIDE_VOLATILE_JUMBO,
SPUT_OBJECT_VOLATILE_JUMBO);
}
} }
public final short value; public final short value;

View File

@ -253,7 +253,13 @@ tokens {
I_STATEMENT_FORMAT35c_TYPE; I_STATEMENT_FORMAT35c_TYPE;
I_STATEMENT_FORMAT3rc_METHOD; I_STATEMENT_FORMAT3rc_METHOD;
I_STATEMENT_FORMAT3rc_TYPE; I_STATEMENT_FORMAT3rc_TYPE;
I_STATEMENT_FORMAT41c_TYPE;
I_STATEMENT_FORMAT41c_FIELD;
I_STATEMENT_FORMAT51l; I_STATEMENT_FORMAT51l;
I_STATEMENT_FORMAT52c_TYPE;
I_STATEMENT_FORMAT52c_FIELD;
I_STATEMENT_FORMAT5rc_METHOD;
I_STATEMENT_FORMAT5rc_TYPE;
I_STATEMENT_ARRAY_DATA; I_STATEMENT_ARRAY_DATA;
I_STATEMENT_PACKED_SWITCH; I_STATEMENT_PACKED_SWITCH;
I_STATEMENT_SPARSE_SWITCH; I_STATEMENT_SPARSE_SWITCH;
@ -858,7 +864,16 @@ instruction returns [int size]
| insn_format3rc_type { $size = $insn_format3rc_type.size; } | insn_format3rc_type { $size = $insn_format3rc_type.size; }
| insn_format3rmi_method { $size = $insn_format3rmi_method.size; } | insn_format3rmi_method { $size = $insn_format3rmi_method.size; }
| insn_format3rms_method { $size = $insn_format3rms_method.size; } | insn_format3rms_method { $size = $insn_format3rms_method.size; }
| insn_format41c_type { $size = $insn_format41c_type.size; }
| insn_format41c_field { $size = $insn_format41c_field.size; }
| insn_format41c_field_odex { $size = $insn_format41c_field_odex.size; }
| insn_format51l { $size = $insn_format51l.size; } | insn_format51l { $size = $insn_format51l.size; }
| insn_format52c_type { $size = $insn_format52c_type.size; }
| insn_format52c_field { $size = $insn_format52c_field.size; }
| insn_format52c_field_odex { $size = $insn_format52c_field_odex.size; }
| insn_format5rc_method { $size = $insn_format5rc_method.size; }
| insn_format5rc_method_odex { $size = $insn_format5rc_method_odex.size; }
| insn_format5rc_type { $size = $insn_format5rc_type.size; }
| insn_array_data_directive { $size = $insn_array_data_directive.size; } | insn_array_data_directive { $size = $insn_array_data_directive.size; }
| insn_packed_switch_directive { $size = $insn_packed_switch_directive.size; } | insn_packed_switch_directive { $size = $insn_packed_switch_directive.size; }
| insn_sparse_switch_directive { $size = $insn_sparse_switch_directive.size; }; | insn_sparse_switch_directive { $size = $insn_sparse_switch_directive.size; };
@ -1106,11 +1121,62 @@ insn_format3rms_method returns [int size]
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT3rms_METHOD.text); throwOdexedInstructionException(input, $INSTRUCTION_FORMAT3rms_METHOD.text);
}; };
insn_format41c_type returns [int size]
: //e.g. const-class/jumbo v2, Lorg/jf/HelloWorld2/HelloWorld2;
INSTRUCTION_FORMAT41c_TYPE REGISTER COMMA reference_type_descriptor {$size = Format.Format41c.size;}
-> ^(I_STATEMENT_FORMAT41c_TYPE[$start, "I_STATEMENT_FORMAT41c"] INSTRUCTION_FORMAT41c_TYPE REGISTER reference_type_descriptor);
insn_format41c_field returns [int size]
: //e.g. sget-object/jumbo v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
INSTRUCTION_FORMAT41c_FIELD REGISTER COMMA fully_qualified_field {$size = Format.Format41c.size;}
-> ^(I_STATEMENT_FORMAT41c_FIELD[$start, "I_STATEMENT_FORMAT41c_FIELD"] INSTRUCTION_FORMAT41c_FIELD REGISTER fully_qualified_field);
insn_format41c_field_odex returns [int size]
: //e.g. sget-object-volatile/jumbo v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
INSTRUCTION_FORMAT41c_FIELD_ODEX REGISTER COMMA fully_qualified_field {$size = Format.Format41c.size;}
{
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT41c_FIELD_ODEX.text);
};
insn_format51l returns [int size] insn_format51l returns [int size]
: //e.g. const-wide v0, 5000000000L : //e.g. const-wide v0, 5000000000L
INSTRUCTION_FORMAT51l REGISTER COMMA fixed_literal {$size = Format.Format51l.size;} INSTRUCTION_FORMAT51l REGISTER COMMA fixed_literal {$size = Format.Format51l.size;}
-> ^(I_STATEMENT_FORMAT51l[$start, "I_STATEMENT_FORMAT51l"] INSTRUCTION_FORMAT51l REGISTER fixed_literal); -> ^(I_STATEMENT_FORMAT51l[$start, "I_STATEMENT_FORMAT51l"] INSTRUCTION_FORMAT51l REGISTER fixed_literal);
insn_format52c_type returns [int size]
: //e.g. instance-of/jumbo v0, v1, Ljava/lang/String;
INSTRUCTION_FORMAT52c_TYPE REGISTER COMMA REGISTER COMMA nonvoid_type_descriptor {$size = Format.Format52c.size;}
-> ^(I_STATEMENT_FORMAT52c_TYPE[$start, "I_STATEMENT_FORMAT52c_TYPE"] INSTRUCTION_FORMAT52c_TYPE REGISTER REGISTER nonvoid_type_descriptor);
insn_format52c_field returns [int size]
: //e.g. iput-object/jumbo v1, v0 Lorg/jf/HelloWorld2/HelloWorld2;->helloWorld:Ljava/lang/String;
INSTRUCTION_FORMAT52c_FIELD REGISTER COMMA REGISTER COMMA fully_qualified_field {$size = Format.Format52c.size;}
-> ^(I_STATEMENT_FORMAT52c_FIELD[$start, "I_STATEMENT_FORMAT52c_FIELD"] INSTRUCTION_FORMAT52c_FIELD REGISTER REGISTER fully_qualified_field);
insn_format52c_field_odex returns [int size]
: //e.g. iput-object-volatile/jumbo v1, v0 Lorg/jf/HelloWorld2/HelloWorld2;->helloWorld:Ljava/lang/String;
INSTRUCTION_FORMAT52c_FIELD_ODEX REGISTER COMMA REGISTER COMMA fully_qualified_field {$size = Format.Format52c.size;}
{
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT52c_FIELD_ODEX.text);
};
insn_format5rc_method returns [int size]
: //e.g. invoke-virtual/jumbo {v25..v26}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
INSTRUCTION_FORMAT5rc_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA fully_qualified_method {$size = Format.Format5rc.size;}
-> ^(I_STATEMENT_FORMAT5rc_METHOD[$start, "I_STATEMENT_FORMAT5rc_METHOD"] INSTRUCTION_FORMAT5rc_METHOD register_range fully_qualified_method);
insn_format5rc_method_odex returns [int size]
: //e.g. invoke-object-init/jumbo {v25}, Ljava/lang/Object-><init>()V
INSTRUCTION_FORMAT5rc_METHOD_ODEX OPEN_BRACE register_range CLOSE_BRACE COMMA fully_qualified_method {$size = Format.Format5rc.size;}
{
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT5rc_METHOD_ODEX.text);
};
insn_format5rc_type returns [int size]
: //e.g. filled-new-array/jumbo {v0..v6}, I
INSTRUCTION_FORMAT5rc_TYPE OPEN_BRACE register_range CLOSE_BRACE COMMA nonvoid_type_descriptor {$size = Format.Format5rc.size;}
-> ^(I_STATEMENT_FORMAT5rc_TYPE[$start, "I_STATEMENT_FORMAT5rc_TYPE"] INSTRUCTION_FORMAT5rc_TYPE register_range nonvoid_type_descriptor);
insn_array_data_directive returns [int size] insn_array_data_directive returns [int size]
@init {boolean needsNop = false;} @init {boolean needsNop = false;}
: ARRAY_DATA_DIRECTIVE : ARRAY_DATA_DIRECTIVE

View File

@ -938,7 +938,13 @@ instruction[int totalMethodRegisters, int methodParameterRegisters, List<Instruc
| insn_format35c_type[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format35c_type.outRegisters; } | insn_format35c_type[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format35c_type.outRegisters; }
| insn_format3rc_method[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format3rc_method.outRegisters; } | insn_format3rc_method[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format3rc_method.outRegisters; }
| insn_format3rc_type[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format3rc_type.outRegisters; } | insn_format3rc_type[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format3rc_type.outRegisters; }
| insn_format41c_type[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format41c_type.outRegisters; }
| insn_format41c_field[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format41c_field.outRegisters; }
| insn_format51l_type[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format51l_type.outRegisters; } | insn_format51l_type[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format51l_type.outRegisters; }
| insn_format52c_type[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format52c_type.outRegisters; }
| insn_format52c_field[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format52c_field.outRegisters; }
| insn_format5rc_method[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format5rc_method.outRegisters; }
| insn_format5rc_type[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format5rc_type.outRegisters; }
| insn_array_data_directive[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_array_data_directive.outRegisters; } | insn_array_data_directive[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_array_data_directive.outRegisters; }
| insn_packed_switch_directive[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_packed_switch_directive.outRegisters; } | insn_packed_switch_directive[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_packed_switch_directive.outRegisters; }
| insn_sparse_switch_directive[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_sparse_switch_directive.outRegisters; }; | insn_sparse_switch_directive[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_sparse_switch_directive.outRegisters; };
@ -1320,6 +1326,30 @@ insn_format3rc_type[int totalMethodRegisters, int methodParameterRegisters, List
$instructions.add(new Instruction3rc(opcode, (short)registerCount, startRegister, typeIdItem)); $instructions.add(new Instruction3rc(opcode, (short)registerCount, startRegister, typeIdItem));
}; };
insn_format41c_type[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
: //e.g. const-class/jumbo v2, org/jf/HelloWorld2/HelloWorld2
^(I_STATEMENT_FORMAT41c_TYPE INSTRUCTION_FORMAT41c_TYPE REGISTER reference_type_descriptor)
{
Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT41c_TYPE.text);
int regA = parseRegister_short($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters);
TypeIdItem typeIdItem = $reference_type_descriptor.type;
$instructions.add(new Instruction41c(opcode, regA, typeIdItem));
};
insn_format41c_field[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
: //e.g. sget-object/jumbo v0, Ljava/lang/System;->out:LJava/io/PrintStream;
^(I_STATEMENT_FORMAT41c_FIELD INSTRUCTION_FORMAT41c_FIELD REGISTER fully_qualified_field)
{
Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT41c_FIELD.text);
int regA = parseRegister_short($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters);
FieldIdItem fieldIdItem = $fully_qualified_field.fieldIdItem;
$instructions.add(new Instruction41c(opcode, regA, fieldIdItem));
};
insn_format51l_type[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] insn_format51l_type[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
: //e.g. const-wide v0, 5000000000L : //e.g. const-wide v0, 5000000000L
^(I_STATEMENT_FORMAT51l INSTRUCTION_FORMAT51l REGISTER fixed_64bit_literal) ^(I_STATEMENT_FORMAT51l INSTRUCTION_FORMAT51l REGISTER fixed_64bit_literal)
@ -1332,6 +1362,64 @@ insn_format51l_type[int totalMethodRegisters, int methodParameterRegisters, List
$instructions.add(new Instruction51l(opcode, regA, litB)); $instructions.add(new Instruction51l(opcode, regA, litB));
}; };
insn_format52c_type[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
: //e.g. instance-of/jumbo v0, v1, Ljava/lang/String;
^(I_STATEMENT_FORMAT52c_TYPE INSTRUCTION_FORMAT52c_TYPE registerA=REGISTER registerB=REGISTER nonvoid_type_descriptor)
{
Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT52c_TYPE.text);
int regA = parseRegister_short($registerA.text, $totalMethodRegisters, $methodParameterRegisters);
int regB = parseRegister_short($registerB.text, $totalMethodRegisters, $methodParameterRegisters);
TypeIdItem typeIdItem = $nonvoid_type_descriptor.type;
$instructions.add(new Instruction52c(opcode, regA, regB, typeIdItem));
};
insn_format52c_field[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
: //e.g. iput-object/jumbo v1, v0, Lorg/jf/HelloWorld2/HelloWorld2;->helloWorld:Ljava/lang/String;
^(I_STATEMENT_FORMAT52c_FIELD INSTRUCTION_FORMAT52c_FIELD registerA=REGISTER registerB=REGISTER fully_qualified_field)
{
Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT52c_FIELD.text);
int regA = parseRegister_short($registerA.text, $totalMethodRegisters, $methodParameterRegisters);
int regB = parseRegister_short($registerB.text, $totalMethodRegisters, $methodParameterRegisters);
FieldIdItem fieldIdItem = $fully_qualified_field.fieldIdItem;
$instructions.add(new Instruction52c(opcode, regA, regB, fieldIdItem));
};
insn_format5rc_method[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
: //e.g. invoke-virtual/jumbo {v25..v26} java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder;
^(I_STATEMENT_FORMAT5rc_METHOD INSTRUCTION_FORMAT5rc_METHOD register_range[$totalMethodRegisters, $methodParameterRegisters] fully_qualified_method)
{
Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT5rc_METHOD.text);
int startRegister = $register_range.startRegister;
int endRegister = $register_range.endRegister;
int registerCount = endRegister-startRegister+1;
$outRegisters = registerCount;
MethodIdItem methodIdItem = $fully_qualified_method.methodIdItem;
$instructions.add(new Instruction5rc(opcode, registerCount, startRegister, methodIdItem));
};
insn_format5rc_type[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
: //e.g. filled-new-array/jumbo {v0..v6} I
^(I_STATEMENT_FORMAT5rc_TYPE INSTRUCTION_FORMAT5rc_TYPE register_range[$totalMethodRegisters, $methodParameterRegisters] nonvoid_type_descriptor)
{
Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT5rc_TYPE.text);
int startRegister = $register_range.startRegister;
int endRegister = $register_range.endRegister;
int registerCount = endRegister-startRegister+1;
$outRegisters = registerCount;
TypeIdItem typeIdItem = $nonvoid_type_descriptor.type;
$instructions.add(new Instruction5rc(opcode, registerCount, startRegister, typeIdItem));
};
insn_array_data_directive[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] insn_array_data_directive[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
: //e.g. .array-data 4 1000000 .end array-data : //e.g. .array-data 4 1000000 .end array-data
^(I_STATEMENT_ARRAY_DATA ^(I_ARRAY_ELEMENT_SIZE short_integral_literal) array_elements) ^(I_STATEMENT_ARRAY_DATA ^(I_ARRAY_ELEMENT_SIZE short_integral_literal) array_elements)

View File

@ -100,7 +100,7 @@ public class main {
boolean allowOdex = false; boolean allowOdex = false;
boolean sort = false; boolean sort = false;
boolean fixJumbo = true; boolean jumboInstructions = false;
boolean fixGoto = true; boolean fixGoto = true;
boolean verboseErrors = false; boolean verboseErrors = false;
boolean printTokens = false; boolean printTokens = false;
@ -149,7 +149,7 @@ public class main {
sort = true; sort = true;
break; break;
case 'J': case 'J':
fixJumbo = false; jumboInstructions = true;
break; break;
case 'G': case 'G':
fixGoto = false; fixGoto = false;
@ -187,7 +187,7 @@ public class main {
} }
} }
Opcode.updateMapsForApiLevel(apiLevel); Opcode.updateMapsForApiLevel(apiLevel, jumboInstructions);
DexFile dexFile = new DexFile(); DexFile dexFile = new DexFile();
@ -212,8 +212,8 @@ public class main {
dexFile.setSortAllItems(true); dexFile.setSortAllItems(true);
} }
if (fixJumbo || fixGoto) { if (fixGoto) {
fixInstructions(dexFile, fixJumbo, fixGoto); fixInstructions(dexFile, true, fixGoto);
} }
dexFile.place(); dexFile.place();
@ -399,8 +399,11 @@ public class main {
.withDescription("sort the items in the dex file into a canonical order before writing") .withDescription("sort the items in the dex file into a canonical order before writing")
.create("S"); .create("S");
Option noFixJumboOption = OptionBuilder.withLongOpt("no-fix-jumbo") Option jumboInstructionsOption = OptionBuilder.withLongOpt("jumbo-instructions")
.withDescription("Don't automatically instructions with the /jumbo variant where appropriate") .withDescription("adds support for the jumbo opcodes that were temporarily available around the" +
" ics timeframe. Note that support for these opcodes was removed from newer version of" +
" dalvik. You shouldn't use this option unless you know the dex file will only be used on a" +
" device that supports these opcodes.")
.create("J"); .create("J");
Option noFixGotoOption = OptionBuilder.withLongOpt("no-fix-goto") Option noFixGotoOption = OptionBuilder.withLongOpt("no-fix-goto")
@ -423,7 +426,7 @@ public class main {
debugOptions.addOption(dumpOption); debugOptions.addOption(dumpOption);
debugOptions.addOption(sortOption); debugOptions.addOption(sortOption);
debugOptions.addOption(noFixJumboOption); debugOptions.addOption(jumboInstructionsOption);
debugOptions.addOption(noFixGotoOption); debugOptions.addOption(noFixGotoOption);
debugOptions.addOption(verboseErrorsOption); debugOptions.addOption(verboseErrorsOption);
debugOptions.addOption(printTokensOption); debugOptions.addOption(printTokensOption);

View File

@ -574,9 +574,52 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayDescriptor}
return newToken(INSTRUCTION_FORMAT3rms_METHOD); return newToken(INSTRUCTION_FORMAT3rms_METHOD);
} }
"check-cast/jumbo" | "new-instance/jumbo" | "const-class/jumbo" {
return newToken(INSTRUCTION_FORMAT41c_TYPE);
}
"sget/jumbo" | "sget-wide/jumbo" | "sget-object/jumbo" | "sget-boolean/jumbo" | "sget-byte/jumbo" |
"sget-char/jumbo" | "sget-short/jumbo" | "sput/jumbo" | "sput-wide/jumbo" | "sput-object/jumbo" |
"sput-boolean/jumbo" | "sput-byte/jumbo" | "sput-char/jumbo" | "sput-short/jumbo" {
return newToken(INSTRUCTION_FORMAT41c_FIELD);
}
"sget-volatile/jumbo" | "sget-wide-volatile/jumbo" | "sget-object-volatile/jumbo" | "sput-volatile/jumbo" |
"sput-wide-volatile/jumbo" | "sput-object-volatile/jumbo" {
return newToken(INSTRUCTION_FORMAT41c_FIELD_ODEX);
}
"const-wide" { "const-wide" {
return newToken(INSTRUCTION_FORMAT51l); return newToken(INSTRUCTION_FORMAT51l);
} }
"instance-of/jumbo" | "new-array/jumbo" {
return newToken(INSTRUCTION_FORMAT52c_TYPE);
}
"iget/jumbo" | "iget-wide/jumbo" | "iget-object/jumbo" | "iget-boolean/jumbo" | "iget-byte/jumbo" |
"iget-char/jumbo" | "iget-short/jumbo" | "iput/jumbo" | "iput-wide/jumbo" | "iput-object/jumbo" |
"iput-boolean/jumbo" | "iput-byte/jumbo" | "iput-char/jumbo" | "iput-short/jumbo" {
return newToken(INSTRUCTION_FORMAT52c_FIELD);
}
"iget-volatile/jumbo" | "iget-wide-volatile/jumbo" | "iget-object-volatile/jumbo" | "iput-volatile/jumbo" |
"iput-wide-volatile/jumbo" | "iput-object-volatile/jumbo" {
return newToken(INSTRUCTION_FORMAT52c_FIELD_ODEX);
}
"invoke-virtual/jumbo" | "invoke-super/jumbo" | "invoke-direct/jumbo" | "invoke-static/jumbo" |
"invoke-interface/jumbo" {
return newToken(INSTRUCTION_FORMAT5rc_METHOD);
}
"invoke-object-init/jumbo" {
return newToken(INSTRUCTION_FORMAT5rc_METHOD_ODEX);
}
"filled-new-array/jumbo" {
return newToken(INSTRUCTION_FORMAT5rc_TYPE);
}
} }
/*Types*/ /*Types*/

View File

@ -1 +1 @@
application.version=1.4.0 application.version=1.4.1

View File

@ -0,0 +1,2 @@
# Prevent newlines from being normalized on windows
*.smali -text

View File

@ -225,4 +225,56 @@ filled-new-array/range
execute-inline/range execute-inline/range
invoke-virtual-quick/range invoke-virtual-quick/range
invoke-super-quick/range invoke-super-quick/range
check-cast/jumbo
new-instance/jumbo
const-class/jumbo
sget/jumbo
sget-wide/jumbo
sget-object/jumbo
sget-boolean/jumbo
sget-byte/jumbo
sget-char/jumbo
sget-short/jumbo
sput/jumbo
sput-wide/jumbo
sput-object/jumbo
sput-boolean/jumbo
sput-byte/jumbo
sput-char/jumbo
sput-short/jumbo
const-wide const-wide
instance-of/jumbo
new-array/jumbo
iget/jumbo
iget-wide/jumbo
iget-object/jumbo
iget-boolean/jumbo
iget-byte/jumbo
iget-char/jumbo
iget-short/jumbo
iput/jumbo
iput-wide/jumbo
iput-object/jumbo
iput-boolean/jumbo
iput-byte/jumbo
iput-char/jumbo
iput-short/jumbo
invoke-virtual/jumbo
invoke-super/jumbo
invoke-direct/jumbo
invoke-static/jumbo
invoke-interface/jumbo
filled-new-array/jumbo
invoke-object-init/jumbo
iget-volatile/jumbo
iget-wide-volatile/jumbo
iget-object-volatile/jumbo
iput-volatile/jumbo
iput-wide-volatile/jumbo
iput-object-volatile/jumbo
sget-volatile/jumbo
sget-wide-volatile/jumbo
sget-object-volatile/jumbo
sput-volatile/jumbo
sput-wide-volatile/jumbo
sput-object-volatile/jumbo

View File

@ -225,4 +225,56 @@ INSTRUCTION_FORMAT3rc_TYPE("filled-new-array/range")
INSTRUCTION_FORMAT3rmi_METHOD("execute-inline/range") INSTRUCTION_FORMAT3rmi_METHOD("execute-inline/range")
INSTRUCTION_FORMAT3rms_METHOD("invoke-virtual-quick/range") INSTRUCTION_FORMAT3rms_METHOD("invoke-virtual-quick/range")
INSTRUCTION_FORMAT3rms_METHOD("invoke-super-quick/range") INSTRUCTION_FORMAT3rms_METHOD("invoke-super-quick/range")
INSTRUCTION_FORMAT51l("const-wide") INSTRUCTION_FORMAT41c_TYPE("check-cast/jumbo")
INSTRUCTION_FORMAT41c_TYPE("new-instance/jumbo")
INSTRUCTION_FORMAT41c_TYPE("const-class/jumbo")
INSTRUCTION_FORMAT41c_FIELD("sget/jumbo")
INSTRUCTION_FORMAT41c_FIELD("sget-wide/jumbo")
INSTRUCTION_FORMAT41c_FIELD("sget-object/jumbo")
INSTRUCTION_FORMAT41c_FIELD("sget-boolean/jumbo")
INSTRUCTION_FORMAT41c_FIELD("sget-byte/jumbo")
INSTRUCTION_FORMAT41c_FIELD("sget-char/jumbo")
INSTRUCTION_FORMAT41c_FIELD("sget-short/jumbo")
INSTRUCTION_FORMAT41c_FIELD("sput/jumbo")
INSTRUCTION_FORMAT41c_FIELD("sput-wide/jumbo")
INSTRUCTION_FORMAT41c_FIELD("sput-object/jumbo")
INSTRUCTION_FORMAT41c_FIELD("sput-boolean/jumbo")
INSTRUCTION_FORMAT41c_FIELD("sput-byte/jumbo")
INSTRUCTION_FORMAT41c_FIELD("sput-char/jumbo")
INSTRUCTION_FORMAT41c_FIELD("sput-short/jumbo")
INSTRUCTION_FORMAT51l("const-wide")
INSTRUCTION_FORMAT52c_TYPE("instance-of/jumbo")
INSTRUCTION_FORMAT52c_TYPE("new-array/jumbo")
INSTRUCTION_FORMAT52c_FIELD("iget/jumbo")
INSTRUCTION_FORMAT52c_FIELD("iget-wide/jumbo")
INSTRUCTION_FORMAT52c_FIELD("iget-object/jumbo")
INSTRUCTION_FORMAT52c_FIELD("iget-boolean/jumbo")
INSTRUCTION_FORMAT52c_FIELD("iget-byte/jumbo")
INSTRUCTION_FORMAT52c_FIELD("iget-char/jumbo")
INSTRUCTION_FORMAT52c_FIELD("iget-short/jumbo")
INSTRUCTION_FORMAT52c_FIELD("iput/jumbo")
INSTRUCTION_FORMAT52c_FIELD("iput-wide/jumbo")
INSTRUCTION_FORMAT52c_FIELD("iput-object/jumbo")
INSTRUCTION_FORMAT52c_FIELD("iput-boolean/jumbo")
INSTRUCTION_FORMAT52c_FIELD("iput-byte/jumbo")
INSTRUCTION_FORMAT52c_FIELD("iput-char/jumbo")
INSTRUCTION_FORMAT52c_FIELD("iput-short/jumbo")
INSTRUCTION_FORMAT5rc_METHOD("invoke-virtual/jumbo")
INSTRUCTION_FORMAT5rc_METHOD("invoke-super/jumbo")
INSTRUCTION_FORMAT5rc_METHOD("invoke-direct/jumbo")
INSTRUCTION_FORMAT5rc_METHOD("invoke-static/jumbo")
INSTRUCTION_FORMAT5rc_METHOD("invoke-interface/jumbo")
INSTRUCTION_FORMAT5rc_TYPE("filled-new-array/jumbo")
INSTRUCTION_FORMAT5rc_METHOD_ODEX("invoke-object-init/jumbo")
INSTRUCTION_FORMAT52c_FIELD_ODEX("iget-volatile/jumbo")
INSTRUCTION_FORMAT52c_FIELD_ODEX("iget-wide-volatile/jumbo")
INSTRUCTION_FORMAT52c_FIELD_ODEX("iget-object-volatile/jumbo")
INSTRUCTION_FORMAT52c_FIELD_ODEX("iput-volatile/jumbo")
INSTRUCTION_FORMAT52c_FIELD_ODEX("iput-wide-volatile/jumbo")
INSTRUCTION_FORMAT52c_FIELD_ODEX("iput-object-volatile/jumbo")
INSTRUCTION_FORMAT41c_FIELD_ODEX("sget-volatile/jumbo")
INSTRUCTION_FORMAT41c_FIELD_ODEX("sget-wide-volatile/jumbo")
INSTRUCTION_FORMAT41c_FIELD_ODEX("sget-object-volatile/jumbo")
INSTRUCTION_FORMAT41c_FIELD_ODEX("sput-volatile/jumbo")
INSTRUCTION_FORMAT41c_FIELD_ODEX("sput-wide-volatile/jumbo")
INSTRUCTION_FORMAT41c_FIELD_ODEX("sput-object-volatile/jumbo")