Search in sources :

Example 1 with Edge

use of jadx.core.dex.nodes.Edge in project jadx by skylot.

the class BlockProcessor method modifyBlocksTree.

private static boolean modifyBlocksTree(MethodNode mth) {
    for (BlockNode block : mth.getBasicBlocks()) {
        if (block.getPredecessors().isEmpty() && block != mth.getEnterBlock()) {
            throw new JadxRuntimeException("Unreachable block: " + block);
        }
        // check loops
        List<LoopInfo> loops = block.getAll(AType.LOOP);
        if (loops.size() > 1) {
            boolean oneHeader = true;
            for (LoopInfo loop : loops) {
                if (loop.getStart() != block) {
                    oneHeader = false;
                    break;
                }
            }
            if (oneHeader) {
                // several back edges connected to one loop header => make additional block
                BlockNode newLoopHeader = BlockSplitter.startNewBlock(mth, block.getStartOffset());
                newLoopHeader.add(AFlag.SYNTHETIC);
                connect(newLoopHeader, block);
                for (LoopInfo la : loops) {
                    BlockNode node = la.getEnd();
                    removeConnection(node, block);
                    connect(node, newLoopHeader);
                }
                return true;
            }
        }
        if (loops.size() == 1) {
            LoopInfo loop = loops.get(0);
            // insert additional blocks for possible 'break' insertion
            List<Edge> edges = loop.getExitEdges();
            if (!edges.isEmpty()) {
                boolean change = false;
                for (Edge edge : edges) {
                    BlockNode target = edge.getTarget();
                    if (!target.contains(AFlag.SYNTHETIC)) {
                        BlockSplitter.insertBlockBetween(mth, edge.getSource(), target);
                        change = true;
                    }
                }
                if (change) {
                    return true;
                }
            }
            // insert additional blocks for possible 'continue' insertion
            BlockNode loopEnd = loop.getEnd();
            if (loopEnd.getPredecessors().size() > 1) {
                boolean change = false;
                List<BlockNode> nodes = new ArrayList<BlockNode>(loopEnd.getPredecessors());
                for (BlockNode pred : nodes) {
                    if (!pred.contains(AFlag.SYNTHETIC)) {
                        BlockSplitter.insertBlockBetween(mth, pred, loopEnd);
                        change = true;
                    }
                }
                if (change) {
                    return true;
                }
            }
        }
    }
    return splitReturn(mth);
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) LoopInfo(jadx.core.dex.attributes.nodes.LoopInfo) ArrayList(java.util.ArrayList) JadxRuntimeException(jadx.core.utils.exceptions.JadxRuntimeException) Edge(jadx.core.dex.nodes.Edge)

Example 2 with Edge

use of jadx.core.dex.nodes.Edge in project jadx by skylot.

the class RegionMaker method makeEndlessLoop.

private BlockNode makeEndlessLoop(IRegion curRegion, RegionStack stack, LoopInfo loop, BlockNode loopStart) {
    LoopRegion loopRegion = new LoopRegion(curRegion, loop, null, false);
    curRegion.getSubBlocks().add(loopRegion);
    loopStart.remove(AType.LOOP);
    processedBlocks.clear(loopStart.getId());
    stack.push(loopRegion);
    BlockNode out = null;
    // insert 'break' for exits
    List<Edge> exitEdges = loop.getExitEdges();
    if (exitEdges.size() == 1) {
        Edge exitEdge = exitEdges.get(0);
        BlockNode exit = exitEdge.getTarget();
        if (insertLoopBreak(stack, loop, exit, exitEdge)) {
            BlockNode nextBlock = getNextBlock(exit);
            if (nextBlock != null) {
                stack.addExit(nextBlock);
                out = nextBlock;
            }
        }
    } else {
        for (Edge exitEdge : exitEdges) {
            BlockNode exit = exitEdge.getTarget();
            List<BlockNode> blocks = BlockUtils.bitSetToBlocks(mth, exit.getDomFrontier());
            for (BlockNode block : blocks) {
                if (BlockUtils.isPathExists(exit, block)) {
                    stack.addExit(block);
                    insertLoopBreak(stack, loop, block, exitEdge);
                    out = block;
                } else {
                    insertLoopBreak(stack, loop, exit, exitEdge);
                }
            }
        }
    }
    Region body = makeRegion(loopStart, stack);
    BlockNode loopEnd = loop.getEnd();
    if (!RegionUtils.isRegionContainsBlock(body, loopEnd) && !loopEnd.contains(AType.EXC_HANDLER) && !inExceptionHandlerBlocks(loopEnd)) {
        body.getSubBlocks().add(loopEnd);
    }
    loopRegion.setBody(body);
    if (out == null) {
        BlockNode next = getNextBlock(loopEnd);
        out = RegionUtils.isRegionContainsBlock(body, next) ? null : next;
    }
    stack.pop();
    loopStart.addAttr(AType.LOOP, loop);
    return out;
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) 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) LoopRegion(jadx.core.dex.regions.loops.LoopRegion) Edge(jadx.core.dex.nodes.Edge)

