Search in sources :

Example 1 with IndexInsnNode

use of jadx.core.dex.instructions.IndexInsnNode in project jadx by skylot.

the class ModVisitor method getArgsToFieldsMapping.

private static Map<InsnArg, FieldNode> getArgsToFieldsMapping(MethodNode callMthNode, ConstructorInsn co) {
    Map<InsnArg, FieldNode> map = new LinkedHashMap<InsnArg, FieldNode>();
    ClassNode parentClass = callMthNode.getParentClass();
    List<RegisterArg> argList = callMthNode.getArguments(false);
    int startArg = parentClass.getAccessFlags().isStatic() ? 0 : 1;
    int argsCount = argList.size();
    for (int i = startArg; i < argsCount; i++) {
        RegisterArg arg = argList.get(i);
        InsnNode useInsn = getParentInsnSkipMove(arg);
        if (useInsn == null) {
            return Collections.emptyMap();
        }
        FieldNode fieldNode = null;
        if (useInsn.getType() == InsnType.IPUT) {
            FieldInfo field = (FieldInfo) ((IndexInsnNode) useInsn).getIndex();
            fieldNode = parentClass.searchField(field);
            if (fieldNode == null || !fieldNode.getAccessFlags().isSynthetic()) {
                return Collections.emptyMap();
            }
        } else if (useInsn.getType() == InsnType.CONSTRUCTOR) {
            ConstructorInsn superConstr = (ConstructorInsn) useInsn;
            if (!superConstr.isSuper()) {
                return Collections.emptyMap();
            }
        } else {
            return Collections.emptyMap();
        }
        map.put(co.getArg(i), fieldNode);
    }
    return map;
}
Also used : ClassNode(jadx.core.dex.nodes.ClassNode) ConstClassNode(jadx.core.dex.instructions.ConstClassNode) IndexInsnNode(jadx.core.dex.instructions.IndexInsnNode) InsnNode(jadx.core.dex.nodes.InsnNode) RegisterArg(jadx.core.dex.instructions.args.RegisterArg) FieldNode(jadx.core.dex.nodes.FieldNode) InsnArg(jadx.core.dex.instructions.args.InsnArg) ConstructorInsn(jadx.core.dex.instructions.mods.ConstructorInsn) FieldInfo(jadx.core.dex.info.FieldInfo) LinkedHashMap(java.util.LinkedHashMap)

Example 2 with IndexInsnNode

use of jadx.core.dex.instructions.IndexInsnNode in project jadx by skylot.

the class ModVisitor method replaceStep.

