Search in sources :

Example 1 with IRegion

use of jadx.core.dex.nodes.IRegion 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 IRegion

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

the class ProcessVariables method visit.

@Override
public void visit(MethodNode mth) throws JadxException {
    if (mth.isNoCode()) {
        return;
    }
    final Map<Variable, Usage> usageMap = new LinkedHashMap<Variable, Usage>();
    for (RegisterArg arg : mth.getArguments(true)) {
        addToUsageMap(arg, usageMap);
    }
    // collect all variables usage
    IRegionVisitor collect = new CollectUsageRegionVisitor(usageMap);
    DepthRegionTraversal.traverse(mth, collect);
    // reduce assigns map
    List<RegisterArg> mthArgs = mth.getArguments(true);
    for (RegisterArg arg : mthArgs) {
        usageMap.remove(new Variable(arg));
    }
    Iterator<Entry<Variable, Usage>> umIt = usageMap.entrySet().iterator();
    while (umIt.hasNext()) {
        Entry<Variable, Usage> entry = umIt.next();
        Usage u = entry.getValue();
        // if no assigns => remove
        if (u.getAssigns().isEmpty()) {
            umIt.remove();
            continue;
        }
        // variable declared at 'catch' clause
        InsnNode parentInsn = u.getArg().getParentInsn();
        if (parentInsn == null || parentInsn.getType() == InsnType.MOVE_EXCEPTION) {
            umIt.remove();
        }
    }
    if (usageMap.isEmpty()) {
        return;
    }
    Map<IContainer, Integer> regionsOrder = new HashMap<IContainer, Integer>();
    calculateOrder(mth.getRegion(), regionsOrder, 0, true);
    for (Iterator<Entry<Variable, Usage>> it = usageMap.entrySet().iterator(); it.hasNext(); ) {
        Entry<Variable, Usage> entry = it.next();
        Usage u = entry.getValue();
        // check if variable can be declared at current assigns
        for (IRegion assignRegion : u.getAssigns()) {
            if (u.getArgRegion() == assignRegion && canDeclareInRegion(u, assignRegion, regionsOrder)) {
                if (declareAtAssign(u)) {
                    it.remove();
                    break;
                }
            }
        }
    }
    if (usageMap.isEmpty()) {
        return;
    }
    // apply
    for (Entry<Variable, Usage> entry : usageMap.entrySet()) {
        Usage u = entry.getValue();
        // find region which contain all usage regions
        Set<IRegion> set = u.getUseRegions();
        for (Iterator<IRegion> it = set.iterator(); it.hasNext(); ) {
            IRegion r = it.next();
            IRegion parent = r.getParent();
            if (parent != null && set.contains(parent)) {
                it.remove();
            }
        }
        IRegion region = null;
        if (!set.isEmpty()) {
            region = set.iterator().next();
        } else if (!u.getAssigns().isEmpty()) {
            region = u.getAssigns().iterator().next();
        }
        if (region == null) {
            continue;
        }
        IRegion parent = region;
        boolean declared = false;
        while (parent != null) {
            if (canDeclareInRegion(u, region, regionsOrder)) {
                declareVar(region, u.getArg());
                declared = true;
                break;
            }
            region = parent;
            parent = region.getParent();
        }
        if (!declared) {
            declareVar(mth.getRegion(), u.getArg());
        }
    }
}
Also used : HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) IRegion(jadx.core.dex.nodes.IRegion) LinkedHashMap(java.util.LinkedHashMap) InsnNode(jadx.core.dex.nodes.InsnNode) RegisterArg(jadx.core.dex.instructions.args.RegisterArg) Entry(java.util.Map.Entry) IContainer(jadx.core.dex.nodes.IContainer)

Example 3 with IRegion

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

the class ProcessVariables method calculateOrder.

private static int calculateOrder(IContainer container, Map<IContainer, Integer> regionsOrder, int id, boolean inc) {
    if (!(container instanceof IRegion)) {
        return id;
    }
    IRegion region = (IRegion) container;
    Integer previous = regionsOrder.put(region, id);
    if (previous != null) {
        return id;
    }
    for (IContainer c : region.getSubBlocks()) {
        if (c instanceof IBranchRegion) {
            // on branch set for all inner regions same order id
            id = calculateOrder(c, regionsOrder, inc ? id + 1 : id, false);
        } else {
            List<IContainer> handlers = RegionUtils.getExcHandlersForRegion(c);
            if (!handlers.isEmpty()) {
                for (IContainer handler : handlers) {
                    id = calculateOrder(handler, regionsOrder, inc ? id + 1 : id, inc);
                }
            }
            id = calculateOrder(c, regionsOrder, inc ? id + 1 : id, inc);
        }
    }
    return id;
}
Also used : IBranchRegion(jadx.core.dex.nodes.IBranchRegion) IContainer(jadx.core.dex.nodes.IContainer) IRegion(jadx.core.dex.nodes.IRegion)

Example 4 with IRegion

use of jadx.core.dex.nodes.IRegion 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 5 with IRegion

use of jadx.core.dex.nodes.IRegion 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)

Aggregations

IRegion (jadx.core.dex.nodes.IRegion)26 IContainer (jadx.core.dex.nodes.IContainer)14 Region (jadx.core.dex.regions.Region)12 LoopRegion (jadx.core.dex.regions.loops.LoopRegion)11 BlockNode (jadx.core.dex.nodes.BlockNode)10 IBlock (jadx.core.dex.nodes.IBlock)10 IfRegion (jadx.core.dex.regions.conditions.IfRegion)8 IBranchRegion (jadx.core.dex.nodes.IBranchRegion)7 SwitchRegion (jadx.core.dex.regions.SwitchRegion)7 SynchronizedRegion (jadx.core.dex.regions.SynchronizedRegion)7 JadxRuntimeException (jadx.core.utils.exceptions.JadxRuntimeException)5 HashSet (java.util.HashSet)4 InsnNode (jadx.core.dex.nodes.InsnNode)3 MethodNode (jadx.core.dex.nodes.MethodNode)3 ArrayList (java.util.ArrayList)3 LinkedHashMap (java.util.LinkedHashMap)3 LoopInfo (jadx.core.dex.attributes.nodes.LoopInfo)2 Edge (jadx.core.dex.nodes.Edge)2 AbstractRegion (jadx.core.dex.regions.AbstractRegion)2 TryCatchRegion (jadx.core.dex.regions.TryCatchRegion)2