Package jadx.core.dex.instructions

Source Code of jadx.core.dex.instructions.InsnDecoder

package jadx.core.dex.instructions;

import jadx.core.dex.info.FieldInfo;
import jadx.core.dex.info.MethodInfo;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.instructions.args.PrimitiveType;
import jadx.core.dex.instructions.args.RegisterArg;
import jadx.core.dex.nodes.DexNode;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.utils.InsnUtils;
import jadx.core.utils.exceptions.DecodeException;

import com.android.dex.Code;
import com.android.dx.io.OpcodeInfo;
import com.android.dx.io.Opcodes;
import com.android.dx.io.instructions.DecodedInstruction;
import com.android.dx.io.instructions.FillArrayDataPayloadDecodedInstruction;
import com.android.dx.io.instructions.PackedSwitchPayloadDecodedInstruction;
import com.android.dx.io.instructions.ShortArrayCodeInput;
import com.android.dx.io.instructions.SparseSwitchPayloadDecodedInstruction;

public class InsnDecoder {

  private final MethodNode method;
  private final DexNode dex;
  private DecodedInstruction[] insnArr;

  public InsnDecoder(MethodNode mthNode) {
    this.method = mthNode;
    this.dex = method.dex();
  }

  public void decodeInsns(Code mthCode) throws DecodeException {
    short[] encodedInstructions = mthCode.getInstructions();
    int size = encodedInstructions.length;
    DecodedInstruction[] decoded = new DecodedInstruction[size];
    ShortArrayCodeInput in = new ShortArrayCodeInput(encodedInstructions);

    try {
      while (in.hasMore()) {
        decoded[in.cursor()] = DecodedInstruction.decode(in);
      }
    } catch (Exception e) {
      throw new DecodeException(method, "", e);
    }
    insnArr = decoded;
  }

  public InsnNode[] process() throws DecodeException {
    InsnNode[] instructions = new InsnNode[insnArr.length];
    for (int i = 0; i < insnArr.length; i++) {
      DecodedInstruction rawInsn = insnArr[i];
      if (rawInsn != null) {
        InsnNode insn = decode(rawInsn, i);
        if (insn != null) {
          insn.setOffset(i);
          insn.setInsnHashCode(calcHashCode(rawInsn));
        }
        instructions[i] = insn;
      } else {
        instructions[i] = null;
      }
    }
    insnArr = null;
    return instructions;
  }

  private int calcHashCode(DecodedInstruction insn) {
    int hash = insn.getOpcode();
    hash = hash * 31 + insn.getClass().getName().hashCode();
    hash = hash * 31 + insn.getFormat().ordinal();
    hash = hash * 31 + insn.getRegisterCount();
    hash = hash * 31 + insn.getIndex();
    hash = hash * 31 + insn.getTarget();
    hash = hash * 31 + insn.getA();
    hash = hash * 31 + insn.getB();
    hash = hash * 31 + insn.getC();
    hash = hash * 31 + insn.getD();
    hash = hash * 31 + insn.getE();
    return hash;
  }