private static void replaceStep(MethodNode mth, InstructionRemover remover) {
    ClassNode parentClass = mth.getParentClass();
    for (BlockNode block : mth.getBasicBlocks()) {
        remover.setBlock(block);
        int size = block.getInstructions().size();
        for (int i = 0; i < size; i++) {
            InsnNode insn = block.getInstructions().get(i);
            switch(insn.getType()) {
                case INVOKE:
                    processInvoke(mth, block, i, remover);
                    break;
                case CONST:
                case CONST_STR:
                case CONST_CLASS:
                    {
                        FieldNode f;
                        if (insn.getType() == InsnType.CONST_STR) {
                            String s = ((ConstStringNode) insn).getString();
                            f = parentClass.getConstField(s);
                        } else if (insn.getType() == InsnType.CONST_CLASS) {
                            ArgType t = ((ConstClassNode) insn).getClsType();
                            f = parentClass.getConstField(t);
                        } else {
                            f = parentClass.getConstFieldByLiteralArg((LiteralArg) insn.getArg(0));
                        }
                        if (f != null) {
                            InsnNode inode = new IndexInsnNode(InsnType.SGET, f.getFieldInfo(), 0);
                            inode.setResult(insn.getResult());
                            replaceInsn(block, i, inode);
                        }
                        break;
                    }
                case SWITCH:
                    SwitchNode sn = (SwitchNode) insn;
                    for (int k = 0; k < sn.getCasesCount(); k++) {
                        FieldNode f = parentClass.getConstField(sn.getKeys()[k]);
                        if (f != null) {
                            sn.getKeys()[k] = f;
                        }
                    }
                    break;
                case NEW_ARRAY:
                    // create array in 'fill-array' instruction
                    int next = i + 1;
                    if (next < size) {
                        InsnNode ni = block.getInstructions().get(next);
                        if (ni.getType() == InsnType.FILL_ARRAY) {
                            ni.getResult().merge(mth.dex(), insn.getResult());
                            ArgType arrType = ((NewArrayNode) insn).getArrayType();
                            ((FillArrayNode) ni).mergeElementType(mth.dex(), arrType.getArrayElement());
                            remover.add(insn);
                        }
                    }
                    break;
                case FILL_ARRAY:
                    InsnNode filledArr = makeFilledArrayInsn(mth, (FillArrayNode) insn);
                    replaceInsn(block, i, filledArr);
                    break;
                case MOVE_EXCEPTION:
                    processMoveException(mth, block, insn, remover);
                    break;
                case ARITH:
                    ArithNode arithNode = (ArithNode) insn;
                    if (arithNode.getArgsCount() == 2) {
                        InsnArg litArg = arithNode.getArg(1);
                        if (litArg.isLiteral()) {
                            FieldNode f = parentClass.getConstFieldByLiteralArg((LiteralArg) litArg);
                            if (f != null) {
                                InsnNode fGet = new IndexInsnNode(InsnType.SGET, f.getFieldInfo(), 0);
                                insn.replaceArg(litArg, InsnArg.wrapArg(fGet));
                            }
                        }
                    }
                    break;
                default:
                    break;
            }
        }
        remover.perform();
    }
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) ArgType(jadx.core.dex.instructions.args.ArgType) ClassNode(jadx.core.dex.nodes.ClassNode) ConstClassNode(jadx.core.dex.instructions.ConstClassNode) FieldNode(jadx.core.dex.nodes.FieldNode) NewArrayNode(jadx.core.dex.instructions.NewArrayNode) FilledNewArrayNode(jadx.core.dex.instructions.FilledNewArrayNode) LiteralArg(jadx.core.dex.instructions.args.LiteralArg) ArithNode(jadx.core.dex.instructions.ArithNode) SwitchNode(jadx.core.dex.instructions.SwitchNode) FillArrayNode(jadx.core.dex.instructions.FillArrayNode) IndexInsnNode(jadx.core.dex.instructions.IndexInsnNode) InsnNode(jadx.core.dex.nodes.InsnNode) InsnArg(jadx.core.dex.instructions.args.InsnArg) ConstClassNode(jadx.core.dex.instructions.ConstClassNode) IndexInsnNode(jadx.core.dex.instructions.IndexInsnNode)

Example 3 with IndexInsnNode

use of jadx.core.dex.instructions.IndexInsnNode in project jadx by skylot.

the class ConstInlineVisitor method fixTypes.

/**
	 * This is method similar to PostTypeInference.process method,
	 * but contains some expensive operations needed only after constant inline
	 */
