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 1b13d22a..3858fa0a 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 @@ -661,6 +661,9 @@ public class MethodAnalyzer { case RETURN_WIDE: case RETURN_OBJECT: return true; + case RETURN_VOID_BARRIER: + analyzeReturnVoidBarrier(analyzedInstruction); + return true; case CONST_4: case CONST_16: case CONST: @@ -1099,7 +1102,7 @@ public class MethodAnalyzer { } - private void verifyInstruction(AnalyzedInstruction analyzedInstruction) { + private void verifyInstruction(AnalyzedInstruction analyzedInstruction) { Instruction instruction = analyzedInstruction.instruction; switch (instruction.opcode) { @@ -1133,6 +1136,7 @@ public class MethodAnalyzer { verifyMoveException(analyzedInstruction); return; case RETURN_VOID: + case RETURN_VOID_BARRIER: verifyReturnVoid(analyzedInstruction); return; case RETURN: @@ -1780,6 +1784,16 @@ public class MethodAnalyzer { } } + private void analyzeReturnVoidBarrier(AnalyzedInstruction analyzedInstruction) { + Instruction10x instruction = (Instruction10x)analyzedInstruction.instruction; + + Instruction10x deodexedInstruction = new Instruction10x(Opcode.RETURN_VOID); + + analyzedInstruction.setDeodexedInstruction(deodexedInstruction); + + analyzeInstruction(analyzedInstruction); + } + private void verifyReturnVoid(AnalyzedInstruction analyzedInstruction) { TypeIdItem returnType = encodedMethod.method.getPrototype().getReturnType(); if (returnType.getTypeDescriptor().charAt(0) != 'V') { diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction10x.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction10x.java index 5997092e..46ea9686 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction10x.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction10x.java @@ -43,7 +43,7 @@ public class Instruction10x extends Instruction { public Instruction10x(Opcode opcode, byte[] buffer, int bufferIndex) { super(opcode); - assert buffer[bufferIndex] == opcode.value; + assert (buffer[bufferIndex] & 0xFF) == opcode.value; assert buffer[bufferIndex + 1] == 0x00; } 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 7cc2d784..3fc0ecd5 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Opcode.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Opcode.java @@ -268,6 +268,7 @@ public enum Opcode EXECUTE_INLINE_RANGE((short)0xef, "execute-inline/range", ReferenceType.none, Format.Format3rmi, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_DIRECT_EMPTY((short)0xf0, "invoke-direct-empty", ReferenceType.method, Format.Format35c, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), INVOKE_OBJECT_INIT_RANGE((short)0xf0, "invoke-object-init/range", ReferenceType.method, Format.Format3rc, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), + RETURN_VOID_BARRIER((short)0xf1, "return-void-barrier", ReferenceType.none, Format.Format10x, Opcode.ODEX_ONLY), IGET_QUICK((short)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((short)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((short)0xf4, "iget-object-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), @@ -419,6 +420,9 @@ public enum Opcode IGET_WIDE_VOLATILE, IPUT_WIDE_VOLATILE, SGET_WIDE_VOLATILE, SPUT_WIDE_VOLATILE, IPUT_OBJECT_VOLATILE, SGET_OBJECT_VOLATILE, SPUT_OBJECT_VOLATILE); } + if (apiLevel < 11) { + removeOpcodes(RETURN_VOID_BARRIER); + } if (apiLevel < 14) { 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, diff --git a/smali/src/main/antlr3/org/jf/smali/smaliLexer.g b/smali/src/main/antlr3/org/jf/smali/smaliLexer.g index 8cb499c2..84cfb65e 100644 --- a/smali/src/main/antlr3/org/jf/smali/smaliLexer.g +++ b/smali/src/main/antlr3/org/jf/smali/smaliLexer.g @@ -373,6 +373,9 @@ INSTRUCTION_FORMAT10x : 'return-void' | 'nop'; +INSTRUCTION_FORMAT10x_ODEX + : 'return-void-barrier'; + INSTRUCTION_FORMAT11n : 'const/4'; diff --git a/smali/src/main/antlr3/org/jf/smali/smaliParser.g b/smali/src/main/antlr3/org/jf/smali/smaliParser.g index 0eb834d1..3fb50d0f 100644 --- a/smali/src/main/antlr3/org/jf/smali/smaliParser.g +++ b/smali/src/main/antlr3/org/jf/smali/smaliParser.g @@ -446,6 +446,7 @@ simple_name | ANNOTATION_VISIBILITY -> SIMPLE_NAME[$ANNOTATION_VISIBILITY] | INSTRUCTION_FORMAT10t -> SIMPLE_NAME[$INSTRUCTION_FORMAT10t] | INSTRUCTION_FORMAT10x -> SIMPLE_NAME[$INSTRUCTION_FORMAT10x] + | INSTRUCTION_FORMAT10x_ODEX -> SIMPLE_NAME[$INSTRUCTION_FORMAT10x_ODEX] | INSTRUCTION_FORMAT11x -> SIMPLE_NAME[$INSTRUCTION_FORMAT11x] | INSTRUCTION_FORMAT12x_OR_ID -> SIMPLE_NAME[$INSTRUCTION_FORMAT12x_OR_ID] | INSTRUCTION_FORMAT21c_FIELD -> SIMPLE_NAME[$INSTRUCTION_FORMAT21c_FIELD] @@ -689,9 +690,14 @@ instruction returns [int size] //e.g. goto +3 INSTRUCTION_FORMAT10t label_ref_or_offset {$size = Format.Format10t.size;} -> ^(I_STATEMENT_FORMAT10t[$start, "I_STATEMENT_FORMAT10t"] INSTRUCTION_FORMAT10t label_ref_or_offset) - | //e.g. return + | //e.g. return-void INSTRUCTION_FORMAT10x {$size = Format.Format10x.size;} -> ^(I_STATEMENT_FORMAT10x[$start, "I_STATEMENT_FORMAT10x"] INSTRUCTION_FORMAT10x) + | //e.g. return-void-barrier + INSTRUCTION_FORMAT10x_ODEX {$size = Format.Format10x.size;} + { + throwOdexedInstructionException(input, $INSTRUCTION_FORMAT10x_ODEX.text); + } | //e.g. const/4 v0, 5 INSTRUCTION_FORMAT11n REGISTER COMMA integral_literal {$size = Format.Format11n.size;} -> ^(I_STATEMENT_FORMAT11n[$start, "I_STATEMENT_FORMAT11n"] INSTRUCTION_FORMAT11n REGISTER integral_literal) diff --git a/smali/src/main/jflex/smaliLexer.flex b/smali/src/main/jflex/smaliLexer.flex index 79323de2..8ceec774 100644 --- a/smali/src/main/jflex/smaliLexer.flex +++ b/smali/src/main/jflex/smaliLexer.flex @@ -388,6 +388,10 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayDescriptor} return newToken(INSTRUCTION_FORMAT10x); } + "return-void-barrier" { + return newToken(INSTRUCTION_FORMAT10x_ODEX); + } + "const/4" { return newToken(INSTRUCTION_FORMAT11n); } diff --git a/smali/src/test/resources/LexerTest/InstructionTest.smali b/smali/src/test/resources/LexerTest/InstructionTest.smali index d6207936..7a85dce4 100644 --- a/smali/src/test/resources/LexerTest/InstructionTest.smali +++ b/smali/src/test/resources/LexerTest/InstructionTest.smali @@ -1,6 +1,7 @@ goto return-void nop +return-void-barrier const/4 move-result move-result-wide diff --git a/smali/src/test/resources/LexerTest/InstructionTest.tokens b/smali/src/test/resources/LexerTest/InstructionTest.tokens index 9c649895..fb0014c3 100644 --- a/smali/src/test/resources/LexerTest/InstructionTest.tokens +++ b/smali/src/test/resources/LexerTest/InstructionTest.tokens @@ -1,6 +1,7 @@ INSTRUCTION_FORMAT10t("goto") INSTRUCTION_FORMAT10x("return-void") INSTRUCTION_FORMAT10x("nop") +INSTRUCTION_FORMAT10x_ODEX("return-void-barrier") INSTRUCTION_FORMAT11n("const/4") INSTRUCTION_FORMAT11x("move-result") INSTRUCTION_FORMAT11x("move-result-wide")