  private InsnNode decode(DecodedInstruction insn, int offset) throws DecodeException {
    switch (insn.getOpcode()) {
      case Opcodes.NOP:
      case Opcodes.PACKED_SWITCH_PAYLOAD:
      case Opcodes.SPARSE_SWITCH_PAYLOAD:
      case Opcodes.FILL_ARRAY_DATA_PAYLOAD:
        return null;

      // move-result will be process in invoke and filled-new-array instructions
      case Opcodes.MOVE_RESULT:
      case Opcodes.MOVE_RESULT_WIDE:
      case Opcodes.MOVE_RESULT_OBJECT:
        return new InsnNode(InsnType.NOP, 0);

      case Opcodes.CONST:
      case Opcodes.CONST_4:
      case Opcodes.CONST_16:
      case Opcodes.CONST_HIGH16:
        return insn(InsnType.CONST, InsnArg.reg(insn, 0, ArgType.NARROW),
            InsnArg.lit(insn, ArgType.NARROW));

      case Opcodes.CONST_WIDE:
      case Opcodes.CONST_WIDE_16:
      case Opcodes.CONST_WIDE_32:
      case Opcodes.CONST_WIDE_HIGH16:
        return insn(InsnType.CONST, InsnArg.reg(insn, 0, ArgType.WIDE),
            InsnArg.lit(insn, ArgType.WIDE));

      case Opcodes.CONST_STRING:
      case Opcodes.CONST_STRING_JUMBO: {
        InsnNode node = new ConstStringNode(dex.getString(insn.getIndex()));
        node.setResult(InsnArg.reg(insn, 0, ArgType.STRING));
        return node;
      }

      case Opcodes.CONST_CLASS: {
        InsnNode node = new ConstClassNode(dex.getType(insn.getIndex()));
        node.setResult(InsnArg.reg(insn, 0, ArgType.CLASS));
        return node;
      }

      case Opcodes.MOVE:
      case Opcodes.MOVE_16:
      case Opcodes.MOVE_FROM16:
        return insn(InsnType.MOVE,
            InsnArg.reg(insn, 0, ArgType.NARROW),
            InsnArg.reg(insn, 1, ArgType.NARROW));

      case Opcodes.MOVE_WIDE:
      case Opcodes.MOVE_WIDE_16:
      case Opcodes.MOVE_WIDE_FROM16:
        return insn(InsnType.MOVE,
            InsnArg.reg(insn, 0, ArgType.WIDE),
            InsnArg.reg(insn, 1, ArgType.WIDE));

      case Opcodes.MOVE_OBJECT:
      case Opcodes.MOVE_OBJECT_16:
      case Opcodes.MOVE_OBJECT_FROM16:
        return insn(InsnType.MOVE,
            InsnArg.reg(insn, 0, ArgType.UNKNOWN_OBJECT),
            InsnArg.reg(insn, 1, ArgType.UNKNOWN_OBJECT));

      case Opcodes.ADD_INT:
      case Opcodes.ADD_INT_2ADDR:
        return arith(insn, ArithOp.ADD, ArgType.INT);

      case Opcodes.ADD_DOUBLE:
      case Opcodes.ADD_DOUBLE_2ADDR:
        return arith(insn, ArithOp.ADD, ArgType.DOUBLE);

      case Opcodes.ADD_FLOAT:
      case Opcodes.ADD_FLOAT_2ADDR:
        return arith(insn, ArithOp.ADD, ArgType.FLOAT);

      case Opcodes.ADD_LONG:
      case Opcodes.ADD_LONG_2ADDR:
        return arith(insn, ArithOp.ADD, ArgType.LONG);

      case Opcodes.ADD_INT_LIT8:
      case Opcodes.ADD_INT_LIT16:
        return arithLit(insn, ArithOp.ADD, ArgType.INT);

      case Opcodes.SUB_INT:
      case Opcodes.SUB_INT_2ADDR:
        return arith(insn, ArithOp.SUB, ArgType.INT);

      case Opcodes.RSUB_INT_LIT8:
      case Opcodes.RSUB_INT: // LIT16
        return new ArithNode(ArithOp.SUB,
            InsnArg.reg(insn, 0, ArgType.INT),
            InsnArg.lit(insn, ArgType.INT),
            InsnArg.reg(insn, 1, ArgType.INT));

      case Opcodes.SUB_LONG:
      case Opcodes.SUB_LONG_2ADDR:
        return arith(insn, ArithOp.SUB, ArgType.LONG);

      case Opcodes.SUB_FLOAT:
      case Opcodes.SUB_FLOAT_2ADDR:
        return arith(insn, ArithOp.SUB, ArgType.FLOAT);

      case Opcodes.SUB_DOUBLE:
      case Opcodes.SUB_DOUBLE_2ADDR:
        return arith(insn, ArithOp.SUB, ArgType.DOUBLE);

      case Opcodes.MUL_INT:
      case Opcodes.MUL_INT_2ADDR:
        return arith(insn, ArithOp.MUL, ArgType.INT);

      case Opcodes.MUL_DOUBLE:
      case Opcodes.MUL_DOUBLE_2ADDR:
        return arith(insn, ArithOp.MUL, ArgType.DOUBLE);

      case Opcodes.MUL_FLOAT:
      case Opcodes.MUL_FLOAT_2ADDR:
        return arith(insn, ArithOp.MUL, ArgType.FLOAT);

      case Opcodes.MUL_LONG:
      case Opcodes.MUL_LONG_2ADDR:
        return arith(insn, ArithOp.MUL, ArgType.LONG);

      case Opcodes.MUL_INT_LIT8:
      case Opcodes.MUL_INT_LIT16:
        return arithLit(insn, ArithOp.MUL, ArgType.INT);

      case Opcodes.DIV_INT:
      case Opcodes.DIV_INT_2ADDR:
        return arith(insn, ArithOp.DIV, ArgType.INT);

      case Opcodes.REM_INT:
      case Opcodes.REM_INT_2ADDR:
        return arith(insn, ArithOp.REM, ArgType.INT);

      case Opcodes.REM_LONG:
      case Opcodes.REM_LONG_2ADDR:
        return arith(insn, ArithOp.REM, ArgType.LONG);

      case Opcodes.REM_FLOAT:
      case Opcodes.REM_FLOAT_2ADDR:
        return arith(insn, ArithOp.REM, ArgType.FLOAT);

      case Opcodes.REM_DOUBLE:
      case Opcodes.REM_DOUBLE_2ADDR:
        return arith(insn, ArithOp.REM, ArgType.DOUBLE);

      case Opcodes.DIV_DOUBLE:
      case Opcodes.DIV_DOUBLE_2ADDR:
        return arith(insn, ArithOp.DIV, ArgType.DOUBLE);

      case Opcodes.DIV_FLOAT:
      case Opcodes.DIV_FLOAT_2ADDR:
        return arith(insn, ArithOp.DIV, ArgType.FLOAT);

      case Opcodes.DIV_LONG:
      case Opcodes.DIV_LONG_2ADDR:
        return arith(insn, ArithOp.DIV, ArgType.LONG);

      case Opcodes.DIV_INT_LIT8:
      case Opcodes.DIV_INT_LIT16:
        return arithLit(insn, ArithOp.DIV, ArgType.INT);

      case Opcodes.REM_INT_LIT8:
      case Opcodes.REM_INT_LIT16:
        return arithLit(insn, ArithOp.REM, ArgType.INT);

      case Opcodes.AND_INT:
      case Opcodes.AND_INT_2ADDR:
        return arith(insn, ArithOp.AND, ArgType.INT);

      case Opcodes.AND_INT_LIT8:
      case Opcodes.AND_INT_LIT16:
        return arithLit(insn, ArithOp.AND, ArgType.INT);

      case Opcodes.XOR_INT_LIT8:
      case Opcodes.XOR_INT_LIT16:
        return arithLit(insn, ArithOp.XOR, ArgType.INT);

      case Opcodes.AND_LONG:
      case Opcodes.AND_LONG_2ADDR:
        return arith(insn, ArithOp.AND, ArgType.LONG);

      case Opcodes.OR_INT:
      case Opcodes.OR_INT_2ADDR:
        return arith(insn, ArithOp.OR, ArgType.INT);

      case Opcodes.OR_INT_LIT8:
      case Opcodes.OR_INT_LIT16:
        return arithLit(insn, ArithOp.OR, ArgType.INT);

      case Opcodes.XOR_INT:
      case Opcodes.XOR_INT_2ADDR:
        return arith(insn, ArithOp.XOR, ArgType.INT);

      case Opcodes.OR_LONG:
      case Opcodes.OR_LONG_2ADDR:
        return arith(insn, ArithOp.OR, ArgType.LONG);

      case Opcodes.XOR_LONG:
      case Opcodes.XOR_LONG_2ADDR:
        return arith(insn, ArithOp.XOR, ArgType.LONG);

      case Opcodes.USHR_INT:
      case Opcodes.USHR_INT_2ADDR:
        return arith(insn, ArithOp.USHR, ArgType.INT);

      case Opcodes.USHR_LONG:
      case Opcodes.USHR_LONG_2ADDR:
        return arith(insn, ArithOp.USHR, ArgType.LONG);

      case Opcodes.SHL_INT:
      case Opcodes.SHL_INT_2ADDR:
        return arith(insn, ArithOp.SHL, ArgType.INT);

      case Opcodes.SHL_LONG:
      case Opcodes.SHL_LONG_2ADDR:
        return arith(insn, ArithOp.SHL, ArgType.LONG);

      case Opcodes.SHR_INT:
      case Opcodes.SHR_INT_2ADDR:
        return arith(insn, ArithOp.SHR, ArgType.INT);

      case Opcodes.SHR_LONG:
      case Opcodes.SHR_LONG_2ADDR:
        return arith(insn, ArithOp.SHR, ArgType.LONG);

      case Opcodes.SHL_INT_LIT8:
        return arithLit(insn, ArithOp.SHL, ArgType.INT);
      case Opcodes.SHR_INT_LIT8:
        return arithLit(insn, ArithOp.SHR, ArgType.INT);
      case Opcodes.USHR_INT_LIT8:
        return arithLit(insn, ArithOp.USHR, ArgType.INT);

      case Opcodes.NEG_INT:
        return neg(insn, ArgType.INT);
      case Opcodes.NEG_LONG:
        return neg(insn, ArgType.LONG);
      case Opcodes.NEG_FLOAT:
        return neg(insn, ArgType.FLOAT);
      case Opcodes.NEG_DOUBLE:
        return neg(insn, ArgType.DOUBLE);

      case Opcodes.INT_TO_BYTE:
        return cast(insn, ArgType.INT, ArgType.BYTE);
      case Opcodes.INT_TO_CHAR:
        return cast(insn, ArgType.INT, ArgType.CHAR);
      case Opcodes.INT_TO_SHORT:
        return cast(insn, ArgType.INT, ArgType.SHORT);
      case Opcodes.INT_TO_FLOAT:
        return cast(insn, ArgType.INT, ArgType.FLOAT);
      case Opcodes.INT_TO_DOUBLE:
        return cast(insn, ArgType.INT, ArgType.DOUBLE);
      case Opcodes.INT_TO_LONG:
        return cast(insn, ArgType.INT, ArgType.LONG);

      case Opcodes.FLOAT_TO_INT:
        return cast(insn, ArgType.FLOAT, ArgType.INT);
      case Opcodes.FLOAT_TO_DOUBLE:
        return cast(insn, ArgType.FLOAT, ArgType.DOUBLE);
      case Opcodes.FLOAT_TO_LONG:
        return cast(insn, ArgType.FLOAT, ArgType.LONG);

      case Opcodes.DOUBLE_TO_INT:
        return cast(insn, ArgType.DOUBLE, ArgType.INT);
      case Opcodes.DOUBLE_TO_FLOAT:
        return cast(insn, ArgType.DOUBLE, ArgType.FLOAT);
      case Opcodes.DOUBLE_TO_LONG:
        return cast(insn, ArgType.DOUBLE, ArgType.LONG);

      case Opcodes.LONG_TO_INT:
        return cast(insn, ArgType.LONG, ArgType.INT);
      case Opcodes.LONG_TO_FLOAT:
        return cast(insn, ArgType.LONG, ArgType.FLOAT);
      case Opcodes.LONG_TO_DOUBLE:
        return cast(insn, ArgType.LONG, ArgType.DOUBLE);

      case Opcodes.IF_EQ:
      case Opcodes.IF_EQZ:
        return new IfNode(insn, IfOp.EQ);

      case Opcodes.IF_NE:
      case Opcodes.IF_NEZ:
        return new IfNode(insn, IfOp.NE);

      case Opcodes.IF_GT:
      case Opcodes.IF_GTZ:
        return new IfNode(insn, IfOp.GT);

      case Opcodes.IF_GE:
      case Opcodes.IF_GEZ:
        return new IfNode(insn, IfOp.GE);

      case Opcodes.IF_LT:
      case Opcodes.IF_LTZ:
        return new IfNode(insn, IfOp.LT);

      case Opcodes.IF_LE:
      case Opcodes.IF_LEZ:
        return new IfNode(insn, IfOp.LE);

      case Opcodes.CMP_LONG:
        return cmp(insn, InsnType.CMP_L, ArgType.LONG);
      case Opcodes.CMPL_FLOAT:
        return cmp(insn, InsnType.CMP_L, ArgType.FLOAT);
      case Opcodes.CMPL_DOUBLE:
        return cmp(insn, InsnType.CMP_L, ArgType.DOUBLE);

      case Opcodes.CMPG_FLOAT:
        return cmp(insn, InsnType.CMP_G, ArgType.FLOAT);
      case Opcodes.CMPG_DOUBLE:
        return cmp(insn, InsnType.CMP_G, ArgType.DOUBLE);

      case Opcodes.GOTO:
      case Opcodes.GOTO_16:
      case Opcodes.GOTO_32:
        return new GotoNode(insn.getTarget());

      case Opcodes.THROW:
        return insn(InsnType.THROW, null,
            InsnArg.reg(insn, 0, ArgType.unknown(PrimitiveType.OBJECT)));

      case Opcodes.MOVE_EXCEPTION:
        return insn(InsnType.MOVE_EXCEPTION,
            InsnArg.reg(insn, 0, ArgType.unknown(PrimitiveType.OBJECT)));

      case Opcodes.RETURN_VOID:
        return new InsnNode(InsnType.RETURN, 0);

      case Opcodes.RETURN:
      case Opcodes.RETURN_WIDE:
      case Opcodes.RETURN_OBJECT:
        return insn(InsnType.RETURN,
            null,
            InsnArg.reg(insn, 0, method.getReturnType()));

      case Opcodes.INSTANCE_OF: {
        InsnNode node = new IndexInsnNode(InsnType.INSTANCE_OF, dex.getType(insn.getIndex()), 1);
        node.setResult(InsnArg.reg(insn, 0, ArgType.BOOLEAN));
        node.addArg(InsnArg.reg(insn, 1, ArgType.UNKNOWN_OBJECT));
        return node;
      }

      case Opcodes.CHECK_CAST: {
        ArgType castType = dex.getType(insn.getIndex());
        InsnNode node = new IndexInsnNode(InsnType.CHECK_CAST, castType, 1);
        node.setResult(InsnArg.reg(insn, 0, castType));
        node.addArg(InsnArg.reg(insn, 0, ArgType.UNKNOWN_OBJECT));
        return node;
      }

      case Opcodes.IGET:
      case Opcodes.IGET_BOOLEAN:
      case Opcodes.IGET_BYTE:
      case Opcodes.IGET_CHAR:
      case Opcodes.IGET_SHORT:
      case Opcodes.IGET_WIDE:
      case Opcodes.IGET_OBJECT: {
        FieldInfo field = FieldInfo.fromDex(dex, insn.getIndex());
        InsnNode node = new IndexInsnNode(InsnType.IGET, field, 1);
        node.setResult(InsnArg.reg(insn, 0, field.getType()));
        node.addArg(InsnArg.reg(insn, 1, field.getDeclClass().getType()));
        return node;
      }

      case Opcodes.IPUT:
      case Opcodes.IPUT_BOOLEAN:
      case Opcodes.IPUT_BYTE:
      case Opcodes.IPUT_CHAR:
      case Opcodes.IPUT_SHORT:
      case Opcodes.IPUT_WIDE:
      case Opcodes.IPUT_OBJECT: {
        FieldInfo field = FieldInfo.fromDex(dex, insn.getIndex());
        InsnNode node = new IndexInsnNode(InsnType.IPUT, field, 2);
        node.addArg(InsnArg.reg(insn, 0, field.getType()));
        node.addArg(InsnArg.reg(insn, 1, field.getDeclClass().getType()));
        return node;
      }

      case Opcodes.SGET:
      case Opcodes.SGET_BOOLEAN:
      case Opcodes.SGET_BYTE:
      case Opcodes.SGET_CHAR:
      case Opcodes.SGET_SHORT:
      case Opcodes.SGET_WIDE:
      case Opcodes.SGET_OBJECT: {
        FieldInfo field = FieldInfo.fromDex(dex, insn.getIndex());
        InsnNode node = new IndexInsnNode(InsnType.SGET, field, 0);
        node.setResult(InsnArg.reg(insn, 0, field.getType()));
        return node;
      }

      case Opcodes.SPUT:
      case Opcodes.SPUT_BOOLEAN:
      case Opcodes.SPUT_BYTE:
      case Opcodes.SPUT_CHAR:
      case Opcodes.SPUT_SHORT:
      case Opcodes.SPUT_WIDE:
      case Opcodes.SPUT_OBJECT: {
        FieldInfo field = FieldInfo.fromDex(dex, insn.getIndex());
        InsnNode node = new IndexInsnNode(InsnType.SPUT, field, 1);
        node.addArg(InsnArg.reg(insn, 0, field.getType()));
        return node;
      }

      case Opcodes.ARRAY_LENGTH: {
        InsnNode node = new InsnNode(InsnType.ARRAY_LENGTH, 1);
        node.setResult(InsnArg.reg(insn, 0, ArgType.INT));
        node.addArg(InsnArg.reg(insn, 1, ArgType.array(ArgType.UNKNOWN)));
        return node;
      }

      case Opcodes.AGET:
        return arrayGet(insn, ArgType.NARROW);
      case Opcodes.AGET_BOOLEAN:
        return arrayGet(insn, ArgType.BOOLEAN);
      case Opcodes.AGET_BYTE:
        return arrayGet(insn, ArgType.BYTE);
      case Opcodes.AGET_CHAR:
        return arrayGet(insn, ArgType.CHAR);
      case Opcodes.AGET_SHORT:
        return arrayGet(insn, ArgType.SHORT);
      case Opcodes.AGET_WIDE:
        return arrayGet(insn, ArgType.WIDE);
      case Opcodes.AGET_OBJECT:
        return arrayGet(insn, ArgType.UNKNOWN_OBJECT);

      case Opcodes.APUT:
        return arrayPut(insn, ArgType.NARROW);
      case Opcodes.APUT_BOOLEAN:
        return arrayPut(insn, ArgType.BOOLEAN);
      case Opcodes.APUT_BYTE:
        return arrayPut(insn, ArgType.BYTE);
      case Opcodes.APUT_CHAR:
        return arrayPut(insn, ArgType.CHAR);
      case Opcodes.APUT_SHORT:
        return arrayPut(insn, ArgType.SHORT);
      case Opcodes.APUT_WIDE:
        return arrayPut(insn, ArgType.WIDE);
      case Opcodes.APUT_OBJECT:
        return arrayPut(insn, ArgType.UNKNOWN_OBJECT);

      case Opcodes.INVOKE_STATIC:
        return invoke(insn, offset, InvokeType.STATIC, false);

      case Opcodes.INVOKE_STATIC_RANGE:
        return invoke(insn, offset, InvokeType.STATIC, true);

      case Opcodes.INVOKE_DIRECT:
        return invoke(insn, offset, InvokeType.DIRECT, false);
      case Opcodes.INVOKE_INTERFACE:
        return invoke(insn, offset, InvokeType.INTERFACE, false);
      case Opcodes.INVOKE_SUPER:
        return invoke(insn, offset, InvokeType.SUPER, false);
      case Opcodes.INVOKE_VIRTUAL:
        return invoke(insn, offset, InvokeType.VIRTUAL, false);

      case Opcodes.INVOKE_DIRECT_RANGE:
        return invoke(insn, offset, InvokeType.DIRECT, true);
      case Opcodes.INVOKE_INTERFACE_RANGE:
        return invoke(insn, offset, InvokeType.INTERFACE, true);
      case Opcodes.INVOKE_SUPER_RANGE:
        return invoke(insn, offset, InvokeType.SUPER, true);
      case Opcodes.INVOKE_VIRTUAL_RANGE:
        return invoke(insn, offset, InvokeType.VIRTUAL, true);

      case Opcodes.NEW_INSTANCE:
        return insn(InsnType.NEW_INSTANCE,
            InsnArg.reg(insn, 0, dex.getType(insn.getIndex())));

      case Opcodes.NEW_ARRAY:
        return insn(InsnType.NEW_ARRAY,
            InsnArg.reg(insn, 0, dex.getType(insn.getIndex())),
            InsnArg.reg(insn, 1, ArgType.INT));

      case Opcodes.FILL_ARRAY_DATA:
        return fillArray(insn);

      case Opcodes.FILLED_NEW_ARRAY:
        return filledNewArray(insn, offset, false);
      case Opcodes.FILLED_NEW_ARRAY_RANGE:
        return filledNewArray(insn, offset, true);

      case Opcodes.PACKED_SWITCH:
        return decodeSwitch(insn, offset, true);

      case Opcodes.SPARSE_SWITCH:
        return decodeSwitch(insn, offset, false);

      case Opcodes.MONITOR_ENTER:
        return insn(InsnType.MONITOR_ENTER,
            null,
            InsnArg.reg(insn, 0, ArgType.UNKNOWN_OBJECT));

      case Opcodes.MONITOR_EXIT:
        return insn(InsnType.MONITOR_EXIT,
            null,
            InsnArg.reg(insn, 0, ArgType.UNKNOWN_OBJECT));
    }

    throw new DecodeException("Unknown instruction: " + OpcodeInfo.getName(insn.getOpcode()));
  }