Example 3 with Edge

use of jadx.core.dex.nodes.Edge in project jadx by skylot.

the class RegionMaker method processLoop.

private BlockNode processLoop(IRegion curRegion, LoopInfo loop, RegionStack stack) {
    BlockNode loopStart = loop.getStart();
    Set<BlockNode> exitBlocksSet = loop.getExitNodes();
    // set exit blocks scan order priority
    // this can help if loop have several exits (after using 'break' or 'return' in loop)
    List<BlockNode> exitBlocks = new ArrayList<>(exitBlocksSet.size());
    BlockNode nextStart = getNextBlock(loopStart);
    if (nextStart != null && exitBlocksSet.remove(nextStart)) {
        exitBlocks.add(nextStart);
    }
    if (exitBlocksSet.remove(loopStart)) {
        exitBlocks.add(loopStart);
    }
    if (exitBlocksSet.remove(loop.getEnd())) {
        exitBlocks.add(loop.getEnd());
    }
    exitBlocks.addAll(exitBlocksSet);
    LoopRegion loopRegion = makeLoopRegion(curRegion, loop, exitBlocks);
    if (loopRegion == null) {
        BlockNode exit = makeEndlessLoop(curRegion, stack, loop, loopStart);
        insertContinue(loop);
        return exit;
    }
    curRegion.getSubBlocks().add(loopRegion);
    IRegion outerRegion = stack.peekRegion();
    stack.push(loopRegion);
    IfInfo condInfo = makeIfInfo(mth, loopRegion.getHeader());
    condInfo = searchNestedIf(condInfo);
    confirmMerge(condInfo);
    if (!loop.getLoopBlocks().contains(condInfo.getThenBlock())) {
        // invert loop condition if 'then' points to exit
        condInfo = IfInfo.invert(condInfo);
    }
    loopRegion.updateCondition(condInfo);
    exitBlocks.removeAll(condInfo.getMergedBlocks());
    if (!exitBlocks.isEmpty()) {
        BlockNode loopExit = condInfo.getElseBlock();
        if (loopExit != null) {
            // add 'break' instruction before path cross between main loop exit and sub-exit
            for (Edge exitEdge : loop.getExitEdges()) {
                if (exitBlocks.contains(exitEdge.getSource())) {
                    insertLoopBreak(stack, loop, loopExit, exitEdge);
                }
            }
        }
    }
    BlockNode out;
    if (loopRegion.isConditionAtEnd()) {
        BlockNode thenBlock = condInfo.getThenBlock();
        out = thenBlock == loopStart ? condInfo.getElseBlock() : thenBlock;
        loopStart.remove(AType.LOOP);
        loop.getEnd().add(AFlag.ADDED_TO_REGION);
        stack.addExit(loop.getEnd());
        processedBlocks.clear(loopStart.getId());
        Region body = makeRegion(loopStart, stack);
        loopRegion.setBody(body);
        loopStart.addAttr(AType.LOOP, loop);
        loop.getEnd().remove(AFlag.ADDED_TO_REGION);
    } else {
        out = condInfo.getElseBlock();
        if (outerRegion != null && out.contains(AFlag.LOOP_START) && !out.getAll(AType.LOOP).contains(loop) && RegionUtils.isRegionContainsBlock(outerRegion, out)) {
            // exit to already processed outer loop
            out = null;
        }
        stack.addExit(out);
        BlockNode loopBody = condInfo.getThenBlock();
        Region body;
        if (Objects.equals(loopBody, loopStart)) {
            // empty loop body
            body = new Region(loopRegion);
        } else {
            body = makeRegion(loopBody, stack);
        }
        // add blocks from loop start to first condition block
        BlockNode conditionBlock = condInfo.getFirstIfBlock();
        if (loopStart != conditionBlock) {
            Set<BlockNode> blocks = BlockUtils.getAllPathsBlocks(loopStart, conditionBlock);
            blocks.remove(conditionBlock);
            for (BlockNode block : blocks) {
                if (block.getInstructions().isEmpty() && !block.contains(AFlag.ADDED_TO_REGION) && !RegionUtils.isRegionContainsBlock(body, block)) {
                    body.add(block);
                }
            }
        }
        loopRegion.setBody(body);
    }
    stack.pop();
    insertContinue(loop);
    return out;
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) ArrayList(java.util.ArrayList) 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) IfMakerHelper.makeIfInfo(jadx.core.dex.visitors.regions.IfMakerHelper.makeIfInfo) IfInfo(jadx.core.dex.regions.conditions.IfInfo) LoopRegion(jadx.core.dex.regions.loops.LoopRegion) Edge(jadx.core.dex.nodes.Edge) IRegion(jadx.core.dex.nodes.IRegion)