private static void fixTypes(MethodNode mth, InsnNode insn, LiteralArg litArg) {
    DexNode dex = mth.dex();
    PostTypeInference.process(mth, insn);
    switch(insn.getType()) {
        case CONST:
            insn.getArg(0).merge(dex, insn.getResult());
            break;
        case MOVE:
            insn.getResult().merge(dex, insn.getArg(0));
            insn.getArg(0).merge(dex, insn.getResult());
            break;
        case IPUT:
        case SPUT:
            IndexInsnNode node = (IndexInsnNode) insn;
            insn.getArg(0).merge(dex, ((FieldInfo) node.getIndex()).getType());
            break;
        case IF:
            {
                InsnArg arg0 = insn.getArg(0);
                InsnArg arg1 = insn.getArg(1);
                if (arg0 == litArg) {
                    arg0.merge(dex, arg1);
                } else {
                    arg1.merge(dex, arg0);
                }
                break;
            }
        case CMP_G:
        case CMP_L:
            InsnArg arg0 = insn.getArg(0);
            InsnArg arg1 = insn.getArg(1);
            if (arg0 == litArg) {
                arg0.merge(dex, arg1);
            } else {
                arg1.merge(dex, arg0);
            }
            break;
        case RETURN:
            if (insn.getArgsCount() != 0) {
                insn.getArg(0).merge(dex, mth.getReturnType());
            }
            break;
        case INVOKE:
            InvokeNode inv = (InvokeNode) insn;
            List<ArgType> types = inv.getCallMth().getArgumentsTypes();
            int count = insn.getArgsCount();
            int k = types.size() == count ? 0 : -1;
            for (int i = 0; i < count; i++) {
                InsnArg arg = insn.getArg(i);
                if (!arg.getType().isTypeKnown()) {
                    ArgType type;
                    if (k >= 0) {
                        type = types.get(k);
                    } else {
                        type = mth.getParentClass().getClassInfo().getType();
                    }
                    arg.merge(dex, type);
                }
                k++;
            }
            break;
        case ARITH:
            litArg.merge(dex, insn.getResult());
            break;
        case APUT:
        case AGET:
            if (litArg == insn.getArg(1)) {
                litArg.merge(dex, ArgType.INT);
            }
            break;
        case NEW_ARRAY:
            if (litArg == insn.getArg(0)) {
                litArg.merge(dex, ArgType.INT);
            }
            break;
        default:
            break;
    }
}
Also used : ArgType(jadx.core.dex.instructions.args.ArgType) InsnArg(jadx.core.dex.instructions.args.InsnArg) DexNode(jadx.core.dex.nodes.DexNode) InvokeNode(jadx.core.dex.instructions.InvokeNode) IndexInsnNode(jadx.core.dex.instructions.IndexInsnNode)

Example 4 with IndexInsnNode

use of jadx.core.dex.instructions.IndexInsnNode in project jadx by skylot.

the class PostTypeInference method process.

public static boolean process(MethodNode mth, InsnNode insn) {
    DexNode dex = mth.dex();
    switch(insn.getType()) {
        case CONST:
            RegisterArg res = insn.getResult();
            LiteralArg litArg = (LiteralArg) insn.getArg(0);
            if (res.getType().isObject()) {
                long lit = litArg.getLiteral();
                if (lit != 0) {
                    // incorrect literal value for object
                    ArgType type = lit == 1 ? ArgType.BOOLEAN : ArgType.INT;
                    // can't merge with object -> force it
                    litArg.setType(type);
                    res.getSVar().setType(type);
                    return true;
                }
            }
            return litArg.merge(dex, res);
        case MOVE:
            {
                boolean change = false;
                if (insn.getResult().merge(dex, insn.getArg(0))) {
                    change = true;
                }
                if (insn.getArg(0).merge(dex, insn.getResult())) {
                    change = true;
                }
                return change;
            }
        case AGET:
            return fixArrayTypes(dex, insn.getArg(0), insn.getResult());
        case APUT:
            return fixArrayTypes(dex, insn.getArg(0), insn.getArg(2));
        case IF:
            {
                boolean change = false;
                if (insn.getArg(1).merge(dex, insn.getArg(0))) {
                    change = true;
                }
                if (insn.getArg(0).merge(dex, insn.getArg(1))) {
                    change = true;
                }
                return change;
            }
        // check argument types for overloaded methods
        case INVOKE:
            {
                boolean change = false;
                InvokeNode inv = (InvokeNode) insn;
                MethodInfo callMth = inv.getCallMth();
                MethodNode node = mth.dex().resolveMethod(callMth);
                if (node != null && node.isArgsOverload()) {
                    List<ArgType> args = callMth.getArgumentsTypes();
                    int j = inv.getArgsCount() - 1;
                    for (int i = args.size() - 1; i >= 0; i--) {
                        ArgType argType = args.get(i);
                        InsnArg insnArg = inv.getArg(j--);
                        if (insnArg.isRegister() && !argType.equals(insnArg.getType())) {
                            insnArg.setType(argType);
                            change = true;
                        }
                    }
                }
                return change;
            }
        case CHECK_CAST:
            {
                ArgType castType = (ArgType) ((IndexInsnNode) insn).getIndex();
                RegisterArg result = insn.getResult();
                ArgType resultType = result.getType();
                // don't override generic types of same base class
                boolean skip = castType.isObject() && resultType.isObject() && castType.getObject().equals(resultType.getObject());
                if (!skip) {
                    // workaround for compiler bug (see TestDuplicateCast)
                    result.getSVar().setType(castType);
                }
                return true;
            }
        case PHI:
        case MERGE:
            {
                ArgType type = insn.getResult().getType();
                if (!type.isTypeKnown()) {
                    for (InsnArg arg : insn.getArguments()) {
                        if (arg.getType().isTypeKnown()) {
                            type = arg.getType();
                            break;
                        }
                    }
                }
                boolean changed = false;
                if (updateType(insn.getResult(), type)) {
                    changed = true;
                }
                for (int i = 0; i < insn.getArgsCount(); i++) {
                    RegisterArg arg = (RegisterArg) insn.getArg(i);
                    if (updateType(arg, type)) {
                        changed = true;
                    }
                }
                return changed;
            }
        default:
            break;
    }
    return false;
}
Also used : ArgType(jadx.core.dex.instructions.args.ArgType) RegisterArg(jadx.core.dex.instructions.args.RegisterArg) MethodNode(jadx.core.dex.nodes.MethodNode) InsnArg(jadx.core.dex.instructions.args.InsnArg) DexNode(jadx.core.dex.nodes.DexNode) InvokeNode(jadx.core.dex.instructions.InvokeNode) LiteralArg(jadx.core.dex.instructions.args.LiteralArg) MethodInfo(jadx.core.dex.info.MethodInfo) List(java.util.List) IndexInsnNode(jadx.core.dex.instructions.IndexInsnNode)

