diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java index 4b0a9956..a51cfb1e 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java @@ -186,6 +186,12 @@ public class InstructionMethodItem extends MethodItem { writer.write(", "); writeReference(writer); return true; + case Format35mi: + writeOpcode(writer); + writer.write(' '); + writeInvokeRegisters(writer); + writer.write(", "); + writeInlineIndex(writer); case Format35ms: writeOpcode(writer); writer.write(' '); @@ -200,6 +206,13 @@ public class InstructionMethodItem extends MethodItem { writer.write(", "); writeReference(writer); return true; + case Format3rmi: + writeOpcode(writer); + writer.write(' '); + writeInvokeRangeRegisters(writer); + writer.write(", "); + writeInlineIndex(writer); + return true; case Format3rms: writeOpcode(writer); writer.write(' '); @@ -304,6 +317,11 @@ public class InstructionMethodItem extends MethodItem { writer.printUnsignedLongAsHex(((OdexedFieldAccess) instruction).getFieldOffset()); } + protected void writeInlineIndex(IndentingWriter writer) throws IOException { + writer.write("inline@0x"); + writer.printUnsignedLongAsHex(((OdexedInvokeInline) instruction).getInlineIndex()); + } + protected void writeVtableIndex(IndentingWriter writer) throws IOException { writer.write("vtable@0x"); writer.printUnsignedLongAsHex(((OdexedInvokeVirtual) instruction).getVtableIndex()); diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/InlineMethodResolver.java b/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/InlineMethodResolver.java index aad4cb53..eb4e9dc7 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/InlineMethodResolver.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/InlineMethodResolver.java @@ -28,10 +28,10 @@ package org.jf.dexlib.Code.Analysis; -import org.jf.dexlib.Code.Format.Instruction35ms; -import org.jf.dexlib.Code.Format.Instruction3rms; +import org.jf.dexlib.Code.Format.Instruction35mi; +import org.jf.dexlib.Code.Format.Instruction3rmi; +import org.jf.dexlib.Code.OdexedInvokeInline; import org.jf.dexlib.Code.OdexedInvokeVirtual; -import org.jf.dexlib.MethodIdItem; import static org.jf.dexlib.Code.Analysis.DeodexUtil.Static; import static org.jf.dexlib.Code.Analysis.DeodexUtil.Virtual; @@ -143,16 +143,16 @@ abstract class InlineMethodResolver { @Override public DeodexUtil.InlineMethod resolveExecuteInline(AnalyzedInstruction analyzedInstruction) { - assert analyzedInstruction.instruction instanceof OdexedInvokeVirtual; + assert analyzedInstruction.instruction instanceof OdexedInvokeInline; - OdexedInvokeVirtual instruction = (OdexedInvokeVirtual)analyzedInstruction.instruction; - int methodIndex = instruction.getVtableIndex(); + OdexedInvokeInline instruction = (OdexedInvokeInline)analyzedInstruction.instruction; + int inlineIndex = instruction.getInlineIndex(); - if (methodIndex < 0 || methodIndex >= inlineMethods.length) { - throw new RuntimeException("Invalid method index: " + methodIndex); + if (inlineIndex < 0 || inlineIndex >= inlineMethods.length) { + throw new RuntimeException("Invalid method index: " + inlineIndex); } - if (methodIndex == 4) { + if (inlineIndex == 4) { int parameterCount = getParameterCount(instruction); if (parameterCount == 2) { return indexOfIMethod; @@ -161,7 +161,7 @@ abstract class InlineMethodResolver { } else { throw new RuntimeException("Could not determine the correct inline method to use"); } - } else if (methodIndex == 5) { + } else if (inlineIndex == 5) { int parameterCount = getParameterCount(instruction); if (parameterCount == 3) { return indexOfIIMethod; @@ -172,14 +172,14 @@ abstract class InlineMethodResolver { } } - return inlineMethods[methodIndex]; + return inlineMethods[inlineIndex]; } - private int getParameterCount(OdexedInvokeVirtual instruction) { - if (instruction instanceof Instruction35ms) { - return ((Instruction35ms)instruction).getRegCount(); + private int getParameterCount(OdexedInvokeInline instruction) { + if (instruction instanceof Instruction35mi) { + return ((Instruction35mi)instruction).getRegCount(); } else { - return ((Instruction3rms)instruction).getRegCount(); + return ((Instruction3rmi)instruction).getRegCount(); } } }; 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 232b8913..8810e359 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 @@ -252,11 +252,13 @@ public class MethodAnalyzer { case Format22cs: objectRegisterNumber = ((Instruction22cs)instruction.instruction).getRegisterB(); break; + case Format35mi: case Format35ms: - objectRegisterNumber = ((Instruction35ms)instruction.instruction).getRegisterD(); + objectRegisterNumber = ((FiveRegisterInstruction)instruction.instruction).getRegisterD(); break; + case Format3rmi: case Format3rms: - objectRegisterNumber = ((Instruction3rms)instruction.instruction).getStartRegister(); + objectRegisterNumber = ((RegisterRangeInstruction)instruction.instruction).getStartRegister(); break; default: continue; @@ -3338,13 +3340,13 @@ public class MethodAnalyzer { throw new ValidationException("Cannot analyze an odexed instruction unless we are deodexing"); } - Instruction35ms instruction = (Instruction35ms)analyzedInstruction.instruction; + Instruction35mi instruction = (Instruction35mi)analyzedInstruction.instruction; DeodexUtil.InlineMethod inlineMethod = deodexUtil.lookupInlineMethod(analyzedInstruction); MethodIdItem inlineMethodIdItem = inlineMethod.getMethodIdItem(); if (inlineMethodIdItem == null) { throw new ValidationException(String.format("Cannot load inline method with index %d", - instruction.getVtableIndex())); + instruction.getInlineIndex())); } Opcode deodexedOpcode = null; @@ -3376,13 +3378,13 @@ public class MethodAnalyzer { throw new ValidationException("Cannot analyze an odexed instruction unless we are deodexing"); } - Instruction3rms instruction = (Instruction3rms)analyzedInstruction.instruction; + Instruction3rmi instruction = (Instruction3rmi)analyzedInstruction.instruction; DeodexUtil.InlineMethod inlineMethod = deodexUtil.lookupInlineMethod(analyzedInstruction); MethodIdItem inlineMethodIdItem = inlineMethod.getMethodIdItem(); if (inlineMethodIdItem == null) { throw new ValidationException(String.format("Cannot load inline method with index %d", - instruction.getVtableIndex())); + instruction.getInlineIndex())); } Opcode deodexedOpcode = null; diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Format.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Format.java index 4ed9fec0..4958cb22 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Format.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Format.java @@ -56,8 +56,10 @@ public enum Format { Format32x(Instruction32x.Factory, 6), Format35c(Instruction35c.Factory, 6), Format35s(Instruction35s.Factory, 6), + Format35mi(Instruction35mi.Factory, 6), Format35ms(Instruction35ms.Factory, 6), Format3rc(Instruction3rc.Factory, 6), + Format3rmi(Instruction3rmi.Factory, 6), Format3rms(Instruction3rms.Factory, 6), Format51l(Instruction51l.Factory, 10), ArrayData(null, -1, true), diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction35mi.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction35mi.java new file mode 100644 index 00000000..787bd07f --- /dev/null +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction35mi.java @@ -0,0 +1,136 @@ +/* + * 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.*; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.Util.AnnotatedOutput; +import org.jf.dexlib.Util.NumberUtils; + + +public class Instruction35mi extends Instruction implements FiveRegisterInstruction, OdexedInvokeInline { + public static final InstructionFactory Factory = new Factory(); + private byte regCount; + private byte regA; + private byte regD; + private byte regE; + private byte regF; + private byte regG; + private short inlineIndex; + + public Instruction35mi(Opcode opcode, int regCount, byte regD, byte regE, byte regF, byte regG, + byte regA, int inlineIndex) { + super(opcode); + if (regCount > 5) { + throw new RuntimeException("regCount cannot be greater than 5"); + } + + if (regD >= 1 << 4 || + regE >= 1 << 4 || + regF >= 1 << 4 || + regG >= 1 << 4 || + regA >= 1 << 4) { + throw new RuntimeException("All register args must fit in 4 bits"); + } + + if (inlineIndex >= 1 << 16) { + throw new RuntimeException("The method index must be less than 65536"); + } + + this.regCount = (byte)regCount; + this.regA = regA; + this.regD = regD; + this.regE = regE; + this.regF = regF; + this.regG = regG; + this.inlineIndex = (short)inlineIndex; + } + + private Instruction35mi(Opcode opcode, byte[] buffer, int bufferIndex) { + super(opcode); + + this.regCount = NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 1]); + this.regA = NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 1]); + this.regD = NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 4]); + this.regE = NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 4]); + this.regF = NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 5]); + this.regG = NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 5]); + this.inlineIndex = (short)NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 2); + } + + protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) { + out.writeByte(opcode.value); + out.writeByte((regCount << 4) | regA); + out.writeShort(inlineIndex); + out.writeByte((regE << 4) | regD); + out.writeByte((regG << 4) | regF); + } + + public Format getFormat() { + return Format.Format35ms; + } + + public byte getRegCount() { + return regCount; + } + + public byte getRegisterA() { + return regA; + } + + public byte getRegisterD() { + return regD; + } + + public byte getRegisterE() { + return regE; + } + + public byte getRegisterF() { + return regF; + } + + public byte getRegisterG() { + return regG; + } + + public int getInlineIndex() { + return inlineIndex & 0xFFFF; + } + + private static class Factory implements InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + return new Instruction35mi(opcode, buffer, bufferIndex); + } + } +} + diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction3rmi.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction3rmi.java new file mode 100644 index 00000000..9e9624da --- /dev/null +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction3rmi.java @@ -0,0 +1,107 @@ +/* + * 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.*; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.Util.AnnotatedOutput; +import org.jf.dexlib.Util.NumberUtils; + +public class Instruction3rmi extends Instruction implements RegisterRangeInstruction, OdexedInvokeInline { + public static final InstructionFactory Factory = new Factory(); + private byte regCount; + private short startReg; + private short inlineIndex; + + public Instruction3rmi(Opcode opcode, short regCount, int startReg, int inlineIndex) { + super(opcode); + + if (regCount >= 1 << 8) { + throw new RuntimeException("regCount must be less than 256"); + } + 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"); + } + + if (inlineIndex >= 1 << 16) { + throw new RuntimeException("The method index must be less than 65536"); + } + + this.regCount = (byte)regCount; + this.startReg = (short)startReg; + this.inlineIndex = (short)inlineIndex; + } + + private Instruction3rmi(Opcode opcode, byte[] buffer, int bufferIndex) { + super(opcode); + + this.regCount = (byte)NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); + this.inlineIndex = (short)NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 2); + this.startReg = (short)NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 4); + } + + protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) { + out.writeByte(opcode.value); + out.writeByte(regCount); + out.writeShort(inlineIndex); + out.writeShort(startReg); + } + + public Format getFormat() { + return Format.Format3rms; + } + + public short getRegCount() { + return (short)(regCount & 0xFF); + } + + public int getStartRegister() { + return startReg & 0xFFFF; + } + + public int getInlineIndex() { + return inlineIndex & 0xFFFF; + } + + private static class Factory implements InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + return new Instruction3rmi(opcode, buffer, bufferIndex); + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/OdexedInvokeInline.java b/dexlib/src/main/java/org/jf/dexlib/Code/OdexedInvokeInline.java new file mode 100644 index 00000000..1f077fa0 --- /dev/null +++ b/dexlib/src/main/java/org/jf/dexlib/Code/OdexedInvokeInline.java @@ -0,0 +1,36 @@ +/* + * 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; + +public interface OdexedInvokeInline { + int getInlineIndex(); +} 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 65dc077f..24e2e2b4 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Opcode.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Opcode.java @@ -264,8 +264,8 @@ public enum Opcode 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), THROW_VERIFICATION_ERROR((byte)0xed, "throw-verification-error", ReferenceType.none, Format.Format20bc, Opcode.ODEX_ONLY | Opcode.CAN_THROW), - 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((byte)0xee, "execute-inline", ReferenceType.none, Format.Format35mi, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT), + EXECUTE_INLINE_RANGE((byte)0xef, "execute-inline/range", ReferenceType.none, Format.Format3rmi, 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.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), diff --git a/smali/src/main/antlr3/org/jf/smali/smaliLexer.g b/smali/src/main/antlr3/org/jf/smali/smaliLexer.g index ceac9545..c07970ea 100644 --- a/smali/src/main/antlr3/org/jf/smali/smaliLexer.g +++ b/smali/src/main/antlr3/org/jf/smali/smaliLexer.g @@ -343,7 +343,10 @@ VERIFICATION_ERROR_TYPE | 'class-change-error' | 'instantiation-error'; -VTABLE_OFFSET +INLINE_INDEX + : 'inline@0x' HEX_DIGIT+; + +VTABLE_INDEX : 'vtable@0x' HEX_DIGIT+; FIELD_OFFSET @@ -663,9 +666,11 @@ INSTRUCTION_FORMAT35c_TYPE INSTRUCTION_FORMAT35s_METHOD : 'invoke-direct-empty'; +INSTRUCTION_FORMAT35mi_METHOD + : 'execute-inline'; + INSTRUCTION_FORMAT35ms_METHOD - : 'execute-inline' - | 'invoke-virtual-quick' + : 'invoke-virtual-quick' | 'invoke-super-quick'; INSTRUCTION_FORMAT3rc_METHOD @@ -678,9 +683,11 @@ INSTRUCTION_FORMAT3rc_METHOD INSTRUCTION_FORMAT3rc_TYPE : 'filled-new-array/range'; +INSTRUCTION_FORMAT3rmi_METHOD + : 'execute-inline/range'; + INSTRUCTION_FORMAT3rms_METHOD - : 'execute-inline/range' - | 'invoke-virtual-quick/range' + : 'invoke-virtual-quick/range' | 'invoke-super-quick/range'; INSTRUCTION_FORMAT51l diff --git a/smali/src/main/antlr3/org/jf/smali/smaliParser.g b/smali/src/main/antlr3/org/jf/smali/smaliParser.g index 942b6ca6..e69e4111 100644 --- a/smali/src/main/antlr3/org/jf/smali/smaliParser.g +++ b/smali/src/main/antlr3/org/jf/smali/smaliParser.g @@ -459,6 +459,7 @@ simple_name | INSTRUCTION_FORMAT35c_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT35c_METHOD] | INSTRUCTION_FORMAT35c_TYPE -> SIMPLE_NAME[$INSTRUCTION_FORMAT35c_TYPE] | INSTRUCTION_FORMAT35s_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT35s_METHOD] + | INSTRUCTION_FORMAT35mi_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT35mi_METHOD] | INSTRUCTION_FORMAT35ms_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT35ms_METHOD] | INSTRUCTION_FORMAT51l -> SIMPLE_NAME[$INSTRUCTION_FORMAT51l]; @@ -806,8 +807,13 @@ instruction returns [int size] { throwOdexedInstructionException(input, $INSTRUCTION_FORMAT35s_METHOD.text); } - | //e.g. invoke-virtual-range {v0, v1}, vtable@0x4 - INSTRUCTION_FORMAT35ms_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA VTABLE_OFFSET + | //e.g. execute-inline {v0, v1}, inline@0x4 + INSTRUCTION_FORMAT35mi_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA INLINE_INDEX + { + throwOdexedInstructionException(input, $INSTRUCTION_FORMAT35mi_METHOD.text); + } + | //e.g. invoke-virtual-quick {v0, v1}, vtable@0x4 + INSTRUCTION_FORMAT35ms_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA VTABLE_INDEX { throwOdexedInstructionException(input, $INSTRUCTION_FORMAT35ms_METHOD.text); } @@ -817,8 +823,13 @@ instruction returns [int size] | //e.g. filled-new-array/range {v0..v6}, I INSTRUCTION_FORMAT3rc_TYPE OPEN_BRACE register_range CLOSE_BRACE COMMA nonvoid_type_descriptor {$size = Format.Format3rc.size;} -> ^(I_STATEMENT_FORMAT3rc_TYPE[$start, "I_STATEMENT_FORMAT3rc_TYPE"] INSTRUCTION_FORMAT3rc_TYPE register_range nonvoid_type_descriptor) + | //e.g. execute-inline/range {v0 .. v10}, inline@0x14 + INSTRUCTION_FORMAT3rmi_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA INLINE_INDEX + { + throwOdexedInstructionException(input, $INSTRUCTION_FORMAT3rmi_METHOD.text); + } | //e.g. invoke-virtual-quick/range {v0 .. v10}, vtable@0x14 - INSTRUCTION_FORMAT3rms_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA VTABLE_OFFSET + INSTRUCTION_FORMAT3rms_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA VTABLE_INDEX { throwOdexedInstructionException(input, $INSTRUCTION_FORMAT3rms_METHOD.text); } diff --git a/smali/src/main/jflex/smaliLexer.flex b/smali/src/main/jflex/smaliLexer.flex index ab1dca9b..8697b8d7 100644 --- a/smali/src/main/jflex/smaliLexer.flex +++ b/smali/src/main/jflex/smaliLexer.flex @@ -369,7 +369,8 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayDescriptor} return newToken(VERIFICATION_ERROR_TYPE); } - "vtable@0x" {HexDigit}+ { return newToken(VTABLE_OFFSET); } + "inline@0x" {HexDigit}+ { return newToken(INLINE_INDEX); } + "vtable@0x" {HexDigit}+ { return newToken(VTABLE_INDEX); } "field@0x" {HexDigit}+ { return newToken(FIELD_OFFSET); } "+" {Integer} { return newToken(OFFSET); } @@ -536,7 +537,11 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayDescriptor} return newToken(INSTRUCTION_FORMAT35s_METHOD); } - "execute-inline" | "invoke-virtual-quick" | "invoke-super-quick" { + "execute-inline" { + return newToken(INSTRUCTION_FORMAT35mi_METHOD); + } + + "invoke-virtual-quick" | "invoke-super-quick" { return newToken(INSTRUCTION_FORMAT35ms_METHOD); } @@ -549,7 +554,11 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayDescriptor} return newToken(INSTRUCTION_FORMAT3rc_TYPE); } - "execute-inline/range" | "invoke-virtual-quick/range" | "invoke-super-quick/range" { + "execute-inline/range" { + return newToken(INSTRUCTION_FORMAT3rmi_METHOD); + } + + "invoke-virtual-quick/range" | "invoke-super-quick/range" { return newToken(INSTRUCTION_FORMAT3rms_METHOD); } diff --git a/smali/src/test/resources/LexerTest/InstructionTest.smali b/smali/src/test/resources/LexerTest/InstructionTest.smali index e5fa785f..7a7c3352 100644 --- a/smali/src/test/resources/LexerTest/InstructionTest.smali +++ b/smali/src/test/resources/LexerTest/InstructionTest.smali @@ -219,6 +219,7 @@ invoke-super/range invoke-direct/range invoke-static/range filled-new-array/range +execute-inline/range invoke-virtual-quick/range invoke-super-quick/range const-wide \ No newline at end of file diff --git a/smali/src/test/resources/LexerTest/InstructionTest.tokens b/smali/src/test/resources/LexerTest/InstructionTest.tokens index a4b1b74b..23e48956 100644 --- a/smali/src/test/resources/LexerTest/InstructionTest.tokens +++ b/smali/src/test/resources/LexerTest/InstructionTest.tokens @@ -211,7 +211,7 @@ INSTRUCTION_FORMAT35c_METHOD("invoke-interface") INSTRUCTION_FORMAT35c_TYPE("filled-new-array") INSTRUCTION_FORMAT35s_METHOD("invoke-direct-empty") INSTRUCTION_FORMAT20bc("throw-verification-error") -INSTRUCTION_FORMAT35ms_METHOD("execute-inline") +INSTRUCTION_FORMAT35mi_METHOD("execute-inline") INSTRUCTION_FORMAT35ms_METHOD("invoke-virtual-quick") INSTRUCTION_FORMAT35ms_METHOD("invoke-super-quick") INSTRUCTION_FORMAT3rc_METHOD("invoke-virtual/range") @@ -219,6 +219,7 @@ INSTRUCTION_FORMAT3rc_METHOD("invoke-super/range") INSTRUCTION_FORMAT3rc_METHOD("invoke-direct/range") INSTRUCTION_FORMAT3rc_METHOD("invoke-static/range") INSTRUCTION_FORMAT3rc_TYPE("filled-new-array/range") +INSTRUCTION_FORMAT3rmi_METHOD("execute-inline/range") INSTRUCTION_FORMAT3rms_METHOD("invoke-virtual-quick/range") INSTRUCTION_FORMAT3rms_METHOD("invoke-super-quick/range") INSTRUCTION_FORMAT51l("const-wide") \ No newline at end of file diff --git a/smali/src/test/resources/LexerTest/MiscTest.smali b/smali/src/test/resources/LexerTest/MiscTest.smali index 3c280e8f..32bbd272 100644 --- a/smali/src/test/resources/LexerTest/MiscTest.smali +++ b/smali/src/test/resources/LexerTest/MiscTest.smali @@ -45,6 +45,10 @@ illegal-method-access class-change-error instantiation-error +inline@0xABCD +inline@0x0123 +inline@0x0123ABCD + vtable@0xABCD vtable@0x0123 vtable@0x0123ABCD @@ -53,6 +57,9 @@ field@0xABCD field@0x0123 field@0x0123ABCD +inline@ +inline@zzz +inline@abcd vtable@ vtable@zzz vtable@abcd diff --git a/smali/src/test/resources/LexerTest/MiscTest.tokens b/smali/src/test/resources/LexerTest/MiscTest.tokens index fda05c45..841c9935 100644 --- a/smali/src/test/resources/LexerTest/MiscTest.tokens +++ b/smali/src/test/resources/LexerTest/MiscTest.tokens @@ -45,14 +45,21 @@ VERIFICATION_ERROR_TYPE("illegal-method-access") VERIFICATION_ERROR_TYPE("class-change-error") VERIFICATION_ERROR_TYPE("instantiation-error") -VTABLE_OFFSET("vtable@0xABCD") -VTABLE_OFFSET("vtable@0x0123") -VTABLE_OFFSET("vtable@0x0123ABCD") +INLINE_INDEX("inline@0xABCD") +INLINE_INDEX("inline@0x0123") +INLINE_INDEX("inline@0x0123ABCD") + +VTABLE_INDEX("vtable@0xABCD") +VTABLE_INDEX("vtable@0x0123") +VTABLE_INDEX("vtable@0x0123ABCD") FIELD_OFFSET("field@0xABCD") FIELD_OFFSET("field@0x0123") FIELD_OFFSET("field@0x0123ABCD") +SIMPLE_NAME("inline") INVALID_TOKEN("@") +SIMPLE_NAME("inline") INVALID_TOKEN("@") SIMPLE_NAME("zzz") +SIMPLE_NAME("inline") INVALID_TOKEN("@") SIMPLE_NAME("abcd") SIMPLE_NAME("vtable") INVALID_TOKEN("@") SIMPLE_NAME("vtable") INVALID_TOKEN("@") SIMPLE_NAME("zzz") SIMPLE_NAME("vtable") INVALID_TOKEN("@") SIMPLE_NAME("abcd")