Search in sources :

Example 41 with JadxRuntimeException

use of jadx.core.utils.exceptions.JadxRuntimeException in project jadx by skylot.

the class ArithNode method build.

public static ArithNode build(InsnData insn, ArithOp op, ArgType type) {
    RegisterArg resArg = InsnArg.reg(insn, 0, fixResultType(op, type));
    ArgType argType = fixArgType(op, type);
    switch(insn.getRegsCount()) {
        case 2:
            return new ArithNode(op, resArg, InsnArg.reg(insn, 0, argType), InsnArg.reg(insn, 1, argType));
        case 3:
            return new ArithNode(op, resArg, InsnArg.reg(insn, 1, argType), InsnArg.reg(insn, 2, argType));
        default:
            throw new JadxRuntimeException("Unexpected registers count in " + insn);
    }
}
Also used : ArgType(jadx.core.dex.instructions.args.ArgType) RegisterArg(jadx.core.dex.instructions.args.RegisterArg) JadxRuntimeException(jadx.core.utils.exceptions.JadxRuntimeException)

Example 42 with JadxRuntimeException

use of jadx.core.utils.exceptions.JadxRuntimeException in project jadx by skylot.

the class ArithNode method buildLit.

public static ArithNode buildLit(InsnData insn, ArithOp op, ArgType type) {
    RegisterArg resArg = InsnArg.reg(insn, 0, fixResultType(op, type));
    ArgType argType = fixArgType(op, type);
    LiteralArg litArg = InsnArg.lit(insn, argType);
    switch(insn.getRegsCount()) {
        case 1:
            return new ArithNode(op, resArg, InsnArg.reg(insn, 0, argType), litArg);
        case 2:
            return new ArithNode(op, resArg, InsnArg.reg(insn, 1, argType), litArg);
        default:
            throw new JadxRuntimeException("Unexpected registers count in " + insn);
    }
}
Also used : ArgType(jadx.core.dex.instructions.args.ArgType) RegisterArg(jadx.core.dex.instructions.args.RegisterArg) LiteralArg(jadx.core.dex.instructions.args.LiteralArg) JadxRuntimeException(jadx.core.utils.exceptions.JadxRuntimeException)

Example 43 with JadxRuntimeException

use of jadx.core.utils.exceptions.JadxRuntimeException in project jadx by skylot.

the class RegionMaker method processSwitch.

