Search in sources :

Example 1 with IfInfo

use of jadx.core.dex.regions.conditions.IfInfo 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 2 with IfInfo

use of jadx.core.dex.regions.conditions.IfInfo in project jadx by skylot.

the class IfMakerHelper method checkForTernaryInCondition.

private static IfInfo checkForTernaryInCondition(IfInfo currentIf) {
    IfInfo nextThen = getNextIf(currentIf, currentIf.getThenBlock());
    IfInfo nextElse = getNextIf(currentIf, currentIf.getElseBlock());
    if (nextThen == null || nextElse == null) {
        return null;
    }
    if (!nextThen.getIfBlock().getDomFrontier().equals(nextElse.getIfBlock().getDomFrontier())) {
        return null;
    }
    nextThen = searchNestedIf(nextThen);
    nextElse = searchNestedIf(nextElse);
    if (nextThen.getThenBlock() == nextElse.getThenBlock() && nextThen.getElseBlock() == nextElse.getElseBlock()) {
        return mergeTernaryConditions(currentIf, nextThen, nextElse);
    }
    if (nextThen.getThenBlock() == nextElse.getElseBlock() && nextThen.getElseBlock() == nextElse.getThenBlock()) {
        nextElse = IfInfo.invert(nextElse);
        return mergeTernaryConditions(currentIf, nextThen, nextElse);
    }
    return null;
}
Also used : IfInfo(jadx.core.dex.regions.conditions.IfInfo)

Example 3 with IfInfo

use of jadx.core.dex.regions.conditions.IfInfo in project jadx by skylot.

the class IfMakerHelper method restructureIf.

static IfInfo restructureIf(MethodNode mth, BlockNode block, IfInfo info) {
    final BlockNode thenBlock = info.getThenBlock();
    final BlockNode elseBlock = info.getElseBlock();
    // select 'then', 'else' and 'exit' blocks
    if (thenBlock.contains(AFlag.RETURN) && elseBlock.contains(AFlag.RETURN)) {
        info.setOutBlock(null);
        return info;
    }
    boolean badThen = isBadBranchBlock(info, thenBlock);
    boolean badElse = isBadBranchBlock(info, elseBlock);
    if (badThen && badElse) {
        LOG.debug("Stop processing blocks after 'if': {}, method: {}", info.getIfBlock(), mth);
        return null;
    }
    if (badElse) {
        info = new IfInfo(info, thenBlock, null);
        info.setOutBlock(elseBlock);
    } else if (badThen) {
        info = IfInfo.invert(info);
        info = new IfInfo(info, elseBlock, null);
        info.setOutBlock(thenBlock);
    } else {
        List<BlockNode> thenSC = thenBlock.getCleanSuccessors();
        List<BlockNode> elseSC = elseBlock.getCleanSuccessors();
        if (thenSC.size() == 1 && sameElements(thenSC, elseSC)) {
            info.setOutBlock(thenSC.get(0));
        } else if (info.getMergedBlocks().size() == 1 && block.getDominatesOn().size() == 2) {
            info.setOutBlock(BlockUtils.getPathCross(mth, thenBlock, elseBlock));
        }
    }
    if (info.getOutBlock() == null) {
        for (BlockNode d : block.getDominatesOn()) {
            if (d != thenBlock && d != elseBlock && !info.getMergedBlocks().contains(d) && isPathExists(thenBlock, d)) {
                info.setOutBlock(d);
                break;
            }
        }
    }
    if (BlockUtils.isBackEdge(block, info.getOutBlock())) {
        info.setOutBlock(null);
    }
    return info;
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) IfInfo(jadx.core.dex.regions.conditions.IfInfo) List(java.util.List)

Example 4 with IfInfo

use of jadx.core.dex.regions.conditions.IfInfo in project jadx by skylot.

the class IfMakerHelper method makeIfInfo.

static IfInfo makeIfInfo(BlockNode ifBlock) {
    IfNode ifNode = (IfNode) ifBlock.getInstructions().get(0);
    IfCondition condition = IfCondition.fromIfNode(ifNode);
    IfInfo info = new IfInfo(condition, ifNode.getThenBlock(), ifNode.getElseBlock());
    info.setIfBlock(ifBlock);
    info.getMergedBlocks().add(ifBlock);
    return info;
}
Also used : IfInfo(jadx.core.dex.regions.conditions.IfInfo) IfNode(jadx.core.dex.instructions.IfNode) IfCondition(jadx.core.dex.regions.conditions.IfCondition)

