Search in sources :

Example 1 with LoopRegion

use of jadx.core.dex.regions.loops.LoopRegion in project jadx by skylot.

the class ProcessTryCatchRegions method wrapBlocks.

/**
	 * Extract all block dominated by 'dominator' to separate region and mark as try/catch block
	 */
private static boolean wrapBlocks(IRegion replaceRegion, TryCatchBlock tb, BlockNode dominator) {
    if (replaceRegion == null) {
        return false;
    }
    if (replaceRegion instanceof LoopRegion) {
        LoopRegion loop = (LoopRegion) replaceRegion;
        return wrapBlocks(loop.getBody(), tb, dominator);
    }
    if (replaceRegion instanceof IBranchRegion) {
        return wrapBlocks(replaceRegion.getParent(), tb, dominator);
    }
    Region tryRegion = new Region(replaceRegion);
    List<IContainer> subBlocks = replaceRegion.getSubBlocks();
    for (IContainer cont : subBlocks) {
        if (RegionUtils.hasPathThroughBlock(dominator, cont)) {
            if (isHandlerPath(tb, cont)) {
                break;
            }
            tryRegion.getSubBlocks().add(cont);
        }
    }
    if (tryRegion.getSubBlocks().isEmpty()) {
        return false;
    }
    TryCatchRegion tryCatchRegion = new TryCatchRegion(replaceRegion, tryRegion);
    tryRegion.setParent(tryCatchRegion);
    tryCatchRegion.setTryCatchBlock(tb.getCatchAttr().getTryBlock());
    // replace first node by region
    IContainer firstNode = tryRegion.getSubBlocks().get(0);
    if (!replaceRegion.replaceSubBlock(firstNode, tryCatchRegion)) {
        return false;
    }
    subBlocks.removeAll(tryRegion.getSubBlocks());
    // fix parents for tryRegion sub blocks
    for (IContainer cont : tryRegion.getSubBlocks()) {
        if (cont instanceof AbstractRegion) {
            AbstractRegion aReg = (AbstractRegion) cont;
            aReg.setParent(tryRegion);
        }
    }
    return true;
}
Also used : TryCatchRegion(jadx.core.dex.regions.TryCatchRegion) IBranchRegion(jadx.core.dex.nodes.IBranchRegion) IRegion(jadx.core.dex.nodes.IRegion) TryCatchRegion(jadx.core.dex.regions.TryCatchRegion) IBranchRegion(jadx.core.dex.nodes.IBranchRegion) LoopRegion(jadx.core.dex.regions.loops.LoopRegion) AbstractRegion(jadx.core.dex.regions.AbstractRegion) Region(jadx.core.dex.regions.Region) LoopRegion(jadx.core.dex.regions.loops.LoopRegion) AbstractRegion(jadx.core.dex.regions.AbstractRegion) IContainer(jadx.core.dex.nodes.IContainer)

Example 2 with LoopRegion

use of jadx.core.dex.regions.loops.LoopRegion 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);
    stack.push(loopRegion);
    BlockNode loopExit = null;
    // insert 'break' for exits
    List<Edge> exitEdges = loop.getExitEdges();
    for (Edge exitEdge : exitEdges) {
        BlockNode exit = exitEdge.getTarget();
        if (insertBreak(stack, exit, exitEdge)) {
            BlockNode nextBlock = getNextBlock(exit);
            if (nextBlock != null) {
                stack.addExit(nextBlock);
                loopExit = nextBlock;
            }
        }
    }
    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 (loopExit == null) {
        BlockNode next = getNextBlock(loopEnd);
        loopExit = RegionUtils.isRegionContainsBlock(body, next) ? null : next;
    }
    stack.pop();
    loopStart.addAttr(AType.LOOP, loop);
    return loopExit;
}
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 LoopRegion