  private InsnNode decodeSwitch(DecodedInstruction insn, int offset, boolean packed) {
    int payloadOffset = insn.getTarget();
    DecodedInstruction payload = insnArr[payloadOffset];
    Object[] keys;
    int[] targets;
    if (packed) {
      PackedSwitchPayloadDecodedInstruction ps = (PackedSwitchPayloadDecodedInstruction) payload;
      targets = ps.getTargets();
      keys = new Object[targets.length];
      int k = ps.getFirstKey();
      for (int i = 0; i < keys.length; i++) {
        keys[i] = k++;
      }
    } else {
      SparseSwitchPayloadDecodedInstruction ss = (SparseSwitchPayloadDecodedInstruction) payload;
      targets = ss.getTargets();
      keys = new Object[targets.length];
      for (int i = 0; i < keys.length; i++) {
        keys[i] = ss.getKeys()[i];
      }
    }
    // convert from relative to absolute offsets
    for (int i = 0; i < targets.length; i++) {
      targets[i] = targets[i] - payloadOffset + offset;
    }
    int nextOffset = getNextInsnOffset(insnArr, offset);
    return new SwitchNode(InsnArg.reg(insn, 0, ArgType.NARROW), keys, targets, nextOffset);
  }

  private InsnNode fillArray(DecodedInstruction insn) {
    DecodedInstruction payload = insnArr[insn.getTarget()];
    return new FillArrayNode(insn.getA(), (FillArrayDataPayloadDecodedInstruction) payload);
  }

