/* * Copyright (c) 2009-2012 Panxiaobo * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.googlecode.dex2jar.reader; import java.util.Map; import com.googlecode.dex2jar.DexException; import com.googlecode.dex2jar.DexLabel; import com.googlecode.dex2jar.Method; import com.googlecode.dex2jar.OdexOpcodes; import com.googlecode.dex2jar.visitors.DexCodeVisitor; import com.googlecode.dex2jar.visitors.OdexCodeVisitor; /** * @author <a href="mailto:pxb1988@gmail.com">Panxiaobo</a> * @version $Rev$ */ /* default */class DexOpcodeAdapter implements OdexOpcodes, DexInternalOpcode { private DexCodeVisitor dcv; private DexFileReader dex; private Map<Integer, DexLabel> labels; private int offset; /** * @param dex * @param labels */ /* package */DexOpcodeAdapter(DexFileReader dex, Map<Integer, DexLabel> labels, DexCodeVisitor dcv) { super(); this.dex = dex; this.labels = labels; this.dcv = dcv; } private DexLabel getLabel(int offset) { return labels.get(this.offset + offset); } /* package */void offset(int currentOffset) { this.offset = currentOffset; DexLabel label = getLabel(0); if (label != null) { dcv.visitLabel(label); } } public void visitFillArrayStmt(int opcode, int aA, int elemWidth, int initLength, Object[] values) { dcv.visitFillArrayStmt(opcode, aA, elemWidth, initLength, values); } public void visitLookupSwitchStmt(int opcode, int aA, int defaultOffset, int[] cases, int[] iLabel) { DexLabel[] labels = new DexLabel[iLabel.length]; for (int i = 0; i < iLabel.length; i++) { labels[i] = getLabel(iLabel[i]); } dcv.visitLookupSwitchStmt(opcode, aA, getLabel(defaultOffset), cases, labels); } public void visitTableSwitchStmt(int opcode, int aA, int defaultOffset, int first_case, int last_case, int[] iLabel) { DexLabel[] labels = new DexLabel[iLabel.length]; for (int i = 0; i < iLabel.length; i++) { labels[i] = getLabel(iLabel[i]); } dcv.visitTableSwitchStmt(opcode, aA, getLabel(defaultOffset), first_case, last_case, labels); } /** * <pre> * OP_GOTO * OP_GOTO_16 * OP_GOTO_32 * </pre> * * @param opcode * @param offset */ public void x0t(int opcode, int offset) { switch (opcode) { case OP_GOTO: case OP_GOTO_16: case OP_GOTO_32: dcv.visitJumpStmt(OP_GOTO, getLabel(offset)); break; default: throw new RuntimeException(""); } } /** * <pre> * OP_NOP * OP_RETURN_VOID * </pre> * * @param opcode */ public void x0x(int opcode) { switch (opcode) { case OP_NOP: break; case OP_RETURN_VOID: case OP_RETURN_VOID_BARRIER: dcv.visitReturnStmt(OP_RETURN_VOID); break; default: throw new RuntimeException(""); } } public void x1c(int opcode, int a, int b) { switch (opcode) { case OP_CONST_STRING: case OP_CONST_STRING_JUMBO: dcv.visitConstStmt(OP_CONST_STRING, a, dex.getString(b), TYPE_OBJECT); break; case OP_CONST_CLASS: case OP_CONST_CLASS_JUMBO: dcv.visitConstStmt(OP_CONST_CLASS, a, dex.getType(b), TYPE_OBJECT); break; case OP_CHECK_CAST: case OP_CHECK_CAST_JUMBO: dcv.visitClassStmt(OP_CHECK_CAST, a, dex.getType(b)); break; case OP_NEW_INSTANCE: case OP_NEW_INSTANCE_JUMBO: dcv.visitClassStmt(OP_NEW_INSTANCE, a, dex.getType(b)); break; case OP_SGET: case OP_SGET_JUMBO: case OP_SGET_VOLATILE: case OP_SGET_VOLATILE_JUMBO: dcv.visitFieldStmt(OP_SGET, a, dex.getField(b), TYPE_SINGLE); break; case OP_SGET_WIDE: case OP_SGET_WIDE_JUMBO: case OP_SGET_WIDE_VOLATILE: case OP_SGET_WIDE_VOLATILE_JUMBO: dcv.visitFieldStmt(OP_SGET, a, dex.getField(b), TYPE_WIDE); break; case OP_SGET_OBJECT: case OP_SGET_OBJECT_JUMBO: case OP_SGET_OBJECT_VOLATILE: case OP_SGET_OBJECT_VOLATILE_JUMBO: dcv.visitFieldStmt(OP_SGET, a, dex.getField(b), TYPE_OBJECT); break; case OP_SGET_BOOLEAN: case OP_SGET_BOOLEAN_JUMBO: dcv.visitFieldStmt(OP_SGET, a, dex.getField(b), TYPE_BOOLEAN); break; case OP_SGET_BYTE: case OP_SGET_BYTE_JUMBO: dcv.visitFieldStmt(OP_SGET, a, dex.getField(b), TYPE_BYTE); break; case OP_SGET_CHAR: case OP_SGET_CHAR_JUMBO: dcv.visitFieldStmt(OP_SGET, a, dex.getField(b), TYPE_CHAR); break; case OP_SGET_SHORT: case OP_SGET_SHORT_JUMBO: dcv.visitFieldStmt(OP_SGET, a, dex.getField(b), TYPE_SHORT); break; case OP_SPUT: case OP_SPUT_JUMBO: case OP_SPUT_VOLATILE: case OP_SPUT_VOLATILE_JUMBO: dcv.visitFieldStmt(OP_SPUT, a, dex.getField(b), TYPE_SINGLE); break; case OP_SPUT_WIDE: case OP_SPUT_WIDE_JUMBO: case OP_SPUT_WIDE_VOLATILE: case OP_SPUT_WIDE_VOLATILE_JUMBO: dcv.visitFieldStmt(OP_SPUT, a, dex.getField(b), TYPE_WIDE); break; case OP_SPUT_OBJECT: case OP_SPUT_OBJECT_JUMBO: case OP_SPUT_OBJECT_VOLATILE: case OP_SPUT_OBJECT_VOLATILE_JUMBO: dcv.visitFieldStmt(OP_SPUT, a, dex.getField(b), TYPE_OBJECT); break; case OP_SPUT_BOOLEAN: case OP_SPUT_BOOLEAN_JUMBO: dcv.visitFieldStmt(OP_SPUT, a, dex.getField(b), TYPE_BOOLEAN); break; case OP_SPUT_BYTE: case OP_SPUT_BYTE_JUMBO: dcv.visitFieldStmt(OP_SPUT, a, dex.getField(b), TYPE_BYTE); break; case OP_SPUT_CHAR: case OP_SPUT_CHAR_JUMBO: dcv.visitFieldStmt(OP_SPUT, a, dex.getField(b), TYPE_CHAR); break; case OP_SPUT_SHORT: case OP_SPUT_SHORT_JUMBO: dcv.visitFieldStmt(OP_SPUT, a, dex.getField(b), TYPE_SHORT); break; default: throw new RuntimeException(""); } } public void x1h(int opcode, int a, int b) { switch (opcode) { case OP_CONST_HIGH16: dcv.visitConstStmt(OP_CONST, a, b << 16, TYPE_SINGLE); break; case OP_CONST_WIDE_HIGH16: dcv.visitConstStmt(OP_CONST, a, ((long) b) << 48, TYPE_WIDE); break; default: throw new RuntimeException(""); } } public void x1i(int opcode, int a, int b) { switch (opcode) { case OP_CONST: dcv.visitConstStmt(opcode, a, b, TYPE_SINGLE); break; case OP_CONST_WIDE_32: dcv.visitConstStmt(OP_CONST, a, (long) b, TYPE_WIDE); break; default: throw new RuntimeException(""); } } public void x1l(int opcode, int a, long b) { switch (opcode) { case OP_CONST_WIDE: dcv.visitConstStmt(OP_CONST, a, b, TYPE_WIDE); break; default: throw new RuntimeException(""); } } /** * OP_CONST_4 * * @param opcode * @param a * @param b */ public void x1n(int opcode, int a, int b) { switch (opcode) { case OP_CONST_4: dcv.visitConstStmt(OP_CONST, a, b, TYPE_SINGLE); break; default: throw new RuntimeException(""); } } public void x1s(int opcode, int a, int b) { switch (opcode) { case OP_CONST_16: dcv.visitConstStmt(OP_CONST, a, b, TYPE_SINGLE); break; case OP_CONST_WIDE_16: dcv.visitConstStmt(OP_CONST, a, (long) b, TYPE_WIDE); break; default: throw new RuntimeException(""); } } public void x1t(int opcode, int a, int offset) { switch (opcode) { case OP_IF_EQZ: case OP_IF_NEZ: case OP_IF_LTZ: case OP_IF_GEZ: case OP_IF_GTZ: case OP_IF_LEZ: dcv.visitJumpStmt(opcode, a, getLabel(offset)); break; default: throw new RuntimeException(""); } } public void x1x(int opcode, int a) { switch (opcode) { case OP_MOVE_RESULT: dcv.visitMoveStmt(OP_MOVE_RESULT, a, TYPE_SINGLE); break; case OP_MOVE_RESULT_WIDE: dcv.visitMoveStmt(OP_MOVE_RESULT, a, TYPE_WIDE); break; case OP_MOVE_RESULT_OBJECT: dcv.visitMoveStmt(OP_MOVE_RESULT, a, TYPE_OBJECT); break; case OP_MOVE_EXCEPTION: dcv.visitMoveStmt(OP_MOVE_EXCEPTION, a, TYPE_OBJECT); break; case OP_RETURN: dcv.visitReturnStmt(OP_RETURN, a, TYPE_SINGLE); break; case OP_RETURN_WIDE: dcv.visitReturnStmt(OP_RETURN, a, TYPE_WIDE); break; case OP_RETURN_OBJECT: dcv.visitReturnStmt(OP_RETURN, a, TYPE_OBJECT); break; case OP_THROW: dcv.visitReturnStmt(opcode, a, TYPE_OBJECT); break; case OP_MONITOR_ENTER: case OP_MONITOR_EXIT: dcv.visitMonitorStmt(opcode, a); break; default: throw new RuntimeException(""); } } public void x2b(int opcode, int a, int b, int c) { switch (opcode) { case OP_ADD_INT_LIT8: case OP_RSUB_INT_LIT8: case OP_MUL_INT_LIT8: case OP_DIV_INT_LIT8: case OP_REM_INT_LIT8: case OP_AND_INT_LIT8: case OP_OR_INT_LIT8: case OP_XOR_INT_LIT8: case OP_SHL_INT_LIT8: case OP_SHR_INT_LIT8: case OP_USHR_INT_LIT8: dcv.visitBinopLitXStmt(opcode - (OP_ADD_INT_LIT8 - OP_ADD_INT_LIT_X), a, b, c); break; default: throw new RuntimeException(""); } } public void x2c(int opcode, int a, int b, int c) { switch (opcode) { case OP_INSTANCE_OF: case OP_INSTANCE_OF_JUMBO: dcv.visitClassStmt(OP_INSTANCE_OF, a, b, dex.getType(c)); break; case OP_NEW_ARRAY: case OP_NEW_ARRAY_JUMBO: dcv.visitClassStmt(OP_NEW_ARRAY, a, b, dex.getType(c)); break; case OP_IGET: case OP_IGET_JUMBO: case OP_IGET_VOLATILE: case OP_IGET_VOLATILE_JUMBO: dcv.visitFieldStmt(OP_IGET, a, b, dex.getField(c), TYPE_SINGLE); break; case OP_IGET_WIDE: case OP_IGET_WIDE_JUMBO: case OP_IGET_WIDE_VOLATILE: case OP_IGET_WIDE_VOLATILE_JUMBO: dcv.visitFieldStmt(OP_IGET, a, b, dex.getField(c), TYPE_WIDE); break; case OP_IGET_OBJECT: case OP_IGET_OBJECT_JUMBO: case OP_IGET_OBJECT_VOLATILE: case OP_IGET_OBJECT_VOLATILE_JUMBO: dcv.visitFieldStmt(OP_IGET, a, b, dex.getField(c), TYPE_OBJECT); break; case OP_IGET_BOOLEAN: case OP_IGET_BOOLEAN_JUMBO: dcv.visitFieldStmt(OP_IGET, a, b, dex.getField(c), TYPE_BOOLEAN); break; case OP_IGET_BYTE: case OP_IGET_BYTE_JUMBO: dcv.visitFieldStmt(OP_IGET, a, b, dex.getField(c), TYPE_BYTE); break; case OP_IGET_CHAR: case OP_IGET_CHAR_JUMBO: dcv.visitFieldStmt(OP_IGET, a, b, dex.getField(c), TYPE_CHAR); break; case OP_IGET_SHORT: case OP_IGET_SHORT_JUMBO: dcv.visitFieldStmt(OP_IGET, a, b, dex.getField(c), TYPE_SHORT); break; case OP_IPUT: case OP_IPUT_JUMBO: case OP_IPUT_VOLATILE: case OP_IPUT_VOLATILE_JUMBO: dcv.visitFieldStmt(OP_IPUT, a, b, dex.getField(c), TYPE_SINGLE); break; case OP_IPUT_WIDE: case OP_IPUT_WIDE_JUMBO: case OP_IPUT_WIDE_VOLATILE: case OP_IPUT_WIDE_VOLATILE_JUMBO: dcv.visitFieldStmt(OP_IPUT, a, b, dex.getField(c), TYPE_WIDE); break; case OP_IPUT_OBJECT: case OP_IPUT_OBJECT_JUMBO: case OP_IPUT_OBJECT_VOLATILE: case OP_IPUT_OBJECT_VOLATILE_JUMBO: dcv.visitFieldStmt(OP_IPUT, a, b, dex.getField(c), TYPE_OBJECT); break; case OP_IPUT_BOOLEAN: case OP_IPUT_BOOLEAN_JUMBO: dcv.visitFieldStmt(OP_IPUT, a, b, dex.getField(c), TYPE_BOOLEAN); break; case OP_IPUT_BYTE: case OP_IPUT_BYTE_JUMBO: dcv.visitFieldStmt(OP_IPUT, a, b, dex.getField(c), TYPE_BYTE); break; case OP_IPUT_CHAR: case OP_IPUT_CHAR_JUMBO: dcv.visitFieldStmt(OP_IPUT, a, b, dex.getField(c), TYPE_CHAR); break; case OP_IPUT_SHORT: case OP_IPUT_SHORT_JUMBO: dcv.visitFieldStmt(OP_IPUT, a, b, dex.getField(c), TYPE_SHORT); break; default: throw new RuntimeException(""); } } public void x2s(int opcode, int a, int b, int c) { switch (opcode) { case OP_ADD_INT_LIT16: case OP_RSUB_INT: case OP_MUL_INT_LIT16: case OP_DIV_INT_LIT16: case OP_REM_INT_LIT16: case OP_AND_INT_LIT16: case OP_OR_INT_LIT16: case OP_XOR_INT_LIT16: dcv.visitBinopLitXStmt(opcode - (OP_ADD_INT_LIT16 - OP_ADD_INT_LIT_X), a, b, c); break; default: throw new RuntimeException(""); } } public void x2t(int opcode, int a, int b, int c) { switch (opcode) { case OP_IF_EQ: case OP_IF_NE: case OP_IF_LT: case OP_IF_GE: case OP_IF_GT: case OP_IF_LE: dcv.visitJumpStmt(opcode, a, b, getLabel(c)); break; default: throw new RuntimeException(""); } } public void x2x(int opcode, int a, int b) { switch (opcode) { case OP_MOVE: case OP_MOVE_FROM16: case OP_MOVE_16: dcv.visitMoveStmt(OP_MOVE, a, b, TYPE_SINGLE); break; case OP_MOVE_WIDE: case OP_MOVE_WIDE_FROM16: case OP_MOVE_WIDE_16: dcv.visitMoveStmt(OP_MOVE, a, b, TYPE_WIDE); break; case OP_MOVE_OBJECT: case OP_MOVE_OBJECT_FROM16: case OP_MOVE_OBJECT_16: dcv.visitMoveStmt(OP_MOVE, a, b, TYPE_OBJECT); break; case OP_ARRAY_LENGTH: dcv.visitUnopStmt(OP_ARRAY_LENGTH, a, b, TYPE_INT); break; case OP_NEG_INT: case OP_NOT_INT: dcv.visitUnopStmt(opcode - (OP_NEG_INT - OP_NEG), a, b, TYPE_INT); break; case OP_NEG_LONG: case OP_NOT_LONG: dcv.visitUnopStmt(opcode - (OP_NEG_LONG - OP_NEG), a, b, TYPE_LONG); break; case OP_NEG_FLOAT: dcv.visitUnopStmt(OP_NEG, a, b, TYPE_FLOAT); break; case OP_NEG_DOUBLE: dcv.visitUnopStmt(OP_NEG, a, b, TYPE_DOUBLE); break; case OP_INT_TO_LONG: dcv.visitUnopStmt(OP_X_TO_Y, a, b, TYPE_INT, TYPE_LONG); break; case OP_INT_TO_FLOAT: dcv.visitUnopStmt(OP_X_TO_Y, a, b, TYPE_INT, TYPE_FLOAT); break; case OP_INT_TO_DOUBLE: dcv.visitUnopStmt(OP_X_TO_Y, a, b, TYPE_INT, TYPE_DOUBLE); break; case OP_LONG_TO_INT: dcv.visitUnopStmt(OP_X_TO_Y, a, b, TYPE_LONG, TYPE_INT); break; case OP_LONG_TO_FLOAT: dcv.visitUnopStmt(OP_X_TO_Y, a, b, TYPE_LONG, TYPE_FLOAT); break; case OP_LONG_TO_DOUBLE: dcv.visitUnopStmt(OP_X_TO_Y, a, b, TYPE_LONG, TYPE_DOUBLE); break; case OP_FLOAT_TO_INT: dcv.visitUnopStmt(OP_X_TO_Y, a, b, TYPE_FLOAT, TYPE_INT); break; case OP_FLOAT_TO_LONG: dcv.visitUnopStmt(OP_X_TO_Y, a, b, TYPE_FLOAT, TYPE_LONG); break; case OP_FLOAT_TO_DOUBLE: dcv.visitUnopStmt(OP_X_TO_Y, a, b, TYPE_FLOAT, TYPE_DOUBLE); break; case OP_DOUBLE_TO_INT: dcv.visitUnopStmt(OP_X_TO_Y, a, b, TYPE_DOUBLE, TYPE_INT); break; case OP_DOUBLE_TO_LONG: dcv.visitUnopStmt(OP_X_TO_Y, a, b, TYPE_DOUBLE, TYPE_LONG); break; case OP_DOUBLE_TO_FLOAT: dcv.visitUnopStmt(OP_X_TO_Y, a, b, TYPE_DOUBLE, TYPE_FLOAT); break; case OP_INT_TO_BYTE: dcv.visitUnopStmt(OP_X_TO_Y, a, b, TYPE_INT, TYPE_BYTE); break; case OP_INT_TO_CHAR: dcv.visitUnopStmt(OP_X_TO_Y, a, b, TYPE_INT, TYPE_CHAR); break; case OP_INT_TO_SHORT: dcv.visitUnopStmt(OP_X_TO_Y, a, b, TYPE_INT, TYPE_SHORT); break; case OP_ADD_INT_2ADDR: case OP_SUB_INT_2ADDR: case OP_MUL_INT_2ADDR: case OP_DIV_INT_2ADDR: case OP_REM_INT_2ADDR: case OP_AND_INT_2ADDR: case OP_OR_INT_2ADDR: case OP_XOR_INT_2ADDR: case OP_SHL_INT_2ADDR: case OP_SHR_INT_2ADDR: case OP_USHR_INT_2ADDR: dcv.visitBinopStmt(opcode - (OP_ADD_INT_2ADDR - OP_ADD), a, a, b, TYPE_INT); break; case OP_ADD_LONG_2ADDR: case OP_SUB_LONG_2ADDR: case OP_MUL_LONG_2ADDR: case OP_DIV_LONG_2ADDR: case OP_REM_LONG_2ADDR: case OP_AND_LONG_2ADDR: case OP_OR_LONG_2ADDR: case OP_XOR_LONG_2ADDR: case OP_SHL_LONG_2ADDR: case OP_SHR_LONG_2ADDR: case OP_USHR_LONG_2ADDR: dcv.visitBinopStmt(opcode - (OP_ADD_LONG_2ADDR - OP_ADD), a, a, b, TYPE_LONG); break; case OP_ADD_FLOAT_2ADDR: case OP_SUB_FLOAT_2ADDR: case OP_MUL_FLOAT_2ADDR: case OP_DIV_FLOAT_2ADDR: case OP_REM_FLOAT_2ADDR: dcv.visitBinopStmt(opcode - (OP_ADD_FLOAT_2ADDR - OP_ADD), a, a, b, TYPE_FLOAT); break; case OP_ADD_DOUBLE_2ADDR: case OP_SUB_DOUBLE_2ADDR: case OP_MUL_DOUBLE_2ADDR: case OP_DIV_DOUBLE_2ADDR: case OP_REM_DOUBLE_2ADDR: dcv.visitBinopStmt(opcode - (OP_ADD_DOUBLE_2ADDR - OP_ADD), a, a, b, TYPE_DOUBLE); break; default: throw new RuntimeException(""); } } public void x3x(int opcode, int a, int b, int c) { switch (opcode) { case OP_CMPL_FLOAT: dcv.visitCmpStmt(OP_CMPL, a, b, c, TYPE_FLOAT); break; case OP_CMPG_FLOAT: dcv.visitCmpStmt(OP_CMPG, a, b, c, TYPE_FLOAT); break; case OP_CMPL_DOUBLE: dcv.visitCmpStmt(OP_CMPL, a, b, c, TYPE_DOUBLE); break; case OP_CMPG_DOUBLE: dcv.visitCmpStmt(OP_CMPG, a, b, c, TYPE_DOUBLE); break; case OP_CMP_LONG: dcv.visitCmpStmt(OP_CMP, a, b, c, TYPE_LONG); break; case OP_AGET: dcv.visitArrayStmt(OP_AGET, a, b, c, TYPE_SINGLE); break; case OP_AGET_WIDE: dcv.visitArrayStmt(OP_AGET, a, b, c, TYPE_WIDE); break; case OP_AGET_OBJECT: dcv.visitArrayStmt(OP_AGET, a, b, c, TYPE_OBJECT); break; case OP_AGET_BOOLEAN: dcv.visitArrayStmt(OP_AGET, a, b, c, TYPE_BOOLEAN); break; case OP_AGET_BYTE: dcv.visitArrayStmt(OP_AGET, a, b, c, TYPE_BYTE); break; case OP_AGET_CHAR: dcv.visitArrayStmt(OP_AGET, a, b, c, TYPE_CHAR); break; case OP_AGET_SHORT: dcv.visitArrayStmt(OP_AGET, a, b, c, TYPE_SHORT); break; case OP_APUT: dcv.visitArrayStmt(OP_APUT, a, b, c, TYPE_SINGLE); break; case OP_APUT_WIDE: dcv.visitArrayStmt(OP_APUT, a, b, c, TYPE_WIDE); break; case OP_APUT_OBJECT: dcv.visitArrayStmt(OP_APUT, a, b, c, TYPE_OBJECT); break; case OP_APUT_BOOLEAN: dcv.visitArrayStmt(OP_APUT, a, b, c, TYPE_BOOLEAN); break; case OP_APUT_BYTE: dcv.visitArrayStmt(OP_APUT, a, b, c, TYPE_BYTE); break; case OP_APUT_CHAR: dcv.visitArrayStmt(OP_APUT, a, b, c, TYPE_CHAR); break; case OP_APUT_SHORT: dcv.visitArrayStmt(OP_APUT, a, b, c, TYPE_SHORT); break; case OP_ADD_INT: case OP_SUB_INT: case OP_MUL_INT: case OP_DIV_INT: case OP_REM_INT: case OP_AND_INT: case OP_OR_INT: case OP_XOR_INT: case OP_SHL_INT: case OP_SHR_INT: case OP_USHR_INT: dcv.visitBinopStmt(opcode - (OP_ADD_INT - OP_ADD), a, b, c, TYPE_INT); break; case OP_ADD_LONG: case OP_SUB_LONG: case OP_MUL_LONG: case OP_DIV_LONG: case OP_REM_LONG: case OP_AND_LONG: case OP_OR_LONG: case OP_XOR_LONG: case OP_SHL_LONG: case OP_SHR_LONG: case OP_USHR_LONG: dcv.visitBinopStmt(opcode - (OP_ADD_LONG - OP_ADD), a, b, c, TYPE_LONG); break; case OP_ADD_FLOAT: case OP_SUB_FLOAT: case OP_MUL_FLOAT: case OP_DIV_FLOAT: case OP_REM_FLOAT: dcv.visitBinopStmt(opcode - (OP_ADD_FLOAT - OP_ADD), a, b, c, TYPE_FLOAT); break; case OP_ADD_DOUBLE: case OP_SUB_DOUBLE: case OP_MUL_DOUBLE: case OP_DIV_DOUBLE: case OP_REM_DOUBLE: dcv.visitBinopStmt(opcode - (OP_ADD_DOUBLE - OP_ADD), a, b, c, TYPE_DOUBLE); break; default: throw new RuntimeException(""); } } public void x5c(int opcode, int a, int c, int d, int e, int f, int g, int b) { int args[]; switch (a) { case 0: args = new int[0]; break; case 1: args = new int[] { c }; break; case 2: args = new int[] { c, d }; break; case 3: args = new int[] { c, d, e }; break; case 4: args = new int[] { c, d, e, f }; break; case 5: args = new int[] { c, d, e, f, g }; break; default: throw new RuntimeException(""); } switch (opcode) { case OP_FILLED_NEW_ARRAY: dcv.visitFilledNewArrayStmt(opcode, args, dex.getType(b)); break; case OP_INVOKE_VIRTUAL: case OP_INVOKE_SUPER: case OP_INVOKE_DIRECT: case OP_INVOKE_STATIC: case OP_INVOKE_INTERFACE: case OP_INVOKE_DIRECT_EMPTY: Method m = dex.getMethod(b); if (OP_INVOKE_DIRECT_EMPTY == opcode) { int[] nArgs; try { nArgs = reBuildArgs(OP_INVOKE_DIRECT, args, m); } catch (Exception ex) { throw new DexException(ex, "while rebuild argements for 0xF0 OP_INVOKE_DIRECT_EMPTY @0x%04x," + " this is typically because of a wrong apiLevel. current apiLevel is %d.", this.offset, dex.apiLevel); } dcv.visitMethodStmt(OP_INVOKE_DIRECT, nArgs, m); } else { int[] nArgs = reBuildArgs(opcode, args, m); dcv.visitMethodStmt(opcode, nArgs, m); } break; default: throw new RuntimeException(""); } } public void xrc(final int opcode, int a, int b, int c) { int args[] = new int[a]; for (int i = 0; i < a; i++) { args[i] = c + i; } switch (opcode) { case OP_FILLED_NEW_ARRAY_RANGE: case OP_FILLED_NEW_ARRAY_JUMBO: dcv.visitFilledNewArrayStmt(OP_FILLED_NEW_ARRAY, args, dex.getType(b)); break; case OP_INVOKE_VIRTUAL_RANGE: case OP_INVOKE_SUPER_RANGE: case OP_INVOKE_DIRECT_RANGE: case OP_INVOKE_STATIC_RANGE: case OP_INVOKE_INTERFACE_RANGE: case OP_INVOKE_VIRTUAL_JUMBO: case OP_INVOKE_SUPER_JUMBO: case OP_INVOKE_DIRECT_JUMBO: case OP_INVOKE_STATIC_JUMBO: case OP_INVOKE_INTERFACE_JUMBO: case OP_INVOKE_OBJECT_INIT_RANGE: case OP_INVOKE_OBJECT_INIT_JUMBO: int nOpcode; if (opcode == OP_INVOKE_OBJECT_INIT_RANGE || opcode == OP_INVOKE_OBJECT_INIT_JUMBO) { nOpcode = OP_INVOKE_DIRECT; } else { nOpcode = opcode - (((opcode >> 4 == 0xFF) ? OP_INVOKE_VIRTUAL_JUMBO : OP_INVOKE_VIRTUAL_RANGE) - OP_INVOKE_VIRTUAL); } Method m = dex.getMethod(b); if (opcode == OP_INVOKE_OBJECT_INIT_RANGE) {// print more detail error message for 0xF0 int[] nArgs; try { nArgs = reBuildArgs(nOpcode, args, m); } catch (Exception ex) { throw new DexException(ex, "while rebuild argements for 0xF0 OP_INVOKE_OBJECT_INIT_RANGE @0x%04x," + " this is typically because of a wrong apiLevel. current apiLevel is %d.", this.offset, dex.apiLevel); } dcv.visitMethodStmt(nOpcode, nArgs, m); } else { int[] nArgs = reBuildArgs(nOpcode, args, m); dcv.visitMethodStmt(nOpcode, nArgs, m); } break; default: throw new RuntimeException(""); } } private int[] reBuildArgs(int opcode, int[] args, Method m) { int realSize = m.getParameterTypes().length + (opcode == OP_INVOKE_STATIC ? 0 : 1); if (realSize != args.length) {// there are some double or float in args int[] nArgs = new int[realSize]; int i = 0; int j = 0; if (opcode != OP_INVOKE_STATIC) { nArgs[i++] = args[j++]; } for (String t : m.getParameterTypes()) { nArgs[i++] = args[j]; j += "J".equals(t) || "D".equals(t) ? 2 : 1; } return nArgs; } else { return args; } } public void x0bc(int opcode, int a, int b) { switch (opcode) { case OP_THROW_VERIFICATION_ERROR: Object ref; switch (a >> 6) { case 0:// type; ref = dex.getType(b); break; case 1:// field; ref = dex.getField(b); break; case 2:// method; ref = dex.getMethod(b); break; default: throw new RuntimeException(); } if (dcv instanceof OdexCodeVisitor) { ((OdexCodeVisitor) dcv).visitReturnStmt(opcode, a & 0x3F, ref); } break; } } public void x2cs(int opcode, int a, int b, int c) { switch (opcode) { case OP_IGET_QUICK: if (dcv instanceof OdexCodeVisitor) { ((OdexCodeVisitor) dcv).visitFieldStmt(OP_IGET_QUICK, a, b, c, TYPE_SINGLE); } break; case OP_IGET_WIDE_QUICK: if (dcv instanceof OdexCodeVisitor) { ((OdexCodeVisitor) dcv).visitFieldStmt(OP_IGET_QUICK, a, b, c, TYPE_WIDE); } break; case OP_IGET_OBJECT_QUICK: if (dcv instanceof OdexCodeVisitor) { ((OdexCodeVisitor) dcv).visitFieldStmt(OP_IGET_QUICK, a, b, c, TYPE_OBJECT); } break; case OP_IPUT_QUICK: if (dcv instanceof OdexCodeVisitor) { ((OdexCodeVisitor) dcv).visitFieldStmt(OP_IPUT_QUICK, a, b, c, TYPE_SINGLE); } break; case OP_IPUT_WIDE_QUICK: if (dcv instanceof OdexCodeVisitor) { ((OdexCodeVisitor) dcv).visitFieldStmt(OP_IPUT_QUICK, a, b, c, TYPE_WIDE); } break; case OP_IPUT_OBJECT_QUICK: if (dcv instanceof OdexCodeVisitor) { ((OdexCodeVisitor) dcv).visitFieldStmt(OP_IPUT_QUICK, a, b, c, TYPE_OBJECT); } break; } } public void x5mi(int opcode, int a, int c, int d, int e, int f, int g, int b) { int args[]; switch (a) { case 0: args = new int[0]; break; case 1: args = new int[] { c }; break; case 2: args = new int[] { c, d }; break; case 3: args = new int[] { c, d, e }; break; case 4: args = new int[] { c, d, e, f }; break; case 5: args = new int[] { c, d, e, f, g }; break; default: throw new RuntimeException(""); } switch (opcode) { case OP_EXECUTE_INLINE: if (dcv instanceof OdexCodeVisitor) { ((OdexCodeVisitor) dcv).visitMethodStmt(opcode, args, b); } break; } } public void x5ms(int opcode, int a, int c, int d, int e, int f, int g, int b) { int args[]; switch (a) { case 0: args = new int[0]; break; case 1: args = new int[] { c }; break; case 2: args = new int[] { c, d }; break; case 3: args = new int[] { c, d, e }; break; case 4: args = new int[] { c, d, e, f }; break; case 5: args = new int[] { c, d, e, f, g }; break; default: throw new RuntimeException(""); } switch (opcode) { case OP_INVOKE_VIRTUAL_QUICK: case OP_INVOKE_SUPER_QUICK: if (dcv instanceof OdexCodeVisitor) { ((OdexCodeVisitor) dcv).visitMethodStmt(opcode, args, b); } break; } } public void xrms(int opcode, int a, int b, int c) { int args[] = new int[a]; for (int i = 0; i < a; i++) { args[i] = c + i; } switch (opcode) { case OP_INVOKE_VIRTUAL_QUICK_RANGE: case OP_INVOKE_SUPER_QUICK_RANGE: if (dcv instanceof OdexCodeVisitor) { ((OdexCodeVisitor) dcv).visitMethodStmt(opcode - (OP_INVOKE_SUPER_QUICK_RANGE - OP_INVOKE_SUPER_QUICK), args, b); } break; } } public void xrmi(int opcode, int a, int b, int c) { int args[] = new int[a]; for (int i = 0; i < a; i++) { args[i] = c + i; } switch (opcode) { case OP_EXECUTE_INLINE_RANGE: if (dcv instanceof OdexCodeVisitor) { ((OdexCodeVisitor) dcv).visitMethodStmt(OP_EXECUTE_INLINE, args, b); } break; } } public void x0sc(int opcode, int a, int b) { // TODO Auto-generated method stub } }