use of jadx.core.dex.regions.loops.LoopRegion 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<BlockNode>(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(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.setCondition(condInfo.getCondition());
    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())) {
                    continue;
                }
                insertBreak(stack, 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.SKIP);
        stack.addExit(loop.getEnd());
        loopRegion.setBody(makeRegion(loopStart, stack));
        loopStart.addAttr(AType.LOOP, loop);
        loop.getEnd().remove(AFlag.SKIP);
    } 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 = makeRegion(loopBody, stack);
        // add blocks from loop start to first condition block
        BlockNode conditionBlock = condInfo.getIfBlock();
        if (loopStart != conditionBlock) {
            Set<BlockNode> blocks = BlockUtils.getAllPathsBlocks(loopStart, conditionBlock);
            blocks.remove(conditionBlock);
            for (BlockNode block : blocks) {
                if (block.getInstructions().isEmpty() && !block.contains(AFlag.SKIP) && !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 LoopRegion

use of jadx.core.dex.regions.loops.LoopRegion in project jadx by skylot.

the class CheckRegions method visit.

@Override
public void visit(MethodNode mth) throws JadxException {
    if (mth.isNoCode() || mth.getBasicBlocks().isEmpty() || mth.contains(AType.JADX_ERROR)) {
        return;
    }
    // check if all blocks included in regions
    final Set<BlockNode> blocksInRegions = new HashSet<BlockNode>();
    DepthRegionTraversal.traverse(mth, new AbstractRegionVisitor() {

        @Override
        public void processBlock(MethodNode mth, IBlock container) {
            if (!(container instanceof BlockNode)) {
                return;
            }
            BlockNode block = (BlockNode) container;
            if (blocksInRegions.add(block)) {
                return;
            }
            if (!block.contains(AFlag.RETURN) && !block.contains(AFlag.SKIP) && !block.contains(AFlag.SYNTHETIC) && !block.getInstructions().isEmpty()) {
                // TODO
                // mth.add(AFlag.INCONSISTENT_CODE);
                LOG.debug(" Duplicated block: {} in {}", block, mth);
            }
        }
    });
    if (mth.getBasicBlocks().size() != blocksInRegions.size()) {
        for (BlockNode block : mth.getBasicBlocks()) {
            if (!blocksInRegions.contains(block) && !block.getInstructions().isEmpty() && !block.contains(AFlag.SKIP)) {
                mth.add(AFlag.INCONSISTENT_CODE);
                LOG.debug(" Missing block: {} in {}", block, mth);
            }
        }
    }
    // check loop conditions
    DepthRegionTraversal.traverse(mth, new AbstractRegionVisitor() {

        @Override
        public boolean enterRegion(MethodNode mth, IRegion region) {
            if (region instanceof LoopRegion) {
                BlockNode loopHeader = ((LoopRegion) region).getHeader();
                if (loopHeader != null && loopHeader.getInstructions().size() != 1) {
                    ErrorsCounter.methodError(mth, "Incorrect condition in loop: " + loopHeader);
                }
            }
            return true;
        }
    });
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) IBlock(jadx.core.dex.nodes.IBlock) MethodNode(jadx.core.dex.nodes.MethodNode) LoopRegion(jadx.core.dex.regions.loops.LoopRegion) IRegion(jadx.core.dex.nodes.IRegion) HashSet(java.util.HashSet)

Example 5 with LoopRegion

use of jadx.core.dex.regions.loops.LoopRegion in project jadx by skylot.

the class RegionMaker method makeLoopRegion.

/**
	 * Select loop exit and construct LoopRegion
	 */
private LoopRegion makeLoopRegion(IRegion curRegion, LoopInfo loop, List<BlockNode> exitBlocks) {
    for (BlockNode block : exitBlocks) {
        if (block.contains(AType.EXC_HANDLER) || block.getInstructions().size() != 1 || block.getInstructions().get(0).getType() != InsnType.IF) {
            continue;
        }
        List<LoopInfo> loops = block.getAll(AType.LOOP);
        if (!loops.isEmpty() && loops.get(0) != loop) {
            // skip nested loop condition
            continue;
        }
        LoopRegion loopRegion = new LoopRegion(curRegion, loop, block, block == loop.getEnd());
        boolean found;
        if (block == loop.getStart() || block == loop.getEnd() || BlockUtils.isEmptySimplePath(loop.getStart(), block)) {
            found = true;
        } else if (block.getPredecessors().contains(loop.getStart())) {
            loopRegion.setPreCondition(loop.getStart());
            // if we can't merge pre-condition this is not correct header
            found = loopRegion.checkPreCondition();
        } else {
            found = false;
        }
        if (found) {
            List<LoopInfo> list = mth.getAllLoopsForBlock(block);
            if (list.size() >= 2) {
                // bad condition if successors going out of all loops
                boolean allOuter = true;
                for (BlockNode outerBlock : block.getCleanSuccessors()) {
                    List<LoopInfo> outLoopList = mth.getAllLoopsForBlock(outerBlock);
                    outLoopList.remove(loop);
                    if (!outLoopList.isEmpty()) {
                        // goes to outer loop
                        allOuter = false;
                        break;
                    }
                }
                if (allOuter) {
                    found = false;
                }
            }
        }
        if (found) {
            return loopRegion;
        }
    }
    // no exit found => endless loop
    return null;
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) LoopInfo(jadx.core.dex.attributes.nodes.LoopInfo) LoopRegion(jadx.core.dex.regions.loops.LoopRegion)

Aggregations

LoopRegion (jadx.core.dex.regions.loops.LoopRegion)5 BlockNode (jadx.core.dex.nodes.BlockNode)4 IRegion (jadx.core.dex.nodes.IRegion)4 Region (jadx.core.dex.regions.Region)3 Edge (jadx.core.dex.nodes.Edge)2 SwitchRegion (jadx.core.dex.regions.SwitchRegion)2 SynchronizedRegion (jadx.core.dex.regions.SynchronizedRegion)2 IfRegion (jadx.core.dex.regions.conditions.IfRegion)2 LoopInfo (jadx.core.dex.attributes.nodes.LoopInfo)1 IBlock (jadx.core.dex.nodes.IBlock)1 IBranchRegion (jadx.core.dex.nodes.IBranchRegion)1 IContainer (jadx.core.dex.nodes.IContainer)1 MethodNode (jadx.core.dex.nodes.MethodNode)1 AbstractRegion (jadx.core.dex.regions.AbstractRegion)1 TryCatchRegion (jadx.core.dex.regions.TryCatchRegion)1 IfInfo (jadx.core.dex.regions.conditions.IfInfo)1 IfMakerHelper.makeIfInfo (jadx.core.dex.visitors.regions.IfMakerHelper.makeIfInfo)1 ArrayList (java.util.ArrayList)1 HashSet (java.util.HashSet)1