Search in sources :

Example 1 with SwitchInsn

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

the class RegionGen method makeSwitch.

public void makeSwitch(SwitchRegion sw, ICodeWriter code) throws CodegenException {
    SwitchInsn insn = (SwitchInsn) BlockUtils.getLastInsn(sw.getHeader());
    Objects.requireNonNull(insn, "Switch insn not found in header");
    InsnArg arg = insn.getArg(0);
    code.startLine("switch (");
    addArg(code, arg, false);
    code.add(") {");
    InsnCodeOffset.attach(code, insn);
    CodeGenUtils.addCodeComments(code, mth, insn);
    code.incIndent();
    for (CaseInfo caseInfo : sw.getCases()) {
        List<Object> keys = caseInfo.getKeys();
        IContainer c = caseInfo.getContainer();
        for (Object k : keys) {
            if (k == SwitchRegion.DEFAULT_CASE_KEY) {
                code.startLine("default:");
            } else {
                code.startLine("case ");
                addCaseKey(code, arg, k);
                code.add(':');
            }
        }
        makeRegionIndent(code, c);
    }
    code.decIndent();
    code.startLine('}');
}
Also used : CaseInfo(jadx.core.dex.regions.SwitchRegion.CaseInfo) InsnArg(jadx.core.dex.instructions.args.InsnArg) IContainer(jadx.core.dex.nodes.IContainer) SwitchInsn(jadx.core.dex.instructions.SwitchInsn)

Example 2 with SwitchInsn

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

the class InsnGen method makeInsnBody.