private BlockNode processSwitch(IRegion currentRegion, BlockNode block, SwitchInsn insn, RegionStack stack) {
    // map case blocks to keys
    int len = insn.getTargets().length;
    Map<BlockNode, List<Object>> blocksMap = new LinkedHashMap<>(len);
    BlockNode[] targetBlocksArr = insn.getTargetBlocks();
    for (int i = 0; i < len; i++) {
        List<Object> keys = blocksMap.computeIfAbsent(targetBlocksArr[i], k -> new ArrayList<>(2));
        keys.add(insn.getKey(i));
    }
    BlockNode defCase = insn.getDefTargetBlock();
    if (defCase != null) {
        List<Object> keys = blocksMap.computeIfAbsent(defCase, k -> new ArrayList<>(1));
        keys.add(SwitchRegion.DEFAULT_CASE_KEY);
    }
    // search 'out' block - 'next' block after whole switch statement
    BlockNode out;
    LoopInfo loop = mth.getLoopForBlock(block);
    if (loop == null) {
        out = calcPostDomOut(mth, block, mth.getPreExitBlocks());
    } else {
        BlockNode loopEnd = loop.getEnd();
        stack.addExit(loop.getStart());
        if (stack.containsExit(block) || block == loopEnd || loopEnd.getPredecessors().contains(block)) {
            // in exits or last insn in loop => no 'out' block
            out = null;
        } else {
            // treat 'continue' as exit
            out = calcPostDomOut(mth, block, loopEnd.getPredecessors());
            if (out != null) {
                insertContinueInSwitch(block, out, loopEnd);
            } else {
                // no 'continue'
                out = calcPostDomOut(mth, block, Collections.singletonList(loopEnd));
            }
        }
        if (out == loop.getStart()) {
            // no other outs instead back edge to loop start
            out = null;
        }
    }
    if (out != null && processedBlocks.get(out.getId())) {
        // out block already processed, prevent endless loop
        throw new JadxRuntimeException("Failed to find switch 'out' block");
    }
    SwitchRegion sw = new SwitchRegion(currentRegion, block);
    currentRegion.getSubBlocks().add(sw);
    stack.push(sw);
    stack.addExit(out);
    // detect fallthrough cases
    Map<BlockNode, BlockNode> fallThroughCases = new LinkedHashMap<>();
    if (out != null) {
        BitSet caseBlocks = BlockUtils.blocksToBitSet(mth, blocksMap.keySet());
        caseBlocks.clear(out.getId());
        for (BlockNode successor : block.getCleanSuccessors()) {
            BlockNode fallThroughBlock = searchFallThroughCase(successor, out, caseBlocks);
            if (fallThroughBlock != null) {
                fallThroughCases.put(successor, fallThroughBlock);
            }
        }
        // check fallthrough cases order
        if (!fallThroughCases.isEmpty() && isBadCasesOrder(blocksMap, fallThroughCases)) {
            Map<BlockNode, List<Object>> newBlocksMap = reOrderSwitchCases(blocksMap, fallThroughCases);
            if (isBadCasesOrder(newBlocksMap, fallThroughCases)) {
                mth.addWarnComment("Can't fix incorrect switch cases order, some code will duplicate");
                fallThroughCases.clear();
            } else {
                blocksMap = newBlocksMap;
            }
        }
    }
    for (Entry<BlockNode, List<Object>> entry : blocksMap.entrySet()) {
        List<Object> keysList = entry.getValue();
        BlockNode caseBlock = entry.getKey();
        if (stack.containsExit(caseBlock)) {
            sw.addCase(keysList, new Region(stack.peekRegion()));
        } else {
            BlockNode next = fallThroughCases.get(caseBlock);
            stack.addExit(next);
            Region caseRegion = makeRegion(caseBlock, stack);
            stack.removeExit(next);
            if (next != null) {
                next.add(AFlag.FALL_THROUGH);
                caseRegion.add(AFlag.FALL_THROUGH);
            }
            sw.addCase(keysList, caseRegion);
        // 'break' instruction will be inserted in RegionMakerVisitor.PostRegionVisitor
        }
    }
    removeEmptyCases(insn, sw, defCase);
    stack.pop();
    return out;
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) BitSet(java.util.BitSet) LinkedHashMap(java.util.LinkedHashMap) LoopInfo(jadx.core.dex.attributes.nodes.LoopInfo) Region(jadx.core.dex.regions.Region) IRegion(jadx.core.dex.nodes.IRegion) SwitchRegion(jadx.core.dex.regions.SwitchRegion) SynchronizedRegion(jadx.core.dex.regions.SynchronizedRegion) LoopRegion(jadx.core.dex.regions.loops.LoopRegion) IfRegion(jadx.core.dex.regions.conditions.IfRegion) List(java.util.List) ArrayList(java.util.ArrayList) JadxRuntimeException(jadx.core.utils.exceptions.JadxRuntimeException) SwitchRegion(jadx.core.dex.regions.SwitchRegion)

Example 44 with JadxRuntimeException

use of jadx.core.utils.exceptions.JadxRuntimeException in project jadx by skylot.

the class CodeShrinkVisitor method canMoveBetweenBlocks.

