Search in sources :

Example 1 with InvokeNode

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

the class SimplifyVisitor method convertInvoke.

private static InsnNode convertInvoke(MethodNode mth, InsnNode insn) {
    MethodInfo callMth = ((InvokeNode) insn).getCallMth();
    // convert it to STRING_CONCAT pseudo instruction.
    if (callMth.getDeclClass().getFullName().equals(Consts.CLASS_STRING_BUILDER) && callMth.getShortId().equals(Consts.MTH_TOSTRING_SIGNATURE) && insn.getArg(0).isInsnWrap()) {
        try {
            List<InsnNode> chain = flattenInsnChain(insn);
            //RAF
            int constrIndex = -1;
            // string is created using .append() calls:
            if (chain.size() > 1 && chain.get(0).getType() == InsnType.CONSTRUCTOR) {
                constrIndex = 0;
            } else if (chain.size() > 2 && chain.get(1).getType() == InsnType.CONSTRUCTOR) {
                //RAF Case where the first string element is String arg to the
                // new StringBuilder("xxx") constructor
                constrIndex = 1;
            } else if (chain.size() > 3 && chain.get(2).getType() == InsnType.CONSTRUCTOR) {
                //RAF Case where the first string element is String.valueOf() arg
                // to the new StringBuilder(String.valueOf(zzz)) constructor
                constrIndex = 2;
            }
            if (constrIndex != -1) {
                // If we found a CONSTRUCTOR, is it a StringBuilder?
                ConstructorInsn constr = (ConstructorInsn) chain.get(constrIndex);
                if (constr.getClassType().getFullName().equals(Consts.CLASS_STRING_BUILDER)) {
                    int len = chain.size(), argInd = 1;
                    InsnNode concatInsn = new InsnNode(InsnType.STR_CONCAT, len - 1);
                    InsnNode argInsn;
                    if (constrIndex > 0) {
                        // There was an arg to the StringBuilder constr
                        InsnWrapArg iwa;
                        if (constrIndex == 2 && (argInsn = chain.get(1)).getType() == InsnType.INVOKE && ((InvokeNode) argInsn).getCallMth().getName().compareTo("valueOf") == 0) {
                            // The argument of new StringBuilder() is a String.valueOf(chainElement0)
                            iwa = (InsnWrapArg) argInsn.getArg(0);
                            // Cause for loop below to skip to after the constructor
                            argInd = 3;
                        } else {
                            InsnNode firstNode = chain.get(0);
                            if (firstNode instanceof ConstStringNode) {
                                ConstStringNode csn = (ConstStringNode) firstNode;
                                iwa = new InsnWrapArg(csn);
                                // Cause for loop below to skip to after the constructor
                                argInd = 2;
                            } else {
                                return null;
                            }
                        }
                        concatInsn.addArg(iwa);
                    }
                    for (; argInd < len; argInd++) {
                        // Add the .append(xxx) arg string to concat
                        concatInsn.addArg(chain.get(argInd).getArg(1));
                    }
                    concatInsn.setResult(insn.getResult());
                    return concatInsn;
                }
            // end of if constructor is for StringBuilder
            }
        // end of if we found a constructor early in the chain
        } catch (Throwable e) {
            LOG.debug("Can't convert string concatenation: {} insn: {}", mth, insn, e);
        }
    }
    return null;
}
Also used : IndexInsnNode(jadx.core.dex.instructions.IndexInsnNode) InsnNode(jadx.core.dex.nodes.InsnNode) InvokeNode(jadx.core.dex.instructions.InvokeNode) ConstStringNode(jadx.core.dex.instructions.ConstStringNode) MethodInfo(jadx.core.dex.info.MethodInfo) InsnWrapArg(jadx.core.dex.instructions.args.InsnWrapArg) ConstructorInsn(jadx.core.dex.instructions.mods.ConstructorInsn)

Example 2 with InvokeNode

use of jadx.core.dex.instructions.InvokeNode 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 3 with InvokeNode

use of jadx.core.dex.instructions.InvokeNode 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 4 with InvokeNode

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

the class NameGen method makeNameFromInsn.