private void makeInsnBody(ICodeWriter code, InsnNode insn, Set<Flags> state) throws CodegenException {
    switch(insn.getType()) {
        case CONST_STR:
            String str = ((ConstStringNode) insn).getString();
            code.add(mth.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:
            oneArgInsn(code, insn, state, '-');
            break;
        case NOT:
            char op = insn.getArg(0).getType() == ArgType.BOOLEAN ? '!' : '~';
            oneArgInsn(code, insn, state, op);
            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());
                int k = 0;
                int argsCount = insn.getArgsCount();
                for (; k < argsCount; k++) {
                    code.add('[');
                    addArg(code, insn.getArg(k), false);
                    code.add(']');
                }
                int dim = arrayType.getArrayDimension();
                for (; k < dim - 1; k++) {
                    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 FILL_ARRAY:
            FillArrayInsn arrayNode = (FillArrayInsn) insn;
            if (fallback) {
                String arrStr = arrayNode.dataToString();
                addArg(code, insn.getArg(0));
                code.add(" = {").add(arrStr.substring(1, arrStr.length() - 1)).add("} // fill-array");
            } else {
                fillArray(code, arrayNode);
            }
            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(");
                if (insn.getArgsCount() == 1) {
                    addArg(code, insn.getArg(0));
                }
                code.add(')');
            }
            break;
        case TERNARY:
            makeTernary((TernaryInsn) insn, code, state);
            break;
        case ONE_ARG:
            addArg(code, insn.getArg(0), state);
            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);
            SwitchInsn sw = (SwitchInsn) insn;
            code.add("switch(");
            addArg(code, insn.getArg(0));
            code.add(") {");
            code.incIndent();
            int[] keys = sw.getKeys();
            int[] targets = sw.getTargets();
            for (int i = 0; i < keys.length; i++) {
                code.startLine("case ").add(Integer.toString(keys[i])).add(": goto ");
                code.add(MethodGen.getLabelName(targets[i])).add(';');
            }
            code.startLine("default: goto ");
            code.add(MethodGen.getLabelName(sw.getDefaultCaseOffset())).add(';');
            code.decIndent();
            code.startLine('}');
            break;
        case NEW_INSTANCE:
            // only fallback - make new instance in constructor invoke
            fallbackOnlyInsn(insn);
            code.add("new ").add(insn.getResult().getInitType().toString());
            break;
        case PHI:
            fallbackOnlyInsn(insn);
            code.add(insn.getType().toString()).add('(');
            for (InsnArg insnArg : insn.getArguments()) {
                addArg(code, insnArg);
                code.add(' ');
            }
            code.add(')');
            break;
        case MOVE_RESULT:
            fallbackOnlyInsn(insn);
            code.add("move-result");
            break;
        case FILL_ARRAY_DATA:
            fallbackOnlyInsn(insn);
            code.add("fill-array " + insn);
            break;
        case SWITCH_DATA:
            fallbackOnlyInsn(insn);
            code.add(insn.toString());
            break;
        case MOVE_MULTI:
            fallbackOnlyInsn(insn);
            int len = insn.getArgsCount();
            for (int i = 0; i < len - 1; i += 2) {
                addArg(code, insn.getArg(i));
                code.add(" = ");
                addArg(code, insn.getArg(i + 1));
                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) SwitchInsn(jadx.core.dex.instructions.SwitchInsn) FillArrayInsn(jadx.core.dex.instructions.FillArrayInsn) 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)

Example 3 with SwitchInsn

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

the class ProcessInstructionsVisitor method initJumps.

private static void initJumps(MethodNode mth, InsnNode[] insnByOffset) {
    for (int offset = 0; offset < insnByOffset.length; offset++) {
        InsnNode insn = insnByOffset[offset];
        if (insn == null) {
            continue;
        }
        switch(insn.getType()) {
            case SWITCH:
                SwitchInsn sw = (SwitchInsn) insn;
                if (sw.needData()) {
                    attachSwitchData(insnByOffset, offset, sw);
                }
                int defCaseOffset = sw.getDefaultCaseOffset();
                if (defCaseOffset != -1) {
                    addJump(mth, insnByOffset, offset, defCaseOffset);
                }
                for (int target : sw.getTargets()) {
                    addJump(mth, insnByOffset, offset, target);
                }
                break;
            case IF:
                int next = getNextInsnOffset(insnByOffset, offset);
                if (next != -1) {
                    addJump(mth, insnByOffset, offset, next);
                }
                addJump(mth, insnByOffset, offset, ((IfNode) insn).getTarget());
                break;
            case GOTO:
                addJump(mth, insnByOffset, offset, ((GotoNode) insn).getTarget());
                break;
            case INVOKE:
                if (insn.getResult() == null) {
                    ArgType retType = ((BaseInvokeNode) insn).getCallMth().getReturnType();
                    mergeMoveResult(insnByOffset, offset, insn, retType);
                }
                break;
            case STR_CONCAT:
                // invoke-custom with string concatenation translated directly to STR_CONCAT, merge next move-result
                if (insn.getResult() == null) {
                    mergeMoveResult(insnByOffset, offset, insn, ArgType.STRING);
                }
                break;
            case FILLED_NEW_ARRAY:
                ArgType arrType = ((FilledNewArrayNode) insn).getArrayType();
                mergeMoveResult(insnByOffset, offset, insn, arrType);
                break;
            case FILL_ARRAY:
                FillArrayInsn fillArrayInsn = (FillArrayInsn) insn;
                int target = fillArrayInsn.getTarget();
                InsnNode arrDataInsn = getInsnAtOffset(insnByOffset, target);
                if (arrDataInsn != null && arrDataInsn.getType() == InsnType.FILL_ARRAY_DATA) {
                    fillArrayInsn.setArrayData((FillArrayData) arrDataInsn);
                    removeInsn(insnByOffset, arrDataInsn);
                } else {
                    throw new JadxRuntimeException("Payload for fill-array not found at " + InsnUtils.formatOffset(target));
                }
                break;
            default:
                break;
        }
    }
}
Also used : ArgType(jadx.core.dex.instructions.args.ArgType) FillArrayInsn(jadx.core.dex.instructions.FillArrayInsn) InsnNode(jadx.core.dex.nodes.InsnNode) FilledNewArrayNode(jadx.core.dex.instructions.FilledNewArrayNode) JadxRuntimeException(jadx.core.utils.exceptions.JadxRuntimeException) SwitchInsn(jadx.core.dex.instructions.SwitchInsn)

Example 4 with SwitchInsn

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

the class RegionMaker method traverse.

/**
 * Recursively traverse all blocks from 'block' until block from 'exits'
 */
private BlockNode traverse(IRegion r, BlockNode block, RegionStack stack) {
    if (block.contains(AFlag.MTH_EXIT_BLOCK)) {
        return null;
    }
    BlockNode next = null;
    boolean processed = false;
    List<LoopInfo> loops = block.getAll(AType.LOOP);
    int loopCount = loops.size();
    if (loopCount != 0 && block.contains(AFlag.LOOP_START)) {
        if (loopCount == 1) {
            next = processLoop(r, loops.get(0), stack);
            processed = true;
        } else {
            for (LoopInfo loop : loops) {
                if (loop.getStart() == block) {
                    next = processLoop(r, loop, stack);
                    processed = true;
                    break;
                }
            }
        }
    }
    InsnNode insn = BlockUtils.getLastInsn(block);
    if (!processed && insn != null) {
        switch(insn.getType()) {
            case IF:
                next = processIf(r, block, (IfNode) insn, stack);
                processed = true;
                break;
            case SWITCH:
                next = processSwitch(r, block, (SwitchInsn) insn, stack);
                processed = true;
                break;
            case MONITOR_ENTER:
                next = processMonitorEnter(r, block, insn, stack);
                processed = true;
                break;
            default:
                break;
        }
    }
    if (!processed) {
        r.getSubBlocks().add(block);
        next = getNextBlock(block);
    }
    if (next != null && !stack.containsExit(block) && !stack.containsExit(next)) {
        return next;
    }
    return null;
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) InsnNode(jadx.core.dex.nodes.InsnNode) LoopInfo(jadx.core.dex.attributes.nodes.LoopInfo) IfNode(jadx.core.dex.instructions.IfNode) SwitchInsn(jadx.core.dex.instructions.SwitchInsn)

Aggregations

SwitchInsn (jadx.core.dex.instructions.SwitchInsn)4 FillArrayInsn (jadx.core.dex.instructions.FillArrayInsn)2 IfNode (jadx.core.dex.instructions.IfNode)2 ArgType (jadx.core.dex.instructions.args.ArgType)2 InsnArg (jadx.core.dex.instructions.args.InsnArg)2 InsnNode (jadx.core.dex.nodes.InsnNode)2 LoopInfo (jadx.core.dex.attributes.nodes.LoopInfo)1 LoopLabelAttr (jadx.core.dex.attributes.nodes.LoopLabelAttr)1 FieldInfo (jadx.core.dex.info.FieldInfo)1 ConstClassNode (jadx.core.dex.instructions.ConstClassNode)1 ConstStringNode (jadx.core.dex.instructions.ConstStringNode)1 FilledNewArrayNode (jadx.core.dex.instructions.FilledNewArrayNode)1 GotoNode (jadx.core.dex.instructions.GotoNode)1 IndexInsnNode (jadx.core.dex.instructions.IndexInsnNode)1 LiteralArg (jadx.core.dex.instructions.args.LiteralArg)1 BlockNode (jadx.core.dex.nodes.BlockNode)1 IContainer (jadx.core.dex.nodes.IContainer)1 CaseInfo (jadx.core.dex.regions.SwitchRegion.CaseInfo)1 CodegenException (jadx.core.utils.exceptions.CodegenException)1 JadxRuntimeException (jadx.core.utils.exceptions.JadxRuntimeException)1