Example 5 with IndexInsnNode

use of jadx.core.dex.instructions.IndexInsnNode in project jadx by skylot.

the class InsnGen method makeInsnBody.

private void makeInsnBody(CodeWriter code, InsnNode insn, Set<Flags> state) throws CodegenException {
    switch(insn.getType()) {
        case CONST_STR:
            String str = ((ConstStringNode) insn).getString();
            code.add(mth.dex().root().getStringUtils().unescapeString(str));
            break;
        case CONST_CLASS:
            ArgType clsType = ((ConstClassNode) insn).getClsType();
            useType(code, clsType);
            code.add(".class");
            break;
        case CONST:
            LiteralArg arg = (LiteralArg) insn.getArg(0);
            code.add(lit(arg));
            break;
        case MOVE:
            addArg(code, insn.getArg(0), false);
            break;
        case CHECK_CAST:
        case CAST:
            {
                boolean wrap = state.contains(Flags.BODY_ONLY);
                if (wrap) {
                    code.add('(');
                }
                code.add('(');
                useType(code, (ArgType) ((IndexInsnNode) insn).getIndex());
                code.add(") ");
                addArg(code, insn.getArg(0), true);
                if (wrap) {
                    code.add(')');
                }
                break;
            }
        case ARITH:
            makeArith((ArithNode) insn, code, state);
            break;
        case NEG:
            {
                boolean wrap = state.contains(Flags.BODY_ONLY);
                if (wrap) {
                    code.add('(');
                }
                code.add('-');
                addArg(code, insn.getArg(0));
                if (wrap) {
                    code.add(')');
                }
                break;
            }
        case RETURN:
            if (insn.getArgsCount() != 0) {
                code.add("return ");
                addArg(code, insn.getArg(0), false);
            } else {
                code.add("return");
            }
            break;
        case BREAK:
            code.add("break");
            LoopLabelAttr labelAttr = insn.get(AType.LOOP_LABEL);
            if (labelAttr != null) {
                code.add(' ').add(mgen.getNameGen().getLoopLabel(labelAttr));
            }
            break;
        case CONTINUE:
            code.add("continue");
            break;
        case THROW:
            code.add("throw ");
            addArg(code, insn.getArg(0), true);
            break;
        case CMP_L:
        case CMP_G:
            code.add('(');
            addArg(code, insn.getArg(0));
            code.add(" > ");
            addArg(code, insn.getArg(1));
            code.add(" ? 1 : (");
            addArg(code, insn.getArg(0));
            code.add(" == ");
            addArg(code, insn.getArg(1));
            code.add(" ? 0 : -1))");
            break;
        case INSTANCE_OF:
            {
                boolean wrap = state.contains(Flags.BODY_ONLY);
                if (wrap) {
                    code.add('(');
                }
                addArg(code, insn.getArg(0));
                code.add(" instanceof ");
                useType(code, (ArgType) ((IndexInsnNode) insn).getIndex());
                if (wrap) {
                    code.add(')');
                }
                break;
            }
        case CONSTRUCTOR:
            makeConstructor((ConstructorInsn) insn, code);
            break;
        case INVOKE:
            makeInvoke((InvokeNode) insn, code);
            break;
        case NEW_ARRAY:
            {
                ArgType arrayType = ((NewArrayNode) insn).getArrayType();
                code.add("new ");
                useType(code, arrayType.getArrayRootElement());
                code.add('[');
                addArg(code, insn.getArg(0));
                code.add(']');
                int dim = arrayType.getArrayDimension();
                for (int i = 0; i < dim - 1; i++) {
                    code.add("[]");
                }
                break;
            }
        case ARRAY_LENGTH:
            addArg(code, insn.getArg(0));
            code.add(".length");
            break;
        case FILLED_NEW_ARRAY:
            filledNewArray((FilledNewArrayNode) insn, code);
            break;
        case AGET:
            addArg(code, insn.getArg(0));
            code.add('[');
            addArg(code, insn.getArg(1), false);
            code.add(']');
            break;
        case APUT:
            addArg(code, insn.getArg(0));
            code.add('[');
            addArg(code, insn.getArg(1), false);
            code.add("] = ");
            addArg(code, insn.getArg(2), false);
            break;
        case IGET:
            {
                FieldInfo fieldInfo = (FieldInfo) ((IndexInsnNode) insn).getIndex();
                instanceField(code, fieldInfo, insn.getArg(0));
                break;
            }
        case IPUT:
            {
                FieldInfo fieldInfo = (FieldInfo) ((IndexInsnNode) insn).getIndex();
                instanceField(code, fieldInfo, insn.getArg(1));
                code.add(" = ");
                addArg(code, insn.getArg(0), false);
                break;
            }
        case SGET:
            staticField(code, (FieldInfo) ((IndexInsnNode) insn).getIndex());
            break;
        case SPUT:
            FieldInfo field = (FieldInfo) ((IndexInsnNode) insn).getIndex();
            staticField(code, field);
            code.add(" = ");
            addArg(code, insn.getArg(0), false);
            break;
        case STR_CONCAT:
            boolean wrap = state.contains(Flags.BODY_ONLY);
            if (wrap) {
                code.add('(');
            }
            for (Iterator<InsnArg> it = insn.getArguments().iterator(); it.hasNext(); ) {
                addArg(code, it.next());
                if (it.hasNext()) {
                    code.add(" + ");
                }
            }
            if (wrap) {
                code.add(')');
            }
            break;
        case MONITOR_ENTER:
            if (isFallback()) {
                code.add("monitor-enter(");
                addArg(code, insn.getArg(0));
                code.add(')');
            }
            break;
        case MONITOR_EXIT:
            if (isFallback()) {
                code.add("monitor-exit(");
                addArg(code, insn.getArg(0));
                code.add(')');
            }
            break;
        case TERNARY:
            makeTernary((TernaryInsn) insn, code, state);
            break;
        case ONE_ARG:
            addArg(code, insn.getArg(0));
            break;
        /* fallback mode instructions */
        case IF:
            fallbackOnlyInsn(insn);
            IfNode ifInsn = (IfNode) insn;
            code.add("if (");
            addArg(code, insn.getArg(0));
            code.add(' ');
            code.add(ifInsn.getOp().getSymbol()).add(' ');
            addArg(code, insn.getArg(1));
            code.add(") goto ").add(MethodGen.getLabelName(ifInsn.getTarget()));
            break;
        case GOTO:
            fallbackOnlyInsn(insn);
            code.add("goto ").add(MethodGen.getLabelName(((GotoNode) insn).getTarget()));
            break;
        case MOVE_EXCEPTION:
            fallbackOnlyInsn(insn);
            code.add("move-exception");
            break;
        case SWITCH:
            fallbackOnlyInsn(insn);
            SwitchNode sw = (SwitchNode) insn;
            code.add("switch(");
            addArg(code, insn.getArg(0));
            code.add(") {");
            code.incIndent();
            for (int i = 0; i < sw.getCasesCount(); i++) {
                String key = sw.getKeys()[i].toString();
                code.startLine("case ").add(key).add(": goto ");
                code.add(MethodGen.getLabelName(sw.getTargets()[i])).add(';');
            }
            code.startLine("default: goto ");
            code.add(MethodGen.getLabelName(sw.getDefaultCaseOffset())).add(';');
            code.decIndent();
            code.startLine('}');
            break;
        case FILL_ARRAY:
            fallbackOnlyInsn(insn);
            FillArrayNode arrayNode = (FillArrayNode) insn;
            Object data = arrayNode.getData();
            String arrStr;
            if (data instanceof int[]) {
                arrStr = Arrays.toString((int[]) data);
            } else if (data instanceof short[]) {
                arrStr = Arrays.toString((short[]) data);
            } else if (data instanceof byte[]) {
                arrStr = Arrays.toString((byte[]) data);
            } else if (data instanceof long[]) {
                arrStr = Arrays.toString((long[]) data);
            } else {
                arrStr = "?";
            }
            code.add('{').add(arrStr.substring(1, arrStr.length() - 1)).add('}');
            break;
        case NEW_INSTANCE:
            // only fallback - make new instance in constructor invoke
            fallbackOnlyInsn(insn);
            code.add("new ").add(insn.getResult().getType().toString());
            break;
        case PHI:
        case MERGE:
            fallbackOnlyInsn(insn);
            code.add(insn.getType().toString()).add("(");
            for (InsnArg insnArg : insn.getArguments()) {
                addArg(code, insnArg);
                code.add(' ');
            }
            code.add(")");
            break;
        default:
            throw new CodegenException(mth, "Unknown instruction: " + insn.getType());
    }
}
Also used : ArgType(jadx.core.dex.instructions.args.ArgType) CodegenException(jadx.core.utils.exceptions.CodegenException) LoopLabelAttr(jadx.core.dex.attributes.nodes.LoopLabelAttr) ConstStringNode(jadx.core.dex.instructions.ConstStringNode) LiteralArg(jadx.core.dex.instructions.args.LiteralArg) IfNode(jadx.core.dex.instructions.IfNode) SwitchNode(jadx.core.dex.instructions.SwitchNode) FillArrayNode(jadx.core.dex.instructions.FillArrayNode) InsnArg(jadx.core.dex.instructions.args.InsnArg) ConstClassNode(jadx.core.dex.instructions.ConstClassNode) IndexInsnNode(jadx.core.dex.instructions.IndexInsnNode) FieldInfo(jadx.core.dex.info.FieldInfo) GotoNode(jadx.core.dex.instructions.GotoNode)

