Search in sources :

Example 6 with TryCatchBlockAttr

use of jadx.core.dex.trycatch.TryCatchBlockAttr in project jadx by skylot.

the class BlockExceptionHandler method process.

public static boolean process(MethodNode mth) {
    if (mth.isNoExceptionHandlers()) {
        return false;
    }
    BlockProcessor.updateCleanSuccessors(mth);
    BlockProcessor.computeDominanceFrontier(mth);
    processCatchAttr(mth);
    initExcHandlers(mth);
    List<TryCatchBlockAttr> tryBlocks = prepareTryBlocks(mth);
    connectExcHandlers(mth, tryBlocks);
    mth.addAttr(AType.TRY_BLOCKS_LIST, tryBlocks);
    mth.getBasicBlocks().forEach(BlockNode::updateCleanSuccessors);
    for (ExceptionHandler eh : mth.getExceptionHandlers()) {
        removeMonitorExitFromExcHandler(mth, eh);
    }
    BlockProcessor.removeMarkedBlocks(mth);
    return true;
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) ExceptionHandler(jadx.core.dex.trycatch.ExceptionHandler) TryCatchBlockAttr(jadx.core.dex.trycatch.TryCatchBlockAttr)

Example 7 with TryCatchBlockAttr

use of jadx.core.dex.trycatch.TryCatchBlockAttr in project jadx by skylot.

the class MarkFinallyVisitor method extractFinally.

/**
 * Search and mark common code from 'try' block and 'handlers'.
 */
private static boolean extractFinally(MethodNode mth, TryCatchBlockAttr tryBlock, ExceptionHandler allHandler) {
    BlockNode handlerBlock = allHandler.getHandlerBlock();
    List<BlockNode> handlerBlocks = new ArrayList<>(BlockUtils.collectBlocksDominatedByWithExcHandlers(mth, handlerBlock, handlerBlock));
    // exclude block with 'move-exception'
    handlerBlocks.remove(handlerBlock);
    handlerBlocks.removeIf(b -> BlockUtils.checkLastInsnType(b, InsnType.THROW));
    if (handlerBlocks.isEmpty() || BlockUtils.isAllBlocksEmpty(handlerBlocks)) {
        // remove empty catch
        allHandler.getTryBlock().removeHandler(allHandler);
        return true;
    }
    BlockNode startBlock = Utils.getOne(handlerBlock.getCleanSuccessors());
    FinallyExtractInfo extractInfo = new FinallyExtractInfo(allHandler, startBlock, handlerBlocks);
    boolean hasInnerBlocks = !tryBlock.getInnerTryBlocks().isEmpty();
    List<ExceptionHandler> handlers;
    if (hasInnerBlocks) {
        // collect handlers from this and all inner blocks (intentionally not using recursive collect for
        // now)
        handlers = new ArrayList<>(tryBlock.getHandlers());
        for (TryCatchBlockAttr innerTryBlock : tryBlock.getInnerTryBlocks()) {
            handlers.addAll(innerTryBlock.getHandlers());
        }
    } else {
        handlers = tryBlock.getHandlers();
    }
    if (handlers.isEmpty()) {
        return false;
    }
    // search 'finally' instructions in other handlers
    for (ExceptionHandler otherHandler : handlers) {
        if (otherHandler == allHandler) {
            continue;
        }
        for (BlockNode checkBlock : otherHandler.getBlocks()) {
            if (searchDuplicateInsns(checkBlock, extractInfo)) {
                break;
            } else {
                extractInfo.getFinallyInsnsSlice().resetIncomplete();
            }
        }
    }
    boolean mergeInnerTryBlocks;
    int duplicatesCount = extractInfo.getDuplicateSlices().size();
    boolean fullTryBlock = duplicatesCount == (handlers.size() - 1);
    if (fullTryBlock) {
        // all collected handlers have duplicate block
        mergeInnerTryBlocks = hasInnerBlocks;
    } else {
        // some handlers don't have duplicated blocks
        if (!hasInnerBlocks || duplicatesCount != (tryBlock.getHandlers().size() - 1)) {
            // unexpected count of duplicated slices
            return false;
        }
        mergeInnerTryBlocks = false;
    }
    // remove 'finally' from 'try' blocks, check all up paths on each exit (connected with finally exit)
    List<BlockNode> tryBlocks = allHandler.getTryBlock().getBlocks();
    BlockNode bottomBlock = BlockUtils.getBottomBlock(allHandler.getBlocks());
    if (bottomBlock == null) {
        return false;
    }
    BlockNode bottomFinallyBlock = BlockUtils.followEmptyPath(bottomBlock);
    BlockNode bottom = BlockUtils.getNextBlock(bottomFinallyBlock);
    if (bottom == null) {
        return false;
    }
    boolean found = false;
    List<BlockNode> pathBlocks = getPathStarts(mth, bottom, bottomFinallyBlock);
    for (BlockNode pred : pathBlocks) {
        List<BlockNode> upPath = BlockUtils.collectPredecessors(mth, pred, tryBlocks);
        if (upPath.size() < handlerBlocks.size()) {
            continue;
        }
        for (BlockNode block : upPath) {
            if (searchDuplicateInsns(block, extractInfo)) {
                found = true;
                break;
            } else {
                extractInfo.getFinallyInsnsSlice().resetIncomplete();
            }
        }
    }
    if (!found) {
        return false;
    }
    if (!checkSlices(extractInfo)) {
        mth.addWarnComment("Finally extract failed");
        return false;
    }
    // 'finally' extract confirmed, apply
    apply(extractInfo);
    allHandler.setFinally(true);
    if (mergeInnerTryBlocks) {
        List<TryCatchBlockAttr> innerTryBlocks = tryBlock.getInnerTryBlocks();
        for (TryCatchBlockAttr innerTryBlock : innerTryBlocks) {
            tryBlock.getHandlers().addAll(innerTryBlock.getHandlers());
            tryBlock.getBlocks().addAll(innerTryBlock.getBlocks());
            innerTryBlock.setMerged(true);
        }
        tryBlock.setBlocks(ListUtils.distinctList(tryBlock.getBlocks()));
        innerTryBlocks.clear();
    }
    return true;
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) ExceptionHandler(jadx.core.dex.trycatch.ExceptionHandler) TryCatchBlockAttr(jadx.core.dex.trycatch.TryCatchBlockAttr) ArrayList(java.util.ArrayList)

