From d4417d7269dad2c6e2f92c67c82a2ada18bb38e3 Mon Sep 17 00:00:00 2001 From: "JesusFreke@JesusFreke.com" Date: Tue, 21 Dec 2010 17:33:30 +0000 Subject: [PATCH] add support for the new odex opcodes for volatile field access that were added in gingerbread git-svn-id: https://smali.googlecode.com/svn/trunk@799 55b6fa8a-2a1e-11de-a435-ffa8d773f76a --- .../dexlib/Code/Analysis/MethodAnalyzer.java | 139 +++++------ .../OdexedFieldInstructionMapper.java | 233 ++++++++++++++++++ .../main/java/org/jf/dexlib/Code/Opcode.java | 46 +++- 3 files changed, 329 insertions(+), 89 deletions(-) create mode 100644 dexlib/src/main/java/org/jf/dexlib/Code/Analysis/OdexedFieldInstructionMapper.java diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/MethodAnalyzer.java b/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/MethodAnalyzer.java index f4d7c49e..2f067902 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/MethodAnalyzer.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/MethodAnalyzer.java @@ -999,6 +999,19 @@ public class MethodAnalyzer { analyzeLiteralBinaryOp(analyzedInstruction, getDestTypeForLiteralShiftRight(analyzedInstruction, false), false); return true; + + /*odexed instructions*/ + case IGET_VOLATILE: + case IPUT_VOLATILE: + case SGET_VOLATILE: + case SPUT_VOLATILE: + case IGET_OBJECT_VOLATILE: + case IGET_WIDE_VOLATILE: + case IPUT_WIDE_VOLATILE: + case SGET_WIDE_VOLATILE: + case SPUT_WIDE_VOLATILE: + analyzePutGetVolatile(analyzedInstruction); + return true; case EXECUTE_INLINE: analyzeExecuteInline(analyzedInstruction); return true; @@ -1011,11 +1024,10 @@ public class MethodAnalyzer { case IGET_QUICK: case IGET_WIDE_QUICK: case IGET_OBJECT_QUICK: - return analyzeIputIgetQuick(analyzedInstruction, false); case IPUT_QUICK: case IPUT_WIDE_QUICK: case IPUT_OBJECT_QUICK: - return analyzeIputIgetQuick(analyzedInstruction, true); + return analyzeIputIgetQuick(analyzedInstruction); case INVOKE_VIRTUAL_QUICK: return analyzeInvokeVirtualQuick(analyzedInstruction, false, false); case INVOKE_SUPER_QUICK: @@ -1024,6 +1036,11 @@ public class MethodAnalyzer { return analyzeInvokeVirtualQuick(analyzedInstruction, false, true); case INVOKE_SUPER_QUICK_RANGE: return analyzeInvokeVirtualQuick(analyzedInstruction, true, true); + case IPUT_OBJECT_VOLATILE: + case SGET_OBJECT_VOLATILE: + case SPUT_OBJECT_VOLATILE: + analyzePutGetVolatile(analyzedInstruction); + return true; default: assert false; return true; @@ -1486,6 +1503,15 @@ public class MethodAnalyzer { case USHR_INT_LIT8: verifyLiteralBinaryOp(analyzedInstruction); return; + case IGET_VOLATILE: + case IPUT_VOLATILE: + case SGET_VOLATILE: + case SPUT_VOLATILE: + case IGET_OBJECT_VOLATILE: + case IGET_WIDE_VOLATILE: + case IPUT_WIDE_VOLATILE: + case SGET_WIDE_VOLATILE: + case SPUT_WIDE_VOLATILE: case EXECUTE_INLINE: case EXECUTE_INLINE_RANGE: case INVOKE_DIRECT_EMPTY: @@ -1499,6 +1525,9 @@ public class MethodAnalyzer { case INVOKE_SUPER_QUICK: case INVOKE_VIRTUAL_QUICK_RANGE: case INVOKE_SUPER_QUICK_RANGE: + case IPUT_OBJECT_VOLATILE: + case SGET_OBJECT_VOLATILE: + case SPUT_OBJECT_VOLATILE: //TODO: throw validation exception? default: assert false; @@ -3388,7 +3417,7 @@ public class MethodAnalyzer { analyzeInstruction(analyzedInstruction); } - private boolean analyzeIputIgetQuick(AnalyzedInstruction analyzedInstruction, boolean isIput) { + private boolean analyzeIputIgetQuick(AnalyzedInstruction analyzedInstruction) { Instruction22cs instruction = (Instruction22cs)analyzedInstruction.instruction; int fieldOffset = instruction.getFieldOffset(); @@ -3407,7 +3436,7 @@ public class MethodAnalyzer { String fieldType = fieldIdItem.getFieldType().getTypeDescriptor(); - Opcode opcode = getAndCheckIgetIputOpcodeForType(fieldType, instruction.opcode, isIput); + Opcode opcode = OdexedFieldInstructionMapper.getAndCheckDeodexedOpcodeForOdexedOpcode(fieldType, instruction.opcode); Instruction22c deodexedInstruction = new Instruction22c(opcode, (byte)instruction.getRegisterA(), (byte)instruction.getRegisterB(), fieldIdItem); @@ -3499,87 +3528,33 @@ public class MethodAnalyzer { return true; } - private static Opcode getAndCheckIgetIputOpcodeForType(String fieldType, Opcode odexedOpcode, boolean isIput) { - Opcode opcode; - Opcode validOdexedOpcode; - switch (fieldType.charAt(0)) { - case 'Z': - if (isIput) { - validOdexedOpcode = Opcode.IPUT_QUICK; - opcode = Opcode.IPUT_BOOLEAN; - } else { - validOdexedOpcode = Opcode.IGET_QUICK; - opcode = Opcode.IGET_BOOLEAN; - } - break; - case 'B': - if (isIput) { - validOdexedOpcode = Opcode.IPUT_QUICK; - opcode = Opcode.IPUT_BYTE; - } else { - validOdexedOpcode = Opcode.IGET_QUICK; - opcode = Opcode.IGET_BYTE; - } - break; - case 'S': - if (isIput) { - validOdexedOpcode = Opcode.IPUT_QUICK; - opcode = Opcode.IPUT_SHORT; - } else { - validOdexedOpcode = Opcode.IGET_QUICK; - opcode = Opcode.IGET_SHORT; - } - break; - case 'C': - if (isIput) { - validOdexedOpcode = Opcode.IPUT_QUICK; - opcode = Opcode.IPUT_CHAR; - } else { - validOdexedOpcode = Opcode.IGET_QUICK; - opcode = Opcode.IGET_CHAR; - } - break; - case 'I': - case 'F': - if (isIput) { - validOdexedOpcode = Opcode.IPUT_QUICK; - opcode = Opcode.IPUT; - } else { - validOdexedOpcode = Opcode.IGET_QUICK; - opcode = Opcode.IGET; - } - break; - case 'J': - case 'D': - if (isIput) { - validOdexedOpcode = Opcode.IPUT_WIDE_QUICK; - opcode = Opcode.IPUT_WIDE; - } else { - validOdexedOpcode = Opcode.IGET_WIDE_QUICK; - opcode = Opcode.IGET_WIDE; - } - break; - case 'L': - case '[': - if (isIput) { - validOdexedOpcode = Opcode.IPUT_OBJECT_QUICK; - opcode = Opcode.IPUT_OBJECT; - } else { - validOdexedOpcode = Opcode.IGET_OBJECT_QUICK; - opcode = Opcode.IGET_OBJECT; - } - break; - default: - throw new RuntimeException(String.format("Unexpected field type %s for %s: ", fieldType, - odexedOpcode.name)); + private boolean analyzePutGetVolatile(AnalyzedInstruction analyzedInstruction) { + FieldIdItem fieldIdItem = + (FieldIdItem)(((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem()); + + String fieldType = fieldIdItem.getFieldType().getTypeDescriptor(); + + Opcode opcode = OdexedFieldInstructionMapper.getAndCheckDeodexedOpcodeForOdexedOpcode(fieldType, + analyzedInstruction.instruction.opcode); + + Instruction deodexedInstruction; + + if (analyzedInstruction.instruction.opcode.isOdexedStaticVolatile()) { + SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction; + + deodexedInstruction = new Instruction21c(opcode, (byte)instruction.getRegisterA(), + fieldIdItem); + } else { + TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction; + + deodexedInstruction = new Instruction22c(opcode, (byte)instruction.getRegisterA(), + (byte)instruction.getRegisterB(), fieldIdItem); } - if (odexedOpcode != validOdexedOpcode) { - throw new ValidationException(String.format("Incorrect field type \"%s\" for %s", fieldType, - odexedOpcode.name)); - } + analyzedInstruction.setDeodexedInstruction(deodexedInstruction); + analyzeInstruction(analyzedInstruction); - return opcode; + return true; } private static boolean checkArrayFieldAssignment(RegisterType.Category arrayFieldCategory, diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/OdexedFieldInstructionMapper.java b/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/OdexedFieldInstructionMapper.java new file mode 100644 index 00000000..2facd985 --- /dev/null +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/OdexedFieldInstructionMapper.java @@ -0,0 +1,233 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2010 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib.Code.Analysis; + +import org.jf.dexlib.Code.Opcode; + +public class OdexedFieldInstructionMapper { + private static Opcode[][][][] opcodeMap = new Opcode[][][][] { + //get opcodes + new Opcode[][][] { + //iget quick + new Opcode[][] { + //odexed + new Opcode[] { + /*Z*/ Opcode.IGET_QUICK, + /*B*/ Opcode.IGET_QUICK, + /*S*/ Opcode.IGET_QUICK, + /*C*/ Opcode.IGET_QUICK, + /*I,F*/ Opcode.IGET_QUICK, + /*J,D*/ Opcode.IGET_WIDE_QUICK, + /*L,[*/ Opcode.IGET_OBJECT_QUICK + }, + //deodexed + new Opcode[] { + /*Z*/ Opcode.IGET_BOOLEAN, + /*B*/ Opcode.IGET_BYTE, + /*S*/ Opcode.IGET_SHORT, + /*C*/ Opcode.IGET_CHAR, + /*I,F*/ Opcode.IGET, + /*J,D*/ Opcode.IGET_WIDE, + /*L,[*/ Opcode.IGET_OBJECT + } + }, + //iget volatile + new Opcode[][] { + //odexed + new Opcode[] { + /*Z*/ Opcode.IGET_VOLATILE, + /*B*/ Opcode.IGET_VOLATILE, + /*S*/ Opcode.IGET_VOLATILE, + /*C*/ Opcode.IGET_VOLATILE, + /*I,F*/ Opcode.IGET_VOLATILE, + /*J,D*/ Opcode.IGET_WIDE_VOLATILE, + /*L,[*/ Opcode.IGET_OBJECT_VOLATILE + }, + //deodexed + new Opcode[] { + /*Z*/ Opcode.IGET_BOOLEAN, + /*B*/ Opcode.IGET_BYTE, + /*S*/ Opcode.IGET_SHORT, + /*C*/ Opcode.IGET_CHAR, + /*I,F*/ Opcode.IGET, + /*J,D*/ Opcode.IGET_WIDE, + /*L,[*/ Opcode.IGET_OBJECT + } + }, + //sget volatile + new Opcode[][] { + //odexed + new Opcode[] { + /*Z*/ Opcode.SGET_VOLATILE, + /*B*/ Opcode.SGET_VOLATILE, + /*S*/ Opcode.SGET_VOLATILE, + /*C*/ Opcode.SGET_VOLATILE, + /*I,F*/ Opcode.SGET_VOLATILE, + /*J,D*/ Opcode.SGET_WIDE_VOLATILE, + /*L,[*/ Opcode.SGET_OBJECT_VOLATILE + }, + //deodexed + new Opcode[] { + /*Z*/ Opcode.SGET_BOOLEAN, + /*B*/ Opcode.SGET_BYTE, + /*S*/ Opcode.SGET_SHORT, + /*C*/ Opcode.SGET_CHAR, + /*I,F*/ Opcode.SGET, + /*J,D*/ Opcode.SGET_WIDE, + /*L,[*/ Opcode.SGET_OBJECT + } + } + }, + //put opcodes + new Opcode[][][] { + //iput quick + new Opcode[][] { + //odexed + new Opcode[] { + /*Z*/ Opcode.IPUT_QUICK, + /*B*/ Opcode.IPUT_QUICK, + /*S*/ Opcode.IPUT_QUICK, + /*C*/ Opcode.IPUT_QUICK, + /*I,F*/ Opcode.IPUT_QUICK, + /*J,D*/ Opcode.IPUT_WIDE_QUICK, + /*L,[*/ Opcode.IPUT_OBJECT_QUICK + }, + //deodexed + new Opcode[] { + /*Z*/ Opcode.IPUT_BOOLEAN, + /*B*/ Opcode.IPUT_BYTE, + /*S*/ Opcode.IPUT_SHORT, + /*C*/ Opcode.IPUT_CHAR, + /*I,F*/ Opcode.IPUT, + /*J,D*/ Opcode.IPUT_WIDE, + /*L,[*/ Opcode.IPUT_OBJECT + } + }, + //iput volatile + new Opcode[][] { + //odexed + new Opcode[] { + /*Z*/ Opcode.IPUT_VOLATILE, + /*B*/ Opcode.IPUT_VOLATILE, + /*S*/ Opcode.IPUT_VOLATILE, + /*C*/ Opcode.IPUT_VOLATILE, + /*I,F*/ Opcode.IPUT_VOLATILE, + /*J,D*/ Opcode.IPUT_WIDE_VOLATILE, + /*L,[*/ Opcode.IPUT_OBJECT_VOLATILE + }, + //deodexed + new Opcode[] { + /*Z*/ Opcode.IPUT_BOOLEAN, + /*B*/ Opcode.IPUT_BYTE, + /*S*/ Opcode.IPUT_SHORT, + /*C*/ Opcode.IPUT_CHAR, + /*I,F*/ Opcode.IPUT, + /*J,D*/ Opcode.IPUT_WIDE, + /*L,[*/ Opcode.IPUT_OBJECT + } + }, + //sput volatile + new Opcode[][] { + //odexed + new Opcode[] { + /*Z*/ Opcode.SPUT_VOLATILE, + /*B*/ Opcode.SPUT_VOLATILE, + /*S*/ Opcode.SPUT_VOLATILE, + /*C*/ Opcode.SPUT_VOLATILE, + /*I,F*/ Opcode.SPUT_VOLATILE, + /*J,D*/ Opcode.SPUT_WIDE_VOLATILE, + /*L,[*/ Opcode.SPUT_OBJECT_VOLATILE + }, + //deodexed + new Opcode[] { + /*Z*/ Opcode.SPUT_BOOLEAN, + /*B*/ Opcode.SPUT_BYTE, + /*S*/ Opcode.SPUT_SHORT, + /*C*/ Opcode.SPUT_CHAR, + /*I,F*/ Opcode.SPUT, + /*J,D*/ Opcode.SPUT_WIDE, + /*L,[*/ Opcode.SPUT_OBJECT + } + } + } + }; + + private static int getTypeIndex(char type) { + switch (type) { + case 'Z': + return 0; + case 'B': + return 1; + case 'S': + return 2; + case 'C': + return 3; + case 'I': + case 'F': + return 4; + case 'J': + case 'D': + return 5; + case 'L': + case '[': + return 6; + default: + } + throw new RuntimeException(String.format("Unknown type %s: ", type)); + } + + private static int getOpcodeSubtype(Opcode opcode) { + if (opcode.isOdexedInstanceQuick()) { + return 0; + } else if (opcode.isOdexedInstanceVolatile()) { + return 1; + } else if (opcode.isOdexedStaticVolatile()) { + return 2; + } + throw new RuntimeException(String.format("Not an odexed field access opcode: %s", opcode.name)); + } + + static Opcode getAndCheckDeodexedOpcodeForOdexedOpcode(String fieldType, Opcode odexedOpcode) { + int opcodeType = odexedOpcode.setsRegister()?0:1; + int opcodeSubType = getOpcodeSubtype(odexedOpcode); + int typeIndex = getTypeIndex(fieldType.charAt(0)); + + Opcode correctOdexedOpcode = opcodeMap[opcodeType][opcodeSubType][0][typeIndex]; + Opcode deodexedOpcode = opcodeMap[opcodeType][opcodeSubType][1][typeIndex]; + + if (correctOdexedOpcode != odexedOpcode) { + throw new ValidationException(String.format("Incorrect field type \"%s\" for %s", fieldType, + odexedOpcode.name)); + } + + return deodexedOpcode; + } +} + + diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Opcode.java b/dexlib/src/main/java/org/jf/dexlib/Code/Opcode.java index 72101d12..4a15a1bf 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Opcode.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Opcode.java @@ -253,19 +253,33 @@ public enum Opcode SHR_INT_LIT8((byte)0xe1, "shr-int/lit8", ReferenceType.none, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), USHR_INT_LIT8((byte)0xe2, "ushr-int/lit8", ReferenceType.none, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), + IGET_VOLATILE((byte)0xe3, "iget-volatile", ReferenceType.field, Format.Format22c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), + IPUT_VOLATILE((byte)0xe4, "iput-volatile", ReferenceType.field, Format.Format22c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE), + SGET_VOLATILE((byte)0xe5, "sget-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), + SPUT_VOLATILE((byte)0xe6, "sput-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE), + IGET_OBJECT_VOLATILE((byte)0xe7, "iget-object-volatile", ReferenceType.field, Format.Format22c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), + IGET_WIDE_VOLATILE((byte)0xe8, "iget-wide-volatile", ReferenceType.field, Format.Format22c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), + IPUT_WIDE_VOLATILE((byte)0xe9, "iput-wide-volatile", ReferenceType.field, Format.Format22c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE), + SGET_WIDE_VOLATILE((byte)0xea, "sget-wide-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), + SPUT_WIDE_VOLATILE((byte)0xeb, "sput-wide-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE), + EXECUTE_INLINE((byte)0xee, "execute-inline", ReferenceType.none, Format.Format35ms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), EXECUTE_INLINE_RANGE((byte)0xef, "execute-inline/range", ReferenceType.none, Format.Format3rms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_DIRECT_EMPTY((byte)0xf0, "invoke-direct-empty", ReferenceType.method, Format.Format35s, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), - IGET_QUICK((byte)0xf2, "iget-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), - IGET_WIDE_QUICK((byte)0xf3, "iget-wide-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), - IGET_OBJECT_QUICK((byte)0xf4, "iget-object-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), - IPUT_QUICK((byte)0xf5, "iput-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE), - IPUT_WIDE_QUICK((byte)0xf6, "iput-wide-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE), - IPUT_OBJECT_QUICK((byte)0xf7, "iput-object-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE), + IGET_QUICK((byte)0xf2, "iget-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), + IGET_WIDE_QUICK((byte)0xf3, "iget-wide-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), + IGET_OBJECT_QUICK((byte)0xf4, "iget-object-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), + IPUT_QUICK((byte)0xf5, "iput-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE), + IPUT_WIDE_QUICK((byte)0xf6, "iput-wide-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE), + IPUT_OBJECT_QUICK((byte)0xf7, "iput-object-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE), INVOKE_VIRTUAL_QUICK((byte)0xf8, "invoke-virtual-quick", ReferenceType.none, Format.Format35ms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_VIRTUAL_QUICK_RANGE((byte)0xf9, "invoke-virtual-quick/range", ReferenceType.none, Format.Format3rms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_SUPER_QUICK((byte)0xfa, "invoke-super-quick", ReferenceType.none, Format.Format35ms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), - INVOKE_SUPER_QUICK_RANGE((byte)0xfb, "invoke-super-quick/range", ReferenceType.none, Format.Format3rms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT); + INVOKE_SUPER_QUICK_RANGE((byte)0xfb, "invoke-super-quick/range", ReferenceType.none, Format.Format3rms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), + + IPUT_OBJECT_VOLATILE((byte)0xfc, "iput-object-volatile", ReferenceType.field, Format.Format22c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE), + SGET_OBJECT_VOLATILE((byte)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((byte)0xfe, "sput-object-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE); private static Opcode[] opcodesByValue; @@ -283,6 +297,12 @@ public enum Opcode public static final int SETS_REGISTER = 0x10; //if the instruction sets the value of it's first register to a wide type public static final int SETS_WIDE_REGISTER = 0x20; + //if the instruction is an odexed iget-quick/iput-quick instruction + public static final int ODEXED_INSTANCE_QUICK = 0x40; + //if the instruction is an odexed iget-volatile/iput-volatile instruction + public static final int ODEXED_INSTANCE_VOLATILE = 0x80; + //if the instruction is an odexed sget-volatile/sput-volatile instruction + public static final int ODEXED_STATIC_VOLATILE = 0x100; static { opcodesByValue = new Opcode[256]; @@ -343,4 +363,16 @@ public enum Opcode public final boolean setsWideRegister() { return (flags & SETS_WIDE_REGISTER) != 0; } + + public final boolean isOdexedInstanceQuick() { + return (flags & ODEXED_INSTANCE_QUICK) != 0; + } + + public final boolean isOdexedInstanceVolatile() { + return (flags & ODEXED_INSTANCE_VOLATILE) != 0; + } + + public final boolean isOdexedStaticVolatile() { + return (flags & ODEXED_STATIC_VOLATILE) != 0; + } }