Aggregations

IndexInsnNode (jadx.core.dex.instructions.IndexInsnNode)14 InsnNode (jadx.core.dex.nodes.InsnNode)11 InsnArg (jadx.core.dex.instructions.args.InsnArg)10 FieldInfo (jadx.core.dex.info.FieldInfo)8 ArgType (jadx.core.dex.instructions.args.ArgType)8 FieldNode (jadx.core.dex.nodes.FieldNode)8 LiteralArg (jadx.core.dex.instructions.args.LiteralArg)5 InvokeNode (jadx.core.dex.instructions.InvokeNode)4 InsnWrapArg (jadx.core.dex.instructions.args.InsnWrapArg)4 RegisterArg (jadx.core.dex.instructions.args.RegisterArg)4 BlockNode (jadx.core.dex.nodes.BlockNode)4 ClassNode (jadx.core.dex.nodes.ClassNode)4 ConstClassNode (jadx.core.dex.instructions.ConstClassNode)3 MethodNode (jadx.core.dex.nodes.MethodNode)3 ArrayList (java.util.ArrayList)3 MethodInfo (jadx.core.dex.info.MethodInfo)2 ArithNode (jadx.core.dex.instructions.ArithNode)2 FillArrayNode (jadx.core.dex.instructions.FillArrayNode)2 FilledNewArrayNode (jadx.core.dex.instructions.FilledNewArrayNode)2 SwitchNode (jadx.core.dex.instructions.SwitchNode)2