Example 4 with Edge

use of jadx.core.dex.nodes.Edge in project jadx by skylot.

the class BlockProcessor method insertBlocksForBreak.

/**
 * Insert additional blocks for possible 'break' insertion
 */
private static boolean insertBlocksForBreak(MethodNode mth, LoopInfo loop) {
    boolean change = false;
    List<Edge> edges = loop.getExitEdges();
    if (!edges.isEmpty()) {
        for (Edge edge : edges) {
            BlockNode target = edge.getTarget();
            BlockNode source = edge.getSource();
            if (!target.contains(AFlag.SYNTHETIC) && !source.contains(AFlag.SYNTHETIC)) {
                BlockSplitter.insertBlockBetween(mth, source, target);
                change = true;
            }
        }
    }
    return change;
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) Edge(jadx.core.dex.nodes.Edge)

Example 5 with Edge

use of jadx.core.dex.nodes.Edge in project jadx by skylot.

the class RegionMaker method checkLoopExits.

private boolean checkLoopExits(LoopInfo loop, BlockNode mainExitBlock) {
    List<Edge> exitEdges = loop.getExitEdges();
    if (exitEdges.size() < 2) {
        return true;
    }
    Optional<Edge> mainEdgeOpt = exitEdges.stream().filter(edge -> edge.getSource() == mainExitBlock).findFirst();
    if (!mainEdgeOpt.isPresent()) {
        throw new JadxRuntimeException("Not found exit edge by exit block: " + mainExitBlock);
    }
    Edge mainExitEdge = mainEdgeOpt.get();
    BlockNode mainOutBlock = mainExitEdge.getTarget();
    for (Edge exitEdge : exitEdges) {
        if (exitEdge != mainExitEdge) {
            // all exit paths must be same or don't cross (will be inside loop)
            BlockNode exitBlock = exitEdge.getTarget();
            if (!isEqualPaths(mainOutBlock, exitBlock)) {
                BlockNode crossBlock = BlockUtils.getPathCross(mth, mainOutBlock, exitBlock);
                if (crossBlock != null) {
                    return false;
                }
            }
        }
    }
    return true;
}
Also used : BlockUtils.followEmptyPath(jadx.core.utils.BlockUtils.followEmptyPath) BlockUtils.isPathExists(jadx.core.utils.BlockUtils.isPathExists) MethodNode(jadx.core.dex.nodes.MethodNode) AType(jadx.core.dex.attributes.AType) IfMakerHelper.mergeNestedIfNodes(jadx.core.dex.visitors.regions.IfMakerHelper.mergeNestedIfNodes) LoggerFactory(org.slf4j.LoggerFactory) EdgeInsnAttr(jadx.core.dex.attributes.nodes.EdgeInsnAttr) IfMakerHelper.makeIfInfo(jadx.core.dex.visitors.regions.IfMakerHelper.makeIfInfo) LoopInfo(jadx.core.dex.attributes.nodes.LoopInfo) ExcHandlerAttr(jadx.core.dex.trycatch.ExcHandlerAttr) Map(java.util.Map) InsnNode(jadx.core.dex.nodes.InsnNode) Set(java.util.Set) IfInfo(jadx.core.dex.regions.conditions.IfInfo) Edge(jadx.core.dex.nodes.Edge) Objects(java.util.Objects) Nullable(org.jetbrains.annotations.Nullable) List(java.util.List) SwitchInsn(jadx.core.dex.instructions.SwitchInsn) Region(jadx.core.dex.regions.Region) IContainer(jadx.core.dex.nodes.IContainer) Entry(java.util.Map.Entry) Optional(java.util.Optional) IRegion(jadx.core.dex.nodes.IRegion) AFlag(jadx.core.dex.attributes.AFlag) IfMakerHelper.searchNestedIf(jadx.core.dex.visitors.regions.IfMakerHelper.searchNestedIf) InsnType(jadx.core.dex.instructions.InsnType) JadxOverflowException(jadx.core.utils.exceptions.JadxOverflowException) BlockUtils(jadx.core.utils.BlockUtils) SwitchRegion(jadx.core.dex.regions.SwitchRegion) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) IfNode(jadx.core.dex.instructions.IfNode) BlockUtils.getNextBlock(jadx.core.utils.BlockUtils.getNextBlock) TryCatchBlockAttr(jadx.core.dex.trycatch.TryCatchBlockAttr) InsnArg(jadx.core.dex.instructions.args.InsnArg) LinkedHashSet(java.util.LinkedHashSet) SynchronizedRegion(jadx.core.dex.regions.SynchronizedRegion) RegionUtils(jadx.core.utils.RegionUtils) Logger(org.slf4j.Logger) LoopRegion(jadx.core.dex.regions.loops.LoopRegion) IfRegion(jadx.core.dex.regions.conditions.IfRegion) LoopLabelAttr(jadx.core.dex.attributes.nodes.LoopLabelAttr) JadxRuntimeException(jadx.core.utils.exceptions.JadxRuntimeException) BlockNode(jadx.core.dex.nodes.BlockNode) InsnContainer(jadx.core.dex.nodes.InsnContainer) ExceptionHandler(jadx.core.dex.trycatch.ExceptionHandler) BitSet(java.util.BitSet) Collections(java.util.Collections) IfMakerHelper.confirmMerge(jadx.core.dex.visitors.regions.IfMakerHelper.confirmMerge) IBlock(jadx.core.dex.nodes.IBlock) Utils(jadx.core.utils.Utils) BlockNode(jadx.core.dex.nodes.BlockNode) JadxRuntimeException(jadx.core.utils.exceptions.JadxRuntimeException) Edge(jadx.core.dex.nodes.Edge)