private String makeNameFromInsn(InsnNode insn) {
    switch(insn.getType()) {
        case INVOKE:
            InvokeNode inv = (InvokeNode) insn;
            return makeNameFromInvoke(inv.getCallMth());
        case CONSTRUCTOR:
            ConstructorInsn co = (ConstructorInsn) insn;
            return makeNameForObject(co.getClassType().getType());
        case ARRAY_LENGTH:
            return "length";
        case ARITH:
        case TERNARY:
        case CAST:
            for (InsnArg arg : insn.getArguments()) {
                if (arg.isInsnWrap()) {
                    InsnNode wrapInsn = ((InsnWrapArg) arg).getWrapInsn();
                    String wName = makeNameFromInsn(wrapInsn);
                    if (wName != null) {
                        return wName;
                    }
                }
            }
            break;
        default:
            break;
    }
    return null;
}
Also used : InsnNode(jadx.core.dex.nodes.InsnNode) InsnArg(jadx.core.dex.instructions.args.InsnArg) InvokeNode(jadx.core.dex.instructions.InvokeNode) InsnWrapArg(jadx.core.dex.instructions.args.InsnWrapArg) ConstructorInsn(jadx.core.dex.instructions.mods.ConstructorInsn)

Example 5 with InvokeNode

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

the class ModVisitor method processInvoke.

private static void processInvoke(MethodNode mth, BlockNode block, int insnNumber, InstructionRemover remover) {
    ClassNode parentClass = mth.getParentClass();
    InsnNode insn = block.getInstructions().get(insnNumber);
    InvokeNode inv = (InvokeNode) insn;
    MethodInfo callMth = inv.getCallMth();
    if (!callMth.isConstructor()) {
        return;
    }
    InsnNode instArgAssignInsn = ((RegisterArg) inv.getArg(0)).getAssignInsn();
    ConstructorInsn co = new ConstructorInsn(mth, inv);
    boolean remove = false;
    if (co.isSuper() && (co.getArgsCount() == 0 || parentClass.isEnum())) {
        remove = true;
    } else if (co.isThis() && co.getArgsCount() == 0) {
        MethodNode defCo = parentClass.searchMethodByName(callMth.getShortId());
        if (defCo == null || defCo.isNoCode()) {
            // default constructor not implemented
            remove = true;
        }
    }
    // remove super() call in instance initializer
    if (parentClass.isAnonymous() && mth.isDefaultConstructor() && co.isSuper()) {
        remove = true;
    }
    if (remove) {
        remover.add(insn);
        return;
    }
    if (co.isNewInstance()) {
        InsnNode newInstInsn = removeAssignChain(instArgAssignInsn, remover, InsnType.NEW_INSTANCE);
        if (newInstInsn != null) {
            RegisterArg instArg = newInstInsn.getResult();
            RegisterArg resultArg = co.getResult();
            if (!resultArg.equals(instArg)) {
                // replace all usages of 'instArg' with result of this constructor instruction
                for (RegisterArg useArg : new ArrayList<RegisterArg>(instArg.getSVar().getUseList())) {
                    RegisterArg dup = resultArg.duplicate();
                    InsnNode parentInsn = useArg.getParentInsn();
                    parentInsn.replaceArg(useArg, dup);
                    dup.setParentInsn(parentInsn);
                    resultArg.getSVar().use(dup);
                }
            }
        }
    }
    ConstructorInsn replace = processConstructor(mth, co);
    if (replace != null) {
        co = replace;
    }
    replaceInsn(block, insnNumber, co);
    processAnonymousConstructor(mth, co);
}
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) MethodNode(jadx.core.dex.nodes.MethodNode) InvokeNode(jadx.core.dex.instructions.InvokeNode) ArrayList(java.util.ArrayList) MethodInfo(jadx.core.dex.info.MethodInfo) ConstructorInsn(jadx.core.dex.instructions.mods.ConstructorInsn)

Aggregations

InvokeNode (jadx.core.dex.instructions.InvokeNode)8 IndexInsnNode (jadx.core.dex.instructions.IndexInsnNode)6 InsnArg (jadx.core.dex.instructions.args.InsnArg)5 InsnNode (jadx.core.dex.nodes.InsnNode)5 MethodInfo (jadx.core.dex.info.MethodInfo)4 InsnWrapArg (jadx.core.dex.instructions.args.InsnWrapArg)4 ArgType (jadx.core.dex.instructions.args.ArgType)3 ConstructorInsn (jadx.core.dex.instructions.mods.ConstructorInsn)3 RegisterArg (jadx.core.dex.instructions.args.RegisterArg)2 ClassNode (jadx.core.dex.nodes.ClassNode)2 DexNode (jadx.core.dex.nodes.DexNode)2 MethodNode (jadx.core.dex.nodes.MethodNode)2 FieldInfo (jadx.core.dex.info.FieldInfo)1 ConstClassNode (jadx.core.dex.instructions.ConstClassNode)1 ConstStringNode (jadx.core.dex.instructions.ConstStringNode)1 LiteralArg (jadx.core.dex.instructions.args.LiteralArg)1 FieldNode (jadx.core.dex.nodes.FieldNode)1 ArrayList (java.util.ArrayList)1 List (java.util.List)1