Example 8 with TryCatchBlockAttr

use of jadx.core.dex.trycatch.TryCatchBlockAttr in project jadx by skylot.

the class MarkFinallyVisitor method visit.

@Override
public void visit(MethodNode mth) {
    if (mth.isNoCode() || mth.isNoExceptionHandlers()) {
        return;
    }
    try {
        boolean applied = false;
        List<TryCatchBlockAttr> tryBlocks = mth.getAll(AType.TRY_BLOCKS_LIST);
        for (TryCatchBlockAttr tryBlock : tryBlocks) {
            applied |= processTryBlock(mth, tryBlock);
        }
        if (applied) {
            mth.clearExceptionHandlers();
            // remove merged or empty try blocks from list in method attribute
            List<TryCatchBlockAttr> clearedTryBlocks = new ArrayList<>(tryBlocks);
            if (clearedTryBlocks.removeIf(tb -> tb.isMerged() || tb.getHandlers().isEmpty())) {
                mth.remove(AType.TRY_BLOCKS_LIST);
                mth.addAttr(AType.TRY_BLOCKS_LIST, clearedTryBlocks);
            }
        }
    } catch (Exception e) {
        LOG.warn("Undo finally extract visitor, mth: {}", mth, e);
        undoFinallyVisitor(mth);
    }
}
Also used : TryCatchBlockAttr(jadx.core.dex.trycatch.TryCatchBlockAttr) ArrayList(java.util.ArrayList)

Example 9 with TryCatchBlockAttr

use of jadx.core.dex.trycatch.TryCatchBlockAttr in project jadx by skylot.

