Search in sources :

Example 1 with Region

use of jadx.core.dex.regions.Region 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 Region

use of jadx.core.dex.regions.Region in project jadx by skylot.

the class RegionMaker method processSwitch.

private BlockNode processSwitch(IRegion currentRegion, BlockNode block, SwitchNode insn, RegionStack stack) {
    SwitchRegion sw = new SwitchRegion(currentRegion, block);
    currentRegion.getSubBlocks().add(sw);
    int len = insn.getTargets().length;
    // sort by target
    Map<Integer, List<Object>> casesMap = new LinkedHashMap<Integer, List<Object>>(len);
    for (int i = 0; i < len; i++) {
        Object key = insn.getKeys()[i];
        int targ = insn.getTargets()[i];
        List<Object> keys = casesMap.get(targ);
        if (keys == null) {
            keys = new ArrayList<Object>(2);
            casesMap.put(targ, keys);
        }
        keys.add(key);
    }
    Map<BlockNode, List<Object>> blocksMap = new LinkedHashMap<BlockNode, List<Object>>(len);
    for (Map.Entry<Integer, List<Object>> entry : casesMap.entrySet()) {
        BlockNode c = getBlockByOffset(entry.getKey(), block.getSuccessors());
        if (c == null) {
            throw new JadxRuntimeException("Switch block not found by offset: " + entry.getKey());
        }
        blocksMap.put(c, entry.getValue());
    }
    BlockNode defCase = getBlockByOffset(insn.getDefaultCaseOffset(), block.getSuccessors());
    if (defCase != null) {
        blocksMap.remove(defCase);
    }
    LoopInfo loop = mth.getLoopForBlock(block);
    Map<BlockNode, BlockNode> fallThroughCases = new LinkedHashMap<BlockNode, BlockNode>();
    List<BlockNode> basicBlocks = mth.getBasicBlocks();
    BitSet outs = new BitSet(basicBlocks.size());
    outs.or(block.getDomFrontier());
    for (BlockNode s : block.getCleanSuccessors()) {
        BitSet df = s.getDomFrontier();
        // fall through case block
        if (df.cardinality() > 1) {
            if (df.cardinality() > 2) {
                LOG.debug("Unexpected case pattern, block: {}, mth: {}", s, mth);
            } else {
                BlockNode first = basicBlocks.get(df.nextSetBit(0));
                BlockNode second = basicBlocks.get(df.nextSetBit(first.getId() + 1));
                if (second.getDomFrontier().get(first.getId())) {
                    fallThroughCases.put(s, second);
                    df = new BitSet(df.size());
                    df.set(first.getId());
                } else if (first.getDomFrontier().get(second.getId())) {
                    fallThroughCases.put(s, first);
                    df = new BitSet(df.size());
                    df.set(second.getId());
                }
            }
        }
        outs.or(df);
    }
    outs.clear(block.getId());
    if (loop != null) {
        outs.clear(loop.getStart().getId());
    }
    stack.push(sw);
    stack.addExits(BlockUtils.bitSetToBlocks(mth, outs));
    // check cases order if fall through case exists
    if (!fallThroughCases.isEmpty()) {
        if (isBadCasesOrder(blocksMap, fallThroughCases)) {
            LOG.debug("Fixing incorrect switch cases order, method: {}", mth);
            blocksMap = reOrderSwitchCases(blocksMap, fallThroughCases);
            if (isBadCasesOrder(blocksMap, fallThroughCases)) {
                LOG.error("Can't fix incorrect switch cases order, method: {}", mth);
                mth.add(AFlag.INCONSISTENT_CODE);
            }
        }
    }
    // filter 'out' block
    if (outs.cardinality() > 1) {
        // remove exception handlers
        BlockUtils.cleanBitSet(mth, outs);
    }
    if (outs.cardinality() > 1) {
        // filter loop start and successors of other blocks
        for (int i = outs.nextSetBit(0); i >= 0; i = outs.nextSetBit(i + 1)) {
            BlockNode b = basicBlocks.get(i);
            outs.andNot(b.getDomFrontier());
            if (b.contains(AFlag.LOOP_START)) {
                outs.clear(b.getId());
            } else {
                for (BlockNode s : b.getCleanSuccessors()) {
                    outs.clear(s.getId());
                }
            }
        }
    }
    if (loop != null && outs.cardinality() > 1) {
        outs.clear(loop.getEnd().getId());
    }
    if (outs.cardinality() == 0) {
        // run expensive algorithm for find 'out' block
        for (BlockNode maybeOut : block.getSuccessors()) {
            boolean allReached = true;
            for (BlockNode s : block.getSuccessors()) {
                if (!isPathExists(s, maybeOut)) {
                    allReached = false;
                    break;
                }
            }
            if (allReached) {
                outs.set(maybeOut.getId());
                break;
            }
        }
    }
    BlockNode out = null;
    if (outs.cardinality() == 1) {
        out = basicBlocks.get(outs.nextSetBit(0));
        stack.addExit(out);
    } else if (loop == null && outs.cardinality() > 1) {
        LOG.warn("Can't detect out node for switch block: {} in {}", block, mth);
    }
    if (loop != null) {
        // check if 'continue' must be inserted
        BlockNode end = loop.getEnd();
        if (out != end && out != null) {
            insertContinueInSwitch(block, out, end);
        }
    }
    if (!stack.containsExit(defCase)) {
        sw.setDefaultCase(makeRegion(defCase, stack));
    }
    for (Entry<BlockNode, List<Object>> entry : blocksMap.entrySet()) {
        BlockNode caseBlock = entry.getKey();
        if (stack.containsExit(caseBlock)) {
            // empty case block
            sw.addCase(entry.getValue(), 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(entry.getValue(), caseRegion);
        // 'break' instruction will be inserted in RegionMakerVisitor.PostRegionVisitor
        }
    }
    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) SwitchRegion(jadx.core.dex.regions.SwitchRegion) List(java.util.List) ArrayList(java.util.ArrayList) JadxRuntimeException(jadx.core.utils.exceptions.JadxRuntimeException) Map(java.util.Map) LinkedHashMap(java.util.LinkedHashMap)

Example 3 with Region

use of jadx.core.dex.regions.Region in project jadx by skylot.

the class RegionMaker method processHandlersOutBlocks.

/**
	 * Search handlers successor blocks not included in any region.
	 */
protected IRegion processHandlersOutBlocks(MethodNode mth, Set<TryCatchBlock> tcs) {
    Set<IBlock> allRegionBlocks = new HashSet<IBlock>();
    RegionUtils.getAllRegionBlocks(mth.getRegion(), allRegionBlocks);
    Set<IBlock> succBlocks = new HashSet<IBlock>();
    for (TryCatchBlock tc : tcs) {
        for (ExceptionHandler handler : tc.getHandlers()) {
            IContainer region = handler.getHandlerRegion();
            if (region != null) {
                IBlock lastBlock = RegionUtils.getLastBlock(region);
                if (lastBlock instanceof BlockNode) {
                    succBlocks.addAll(((BlockNode) lastBlock).getSuccessors());
                }
                RegionUtils.getAllRegionBlocks(region, allRegionBlocks);
            }
        }
    }
    succBlocks.removeAll(allRegionBlocks);
    if (succBlocks.isEmpty()) {
        return null;
    }
    Region excOutRegion = new Region(mth.getRegion());
    for (IBlock block : succBlocks) {
        if (block instanceof BlockNode) {
            excOutRegion.add(makeRegion((BlockNode) block, new RegionStack(mth)));
        }
    }
    return excOutRegion;
}
Also used : ExceptionHandler(jadx.core.dex.trycatch.ExceptionHandler) BlockNode(jadx.core.dex.nodes.BlockNode) IBlock(jadx.core.dex.nodes.IBlock) 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) TryCatchBlock(jadx.core.dex.trycatch.TryCatchBlock) IContainer(jadx.core.dex.nodes.IContainer) HashSet(java.util.HashSet)