Aggregations

BlockNode (jadx.core.dex.nodes.BlockNode)7 Edge (jadx.core.dex.nodes.Edge)7 ArrayList (java.util.ArrayList)4 LoopInfo (jadx.core.dex.attributes.nodes.LoopInfo)3 IRegion (jadx.core.dex.nodes.IRegion)3 Region (jadx.core.dex.regions.Region)3 SwitchRegion (jadx.core.dex.regions.SwitchRegion)3 SynchronizedRegion (jadx.core.dex.regions.SynchronizedRegion)3 IfRegion (jadx.core.dex.regions.conditions.IfRegion)3 LoopRegion (jadx.core.dex.regions.loops.LoopRegion)3 InsnNode (jadx.core.dex.nodes.InsnNode)2 IfInfo (jadx.core.dex.regions.conditions.IfInfo)2 IfMakerHelper.makeIfInfo (jadx.core.dex.visitors.regions.IfMakerHelper.makeIfInfo)2 JadxRuntimeException (jadx.core.utils.exceptions.JadxRuntimeException)2 AFlag (jadx.core.dex.attributes.AFlag)1 AType (jadx.core.dex.attributes.AType)1 EdgeInsnAttr (jadx.core.dex.attributes.nodes.EdgeInsnAttr)1 LoopLabelAttr (jadx.core.dex.attributes.nodes.LoopLabelAttr)1 IfNode (jadx.core.dex.instructions.IfNode)1 InsnType (jadx.core.dex.instructions.InsnType)1