the class RegionMaker method processHandlersOutBlocks.

/**
 * Search handlers successor blocks not included in any region.
 */
protected IRegion processHandlersOutBlocks(MethodNode mth, List<TryCatchBlockAttr> tcs) {
    Set<IBlock> allRegionBlocks = new HashSet<>();
    RegionUtils.getAllRegionBlocks(mth.getRegion(), allRegionBlocks);
    Set<IBlock> succBlocks = new HashSet<>();
    for (TryCatchBlockAttr 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) TryCatchBlockAttr(jadx.core.dex.trycatch.TryCatchBlockAttr) 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) IContainer(jadx.core.dex.nodes.IContainer) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Example 10 with TryCatchBlockAttr

use of jadx.core.dex.trycatch.TryCatchBlockAttr in project jadx by skylot.

the class RegionMaker method processTryCatchBlocks.

public IRegion processTryCatchBlocks(MethodNode mth) {
    List<TryCatchBlockAttr> tcs = mth.getAll(AType.TRY_BLOCKS_LIST);
    for (TryCatchBlockAttr tc : tcs) {
        List<BlockNode> blocks = new ArrayList<>(tc.getHandlersCount());
        Set<BlockNode> splitters = new HashSet<>();
        for (ExceptionHandler handler : tc.getHandlers()) {
            BlockNode handlerBlock = handler.getHandlerBlock();
            if (handlerBlock != null) {
                blocks.add(handlerBlock);
                splitters.add(BlockUtils.getTopSplitterForHandler(handlerBlock));
            } else {
                mth.addDebugComment("No exception handler block: " + handler);
            }
        }
        Set<BlockNode> exits = new HashSet<>();
        for (BlockNode splitter : splitters) {
            for (BlockNode handler : blocks) {
                if (handler.contains(AFlag.REMOVE)) {
                    continue;
                }
                List<BlockNode> s = splitter.getSuccessors();
                if (s.isEmpty()) {
                    mth.addDebugComment("No successors for splitter: " + splitter);
                    continue;
                }
                BlockNode ss = s.get(0);
                BlockNode cross = BlockUtils.getPathCross(mth, ss, handler);
                if (cross != null && cross != ss && cross != handler) {
                    exits.add(cross);
                }
            }
        }
        for (ExceptionHandler handler : tc.getHandlers()) {
            processExcHandler(mth, handler, exits);
        }
    }
    return processHandlersOutBlocks(mth, tcs);
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) ExceptionHandler(jadx.core.dex.trycatch.ExceptionHandler) TryCatchBlockAttr(jadx.core.dex.trycatch.TryCatchBlockAttr) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Aggregations

TryCatchBlockAttr (jadx.core.dex.trycatch.TryCatchBlockAttr)12 ExceptionHandler (jadx.core.dex.trycatch.ExceptionHandler)9 BlockNode (jadx.core.dex.nodes.BlockNode)8 ArrayList (java.util.ArrayList)6 JadxRuntimeException (jadx.core.utils.exceptions.JadxRuntimeException)5 ArgType (jadx.core.dex.instructions.args.ArgType)4 TypeCompare (jadx.core.dex.visitors.typeinference.TypeCompare)4 ArrayDeque (java.util.ArrayDeque)4 Utils (jadx.api.plugins.utils.Utils)3 Consts (jadx.core.Consts)3 AFlag (jadx.core.dex.attributes.AFlag)3 AType (jadx.core.dex.attributes.AType)3 TmpEdgeAttr (jadx.core.dex.attributes.nodes.TmpEdgeAttr)3 ClassInfo (jadx.core.dex.info.ClassInfo)3 InsnType (jadx.core.dex.instructions.InsnType)3 InsnArg (jadx.core.dex.instructions.args.InsnArg)3 NamedArg (jadx.core.dex.instructions.args.NamedArg)3 RegisterArg (jadx.core.dex.instructions.args.RegisterArg)3 InsnNode (jadx.core.dex.nodes.InsnNode)3 MethodNode (jadx.core.dex.nodes.MethodNode)3