  private InsnNode filledNewArray(DecodedInstruction insn, int offset, boolean isRange) {
    int resReg = getMoveResultRegister(insnArr, offset);
    ArgType arrType = dex.getType(insn.getIndex());
    ArgType elType = arrType.getArrayElement();
    boolean typeImmutable = elType.isPrimitive();
    int regsCount = insn.getRegisterCount();
    InsnArg[] regs = new InsnArg[regsCount];
    if (isRange) {
      int r = insn.getA();
      for (int i = 0; i < regsCount; i++) {
        regs[i] = InsnArg.reg(r, elType, typeImmutable);
        r++;
      }
    } else {
      for (int i = 0; i < regsCount; i++) {
        int regNum = InsnUtils.getArg(insn, i);
        regs[i] = InsnArg.reg(regNum, elType, typeImmutable);
      }
    }
    return insn(InsnType.FILLED_NEW_ARRAY,
        resReg == -1 ? null : InsnArg.reg(resReg, arrType),
        regs);
  }

  private InsnNode cmp(DecodedInstruction insn, InsnType itype, ArgType argType) {
    InsnNode inode = new InsnNode(itype, 2);
    inode.setResult(InsnArg.reg(insn, 0, ArgType.INT));
    inode.addArg(InsnArg.reg(insn, 1, argType));
    inode.addArg(InsnArg.reg(insn, 2, argType));
    return inode;
  }