private static boolean canMoveBetweenBlocks(MethodNode mth, InsnNode assignInsn, BlockNode assignBlock, BlockNode useBlock, InsnNode useInsn) {
    if (!BlockUtils.isPathExists(assignBlock, useBlock)) {
        return false;
    }
    List<RegisterArg> argsList = ArgsInfo.getArgs(assignInsn);
    BitSet args = new BitSet();
    for (RegisterArg arg : argsList) {
        args.set(arg.getRegNum());
    }
    boolean startCheck = false;
    for (InsnNode insn : assignBlock.getInstructions()) {
        if (startCheck && (!insn.canReorder() || ArgsInfo.usedArgAssign(insn, args))) {
            return false;
        }
        if (insn == assignInsn) {
            startCheck = true;
        }
    }
    Set<BlockNode> pathsBlocks = BlockUtils.getAllPathsBlocks(assignBlock, useBlock);
    pathsBlocks.remove(assignBlock);
    pathsBlocks.remove(useBlock);
    for (BlockNode block : pathsBlocks) {
        if (block.contains(AFlag.DONT_GENERATE)) {
            if (BlockUtils.checkLastInsnType(block, InsnType.MONITOR_EXIT)) {
                if (RegionUtils.isBlocksInSameRegion(mth, assignBlock, useBlock)) {
                // allow move inside same synchronized region
                } else {
                    // don't move from synchronized block
                    return false;
                }
            }
            // skip checks for not generated blocks
            continue;
        }
        for (InsnNode insn : block.getInstructions()) {
            if (!insn.canReorder() || ArgsInfo.usedArgAssign(insn, args)) {
                return false;
            }
        }
    }
    for (InsnNode insn : useBlock.getInstructions()) {
        if (insn == useInsn) {
            return true;
        }
        if (!insn.canReorder() || ArgsInfo.usedArgAssign(insn, args)) {
            return false;
        }
    }
    throw new JadxRuntimeException("Can't process instruction move : " + assignBlock);
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) InsnNode(jadx.core.dex.nodes.InsnNode) RegisterArg(jadx.core.dex.instructions.args.RegisterArg) BitSet(java.util.BitSet) JadxRuntimeException(jadx.core.utils.exceptions.JadxRuntimeException)

Example 45 with JadxRuntimeException

use of jadx.core.utils.exceptions.JadxRuntimeException in project jadx by skylot.

the class ArgsInfo method canMove.

private boolean canMove(int from, int to) {
    ArgsInfo startInfo = argsList.get(from);
    List<RegisterArg> movedArgs = startInfo.getArgs();
    int start = from + 1;
    if (start == to) {
        // previous instruction or on edge of inline border
        return true;
    }
    if (start > to) {
        throw new JadxRuntimeException("Invalid inline insn positions: " + start + " - " + to);
    }
    BitSet movedSet;
    if (movedArgs.isEmpty()) {
        if (startInfo.insn.isConstInsn()) {
            return true;
        }
        movedSet = EmptyBitSet.EMPTY;
    } else {
        movedSet = new BitSet();
        for (RegisterArg arg : movedArgs) {
            movedSet.set(arg.getRegNum());
        }
    }
    boolean canReorder = startInfo.insn.canReorder();
    for (int i = start; i < to; i++) {
        ArgsInfo argsInfo = argsList.get(i);
        if (argsInfo.getInlinedInsn() == this) {
            continue;
        }
        InsnNode curInsn = argsInfo.insn;
        if (canReorder) {
            if (usedArgAssign(curInsn, movedSet)) {
                return false;
            }
        } else {
            if (!curInsn.canReorder() || usedArgAssign(curInsn, movedSet)) {
                return false;
            }
        }
    }
    return true;
}
Also used : InsnNode(jadx.core.dex.nodes.InsnNode) RegisterArg(jadx.core.dex.instructions.args.RegisterArg) EmptyBitSet(jadx.core.utils.EmptyBitSet) BitSet(java.util.BitSet) JadxRuntimeException(jadx.core.utils.exceptions.JadxRuntimeException)

Aggregations

JadxRuntimeException (jadx.core.utils.exceptions.JadxRuntimeException)115 BlockNode (jadx.core.dex.nodes.BlockNode)25 ArrayList (java.util.ArrayList)25 InsnNode (jadx.core.dex.nodes.InsnNode)24 ArgType (jadx.core.dex.instructions.args.ArgType)20 RegisterArg (jadx.core.dex.instructions.args.RegisterArg)17 BitSet (java.util.BitSet)11 ClassNode (jadx.core.dex.nodes.ClassNode)10 MethodNode (jadx.core.dex.nodes.MethodNode)9 InsnArg (jadx.core.dex.instructions.args.InsnArg)8 SSAVar (jadx.core.dex.instructions.args.SSAVar)8 IOException (java.io.IOException)8 List (java.util.List)8 File (java.io.File)7 IRegion (jadx.core.dex.nodes.IRegion)6 Path (java.nio.file.Path)6 IndexInsnNode (jadx.core.dex.instructions.IndexInsnNode)5 PhiInsn (jadx.core.dex.instructions.PhiInsn)5 LiteralArg (jadx.core.dex.instructions.args.LiteralArg)5 FieldNode (jadx.core.dex.nodes.FieldNode)5