mirror of
https://github.com/revanced/smali.git
synced 2025-05-04 16:44:25 +02:00
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
This commit is contained in:
parent
595cdad3d6
commit
d4417d7269
@ -999,6 +999,19 @@ public class MethodAnalyzer {
|
|||||||
analyzeLiteralBinaryOp(analyzedInstruction, getDestTypeForLiteralShiftRight(analyzedInstruction, false),
|
analyzeLiteralBinaryOp(analyzedInstruction, getDestTypeForLiteralShiftRight(analyzedInstruction, false),
|
||||||
false);
|
false);
|
||||||
return true;
|
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:
|
case EXECUTE_INLINE:
|
||||||
analyzeExecuteInline(analyzedInstruction);
|
analyzeExecuteInline(analyzedInstruction);
|
||||||
return true;
|
return true;
|
||||||
@ -1011,11 +1024,10 @@ public class MethodAnalyzer {
|
|||||||
case IGET_QUICK:
|
case IGET_QUICK:
|
||||||
case IGET_WIDE_QUICK:
|
case IGET_WIDE_QUICK:
|
||||||
case IGET_OBJECT_QUICK:
|
case IGET_OBJECT_QUICK:
|
||||||
return analyzeIputIgetQuick(analyzedInstruction, false);
|
|
||||||
case IPUT_QUICK:
|
case IPUT_QUICK:
|
||||||
case IPUT_WIDE_QUICK:
|
case IPUT_WIDE_QUICK:
|
||||||
case IPUT_OBJECT_QUICK:
|
case IPUT_OBJECT_QUICK:
|
||||||
return analyzeIputIgetQuick(analyzedInstruction, true);
|
return analyzeIputIgetQuick(analyzedInstruction);
|
||||||
case INVOKE_VIRTUAL_QUICK:
|
case INVOKE_VIRTUAL_QUICK:
|
||||||
return analyzeInvokeVirtualQuick(analyzedInstruction, false, false);
|
return analyzeInvokeVirtualQuick(analyzedInstruction, false, false);
|
||||||
case INVOKE_SUPER_QUICK:
|
case INVOKE_SUPER_QUICK:
|
||||||
@ -1024,6 +1036,11 @@ public class MethodAnalyzer {
|
|||||||
return analyzeInvokeVirtualQuick(analyzedInstruction, false, true);
|
return analyzeInvokeVirtualQuick(analyzedInstruction, false, true);
|
||||||
case INVOKE_SUPER_QUICK_RANGE:
|
case INVOKE_SUPER_QUICK_RANGE:
|
||||||
return analyzeInvokeVirtualQuick(analyzedInstruction, true, true);
|
return analyzeInvokeVirtualQuick(analyzedInstruction, true, true);
|
||||||
|
case IPUT_OBJECT_VOLATILE:
|
||||||
|
case SGET_OBJECT_VOLATILE:
|
||||||
|
case SPUT_OBJECT_VOLATILE:
|
||||||
|
analyzePutGetVolatile(analyzedInstruction);
|
||||||
|
return true;
|
||||||
default:
|
default:
|
||||||
assert false;
|
assert false;
|
||||||
return true;
|
return true;
|
||||||
@ -1486,6 +1503,15 @@ public class MethodAnalyzer {
|
|||||||
case USHR_INT_LIT8:
|
case USHR_INT_LIT8:
|
||||||
verifyLiteralBinaryOp(analyzedInstruction);
|
verifyLiteralBinaryOp(analyzedInstruction);
|
||||||
return;
|
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:
|
||||||
case EXECUTE_INLINE_RANGE:
|
case EXECUTE_INLINE_RANGE:
|
||||||
case INVOKE_DIRECT_EMPTY:
|
case INVOKE_DIRECT_EMPTY:
|
||||||
@ -1499,6 +1525,9 @@ public class MethodAnalyzer {
|
|||||||
case INVOKE_SUPER_QUICK:
|
case INVOKE_SUPER_QUICK:
|
||||||
case INVOKE_VIRTUAL_QUICK_RANGE:
|
case INVOKE_VIRTUAL_QUICK_RANGE:
|
||||||
case INVOKE_SUPER_QUICK_RANGE:
|
case INVOKE_SUPER_QUICK_RANGE:
|
||||||
|
case IPUT_OBJECT_VOLATILE:
|
||||||
|
case SGET_OBJECT_VOLATILE:
|
||||||
|
case SPUT_OBJECT_VOLATILE:
|
||||||
//TODO: throw validation exception?
|
//TODO: throw validation exception?
|
||||||
default:
|
default:
|
||||||
assert false;
|
assert false;
|
||||||
@ -3388,7 +3417,7 @@ public class MethodAnalyzer {
|
|||||||
analyzeInstruction(analyzedInstruction);
|
analyzeInstruction(analyzedInstruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean analyzeIputIgetQuick(AnalyzedInstruction analyzedInstruction, boolean isIput) {
|
private boolean analyzeIputIgetQuick(AnalyzedInstruction analyzedInstruction) {
|
||||||
Instruction22cs instruction = (Instruction22cs)analyzedInstruction.instruction;
|
Instruction22cs instruction = (Instruction22cs)analyzedInstruction.instruction;
|
||||||
|
|
||||||
int fieldOffset = instruction.getFieldOffset();
|
int fieldOffset = instruction.getFieldOffset();
|
||||||
@ -3407,7 +3436,7 @@ public class MethodAnalyzer {
|
|||||||
|
|
||||||
String fieldType = fieldIdItem.getFieldType().getTypeDescriptor();
|
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(),
|
Instruction22c deodexedInstruction = new Instruction22c(opcode, (byte)instruction.getRegisterA(),
|
||||||
(byte)instruction.getRegisterB(), fieldIdItem);
|
(byte)instruction.getRegisterB(), fieldIdItem);
|
||||||
@ -3499,87 +3528,33 @@ public class MethodAnalyzer {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Opcode getAndCheckIgetIputOpcodeForType(String fieldType, Opcode odexedOpcode, boolean isIput) {
|
private boolean analyzePutGetVolatile(AnalyzedInstruction analyzedInstruction) {
|
||||||
Opcode opcode;
|
FieldIdItem fieldIdItem =
|
||||||
Opcode validOdexedOpcode;
|
(FieldIdItem)(((InstructionWithReference)analyzedInstruction.instruction).getReferencedItem());
|
||||||
switch (fieldType.charAt(0)) {
|
|
||||||
case 'Z':
|
String fieldType = fieldIdItem.getFieldType().getTypeDescriptor();
|
||||||
if (isIput) {
|
|
||||||
validOdexedOpcode = Opcode.IPUT_QUICK;
|
Opcode opcode = OdexedFieldInstructionMapper.getAndCheckDeodexedOpcodeForOdexedOpcode(fieldType,
|
||||||
opcode = Opcode.IPUT_BOOLEAN;
|
analyzedInstruction.instruction.opcode);
|
||||||
|
|
||||||
|
Instruction deodexedInstruction;
|
||||||
|
|
||||||
|
if (analyzedInstruction.instruction.opcode.isOdexedStaticVolatile()) {
|
||||||
|
SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction;
|
||||||
|
|
||||||
|
deodexedInstruction = new Instruction21c(opcode, (byte)instruction.getRegisterA(),
|
||||||
|
fieldIdItem);
|
||||||
} else {
|
} else {
|
||||||
validOdexedOpcode = Opcode.IGET_QUICK;
|
TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction;
|
||||||
opcode = Opcode.IGET_BOOLEAN;
|
|
||||||
}
|
deodexedInstruction = new Instruction22c(opcode, (byte)instruction.getRegisterA(),
|
||||||
break;
|
(byte)instruction.getRegisterB(), fieldIdItem);
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (odexedOpcode != validOdexedOpcode) {
|
analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
|
||||||
throw new ValidationException(String.format("Incorrect field type \"%s\" for %s", fieldType,
|
analyzeInstruction(analyzedInstruction);
|
||||||
odexedOpcode.name));
|
|
||||||
}
|
|
||||||
|
|
||||||
return opcode;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean checkArrayFieldAssignment(RegisterType.Category arrayFieldCategory,
|
private static boolean checkArrayFieldAssignment(RegisterType.Category arrayFieldCategory,
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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),
|
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),
|
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((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),
|
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),
|
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_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.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_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.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_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.CAN_THROW | Opcode.CAN_CONTINUE),
|
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.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.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((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_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((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;
|
private static Opcode[] opcodesByValue;
|
||||||
@ -283,6 +297,12 @@ public enum Opcode
|
|||||||
public static final int SETS_REGISTER = 0x10;
|
public static final int SETS_REGISTER = 0x10;
|
||||||
//if the instruction sets the value of it's first register to a wide type
|
//if the instruction sets the value of it's first register to a wide type
|
||||||
public static final int SETS_WIDE_REGISTER = 0x20;
|
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 {
|
static {
|
||||||
opcodesByValue = new Opcode[256];
|
opcodesByValue = new Opcode[256];
|
||||||
@ -343,4 +363,16 @@ public enum Opcode
|
|||||||
public final boolean setsWideRegister() {
|
public final boolean setsWideRegister() {
|
||||||
return (flags & SETS_WIDE_REGISTER) != 0;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user