  private InsnNode cast(DecodedInstruction insn, ArgType from, ArgType to) {
    InsnNode inode = new IndexInsnNode(InsnType.CAST, to, 1);
    inode.setResult(InsnArg.reg(insn, 0, to));
    inode.addArg(InsnArg.reg(insn, 1, from));
    return inode;
  }

  private InsnNode invoke(DecodedInstruction insn, int offset, InvokeType type, boolean isRange) {
    int resReg = getMoveResultRegister(insnArr, offset);
    MethodInfo mth = MethodInfo.fromDex(dex, insn.getIndex());
    return new InvokeNode(mth, insn, type, isRange, resReg);
  }

  private InsnNode arrayGet(DecodedInstruction insn, ArgType argType) {
    InsnNode inode = new InsnNode(InsnType.AGET, 2);
    inode.setResult(InsnArg.reg(insn, 0, argType));
    inode.addArg(InsnArg.reg(insn, 1, ArgType.unknown(PrimitiveType.ARRAY)));
    inode.addArg(InsnArg.reg(insn, 2, ArgType.INT));
    return inode;
  }

  private InsnNode arrayPut(DecodedInstruction insn, ArgType argType) {
    InsnNode inode = new InsnNode(InsnType.APUT, 3);
    inode.addArg(InsnArg.reg(insn, 1, ArgType.unknown(PrimitiveType.ARRAY)));
    inode.addArg(InsnArg.reg(insn, 2, ArgType.INT));
    inode.addArg(InsnArg.reg(insn, 0, argType));
    return inode;
  }