Example 5 with IfInfo

use of jadx.core.dex.regions.conditions.IfInfo in project jadx by skylot.

the class RegionMaker method processIf.

private BlockNode processIf(IRegion currentRegion, BlockNode block, IfNode ifnode, RegionStack stack) {
    if (block.contains(AFlag.SKIP)) {
        // block already included in other 'if' region
        return ifnode.getThenBlock();
    }
    IfInfo currentIf = makeIfInfo(block);
    IfInfo mergedIf = mergeNestedIfNodes(currentIf);
    if (mergedIf != null) {
        currentIf = mergedIf;
    } else {
        // invert simple condition (compiler often do it)
        currentIf = IfInfo.invert(currentIf);
    }
    IfInfo modifiedIf = IfMakerHelper.restructureIf(mth, block, currentIf);
    if (modifiedIf != null) {
        currentIf = modifiedIf;
    } else {
        if (currentIf.getMergedBlocks().size() <= 1) {
            return null;
        }
        currentIf = makeIfInfo(block);
        currentIf = IfMakerHelper.restructureIf(mth, block, currentIf);
        if (currentIf == null) {
            // all attempts failed
            return null;
        }
    }
    confirmMerge(currentIf);
    IfRegion ifRegion = new IfRegion(currentRegion, block);
    ifRegion.setCondition(currentIf.getCondition());
    currentRegion.getSubBlocks().add(ifRegion);
    BlockNode outBlock = currentIf.getOutBlock();
    stack.push(ifRegion);
    stack.addExit(outBlock);
    ifRegion.setThenRegion(makeRegion(currentIf.getThenBlock(), stack));
    BlockNode elseBlock = currentIf.getElseBlock();
    if (elseBlock == null || stack.containsExit(elseBlock)) {
        ifRegion.setElseRegion(null);
    } else {
        ifRegion.setElseRegion(makeRegion(elseBlock, stack));
    }
    // TODO: make more common algorithm
    if (ifRegion.getElseRegion() == null && outBlock != null) {
        List<EdgeInsnAttr> edgeInsnAttrs = outBlock.getAll(AType.EDGE_INSN);
        if (!edgeInsnAttrs.isEmpty()) {
            Region elseRegion = new Region(ifRegion);
            for (EdgeInsnAttr edgeInsnAttr : edgeInsnAttrs) {
                if (edgeInsnAttr.getEnd().equals(outBlock)) {
                    addEdgeInsn(currentIf, elseRegion, edgeInsnAttr);
                }
            }
            ifRegion.setElseRegion(elseRegion);
        }
    }
    stack.pop();
    return outBlock;
}
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) IfMakerHelper.makeIfInfo(jadx.core.dex.visitors.regions.IfMakerHelper.makeIfInfo) IfInfo(jadx.core.dex.regions.conditions.IfInfo) IfRegion(jadx.core.dex.regions.conditions.IfRegion) EdgeInsnAttr(jadx.core.dex.attributes.nodes.EdgeInsnAttr)

Aggregations

IfInfo (jadx.core.dex.regions.conditions.IfInfo)8 BlockNode (jadx.core.dex.nodes.BlockNode)5 IfCondition (jadx.core.dex.regions.conditions.IfCondition)3 IRegion (jadx.core.dex.nodes.IRegion)2 Region (jadx.core.dex.regions.Region)2 SwitchRegion (jadx.core.dex.regions.SwitchRegion)2 SynchronizedRegion (jadx.core.dex.regions.SynchronizedRegion)2 IfRegion (jadx.core.dex.regions.conditions.IfRegion)2 LoopRegion (jadx.core.dex.regions.loops.LoopRegion)2 IfMakerHelper.makeIfInfo (jadx.core.dex.visitors.regions.IfMakerHelper.makeIfInfo)2 EdgeInsnAttr (jadx.core.dex.attributes.nodes.EdgeInsnAttr)1 IfNode (jadx.core.dex.instructions.IfNode)1 Edge (jadx.core.dex.nodes.Edge)1 Mode (jadx.core.dex.regions.conditions.IfCondition.Mode)1 ArrayList (java.util.ArrayList)1 List (java.util.List)1