Example 4 with Region

use of jadx.core.dex.regions.Region in project jadx by skylot.

the class RegionUtils method isBlocksInSameRegion.

/**
 * Check if two blocks in same region on same level
 * TODO: Add 'region' annotation to all blocks to speed up checks
 */
public static boolean isBlocksInSameRegion(MethodNode mth, BlockNode firstBlock, BlockNode secondBlock) {
    Region region = mth.getRegion();
    if (region == null) {
        return false;
    }
    IContainer firstContainer = getBlockContainer(region, firstBlock);
    if (firstContainer instanceof IRegion) {
        if (firstContainer instanceof IBranchRegion) {
            return false;
        }
        List<IContainer> subBlocks = ((IRegion) firstContainer).getSubBlocks();
        return subBlocks.contains(secondBlock);
    }
    return false;
}
Also used : IRegion(jadx.core.dex.nodes.IRegion) Region(jadx.core.dex.regions.Region) IBranchRegion(jadx.core.dex.nodes.IBranchRegion) IBranchRegion(jadx.core.dex.nodes.IBranchRegion) IContainer(jadx.core.dex.nodes.IContainer) IRegion(jadx.core.dex.nodes.IRegion)

Example 5 with Region

use of jadx.core.dex.regions.Region 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)

Aggregations

Region (jadx.core.dex.regions.Region)19 IRegion (jadx.core.dex.nodes.IRegion)17 LoopRegion (jadx.core.dex.regions.loops.LoopRegion)14 BlockNode (jadx.core.dex.nodes.BlockNode)11 SwitchRegion (jadx.core.dex.regions.SwitchRegion)11 SynchronizedRegion (jadx.core.dex.regions.SynchronizedRegion)11 IfRegion (jadx.core.dex.regions.conditions.IfRegion)11 IContainer (jadx.core.dex.nodes.IContainer)10 HashSet (java.util.HashSet)4 IBlock (jadx.core.dex.nodes.IBlock)3 IBranchRegion (jadx.core.dex.nodes.IBranchRegion)3 TryCatchRegion (jadx.core.dex.regions.TryCatchRegion)3 ArrayList (java.util.ArrayList)3 LoopInfo (jadx.core.dex.attributes.nodes.LoopInfo)2 Edge (jadx.core.dex.nodes.Edge)2 AbstractRegion (jadx.core.dex.regions.AbstractRegion)2 IfInfo (jadx.core.dex.regions.conditions.IfInfo)2 ExceptionHandler (jadx.core.dex.trycatch.ExceptionHandler)2 IfMakerHelper.makeIfInfo (jadx.core.dex.visitors.regions.IfMakerHelper.makeIfInfo)2 JadxRuntimeException (jadx.core.utils.exceptions.JadxRuntimeException)2