  private InsnNode arith(DecodedInstruction insn, ArithOp op, ArgType type) {
    return new ArithNode(insn, op, type, false);
  }

  private InsnNode arithLit(DecodedInstruction insn, ArithOp op, ArgType type) {
    return new ArithNode(insn, op, type, true);
  }

  private InsnNode neg(DecodedInstruction insn, ArgType type) {
    InsnNode inode = new InsnNode(InsnType.NEG, 1);
    inode.setResult(InsnArg.reg(insn, 0, type));
    inode.addArg(InsnArg.reg(insn, 1, type));
    return inode;
  }

  private InsnNode insn(InsnType type, RegisterArg res) {
    InsnNode node = new InsnNode(type, 0);
    node.setResult(res);
    return node;
  }

  private InsnNode insn(InsnType type, RegisterArg res, InsnArg arg) {
    InsnNode node = new InsnNode(type, 1);
    node.setResult(res);
    node.addArg(arg);
    return node;
  }

  private InsnNode insn(InsnType type, RegisterArg res, InsnArg... args) {
    InsnNode node = new InsnNode(type, args == null ? 0 : args.length);
    node.setResult(res);
    if (args != null) {
      for (InsnArg arg : args) {
        node.addArg(arg);
      }
    }
    return node;
  }

  private int getMoveResultRegister(DecodedInstruction[] insnArr, int offset) {
    int nextOffset = getNextInsnOffset(insnArr, offset);
    if (nextOffset >= 0) {
      DecodedInstruction next = insnArr[nextOffset];
      int opc = next.getOpcode();
      if (opc == Opcodes.MOVE_RESULT
          || opc == Opcodes.MOVE_RESULT_WIDE
          || opc == Opcodes.MOVE_RESULT_OBJECT) {
        return next.getA();
      }
    }
    return -1;
  }

  public static int getPrevInsnOffset(Object[] insnArr, int offset) {
    int i = offset - 1;
    while (i >= 0 && insnArr[i] == null) {
      i--;
    }
    if (i < 0) {
      return -1;
    }
    return i;
  }

  public static int getNextInsnOffset(Object[] insnArr, int offset) {
    int i = offset + 1;
    while (i < insnArr.length && insnArr[i] == null) {
      i++;
    }
    if (i >= insnArr.length) {
      return -1;
    }
    return i;
  }
}
TOP

Related Classes of jadx.core.dex.instructions.InsnDecoder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.