Search in sources :

Example 1 with TryCatchBlockAttr

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

the class BlockExceptionHandler method connectExcHandlers.

/**
 * Wrap try blocks with top/bottom splitter and connect them to handler block.
 * Sometimes try block can be handler block itself and should be connected before wrapping.
 * Use queue for postpone try blocks not ready for wrap.
 */
private static void connectExcHandlers(MethodNode mth, List<TryCatchBlockAttr> tryBlocks) {
    if (tryBlocks.isEmpty()) {
        return;
    }
    int limit = tryBlocks.size() * 3;
    int count = 0;
    Deque<TryCatchBlockAttr> queue = new ArrayDeque<>(tryBlocks);
    while (!queue.isEmpty()) {
        TryCatchBlockAttr tryBlock = queue.removeFirst();
        boolean complete = wrapBlocksWithTryCatch(mth, tryBlock);
        if (!complete) {
            // return to queue at the end
            queue.addLast(tryBlock);
        }
        if (count++ > limit) {
            throw new JadxRuntimeException("Try blocks wrapping queue limit reached! Please report as an issue!");
        }
    }
}
Also used : TryCatchBlockAttr(jadx.core.dex.trycatch.TryCatchBlockAttr) JadxRuntimeException(jadx.core.utils.exceptions.JadxRuntimeException) ArrayDeque(java.util.ArrayDeque)

Example 2 with TryCatchBlockAttr

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

the class BlockExceptionHandler method checkTryCatchRelation.

private static boolean checkTryCatchRelation(List<TryCatchBlockAttr> tryBlocks, TryCatchBlockAttr outerTryBlock, TryCatchBlockAttr innerTryBlock) {
    if (outerTryBlock.getBlocks().equals(innerTryBlock.getBlocks())) {
        // same try blocks -> merge handlers
        List<ExceptionHandler> handlers = Utils.concatDistinct(outerTryBlock.getHandlers(), innerTryBlock.getHandlers());
        tryBlocks.add(new TryCatchBlockAttr(tryBlocks.size(), handlers, outerTryBlock.getBlocks()));
        tryBlocks.remove(outerTryBlock);
        tryBlocks.remove(innerTryBlock);
        return true;
    }
    Set<BlockNode> handlerBlocks = innerTryBlock.getHandlers().stream().flatMap(eh -> eh.getBlocks().stream()).collect(Collectors.toSet());
    boolean catchInHandler = handlerBlocks.stream().anyMatch(isHandlersIntersects(outerTryBlock));
    boolean catchInTry = innerTryBlock.getBlocks().stream().anyMatch(isHandlersIntersects(outerTryBlock));
    boolean blocksOutsideHandler = outerTryBlock.getBlocks().stream().anyMatch(b -> !handlerBlocks.contains(b));
    boolean makeInner = catchInHandler && (catchInTry || blocksOutsideHandler);
    if (makeInner && innerTryBlock.isAllHandler()) {
        // inner try block can't have catch-all handler
        outerTryBlock.setBlocks(Utils.concatDistinct(outerTryBlock.getBlocks(), innerTryBlock.getBlocks()));
        innerTryBlock.clear();
        return false;
    }
    if (makeInner) {
        // convert to inner
        List<BlockNode> mergedBlocks = Utils.concatDistinct(outerTryBlock.getBlocks(), innerTryBlock.getBlocks());
        innerTryBlock.getHandlers().removeAll(outerTryBlock.getHandlers());
        innerTryBlock.setOuterTryBlock(outerTryBlock);
        outerTryBlock.addInnerTryBlock(innerTryBlock);
        outerTryBlock.setBlocks(mergedBlocks);
        return false;
    }
    if (innerTryBlock.getHandlers().containsAll(outerTryBlock.getHandlers())) {
        // merge
        List<BlockNode> mergedBlocks = Utils.concatDistinct(outerTryBlock.getBlocks(), innerTryBlock.getBlocks());
        List<ExceptionHandler> handlers = Utils.concatDistinct(outerTryBlock.getHandlers(), innerTryBlock.getHandlers());
        tryBlocks.add(new TryCatchBlockAttr(tryBlocks.size(), handlers, mergedBlocks));
        tryBlocks.remove(outerTryBlock);
        tryBlocks.remove(innerTryBlock);
        return true;
    }
    return false;
}
Also used : ExceptionHandler(jadx.core.dex.trycatch.ExceptionHandler) BlockNode(jadx.core.dex.nodes.BlockNode) ArgType(jadx.core.dex.instructions.args.ArgType) MethodNode(jadx.core.dex.nodes.MethodNode) Consts(jadx.core.Consts) AType(jadx.core.dex.attributes.AType) AFlag(jadx.core.dex.attributes.AFlag) TmpEdgeAttr(jadx.core.dex.attributes.nodes.TmpEdgeAttr) LoggerFactory(org.slf4j.LoggerFactory) InsnType(jadx.core.dex.instructions.InsnType) CatchAttr(jadx.core.dex.trycatch.CatchAttr) HashMap(java.util.HashMap) ClassInfo(jadx.core.dex.info.ClassInfo) Deque(java.util.Deque) BlockUtils(jadx.core.utils.BlockUtils) NamedArg(jadx.core.dex.instructions.args.NamedArg) ArrayList(java.util.ArrayList) ExcHandlerAttr(jadx.core.dex.trycatch.ExcHandlerAttr) Utils(jadx.api.plugins.utils.Utils) ListUtils(jadx.core.utils.ListUtils) Map(java.util.Map) InsnNode(jadx.core.dex.nodes.InsnNode) TryCatchBlockAttr(jadx.core.dex.trycatch.TryCatchBlockAttr) InsnArg(jadx.core.dex.instructions.args.InsnArg) RegisterArg(jadx.core.dex.instructions.args.RegisterArg) Logger(org.slf4j.Logger) Predicate(java.util.function.Predicate) Set(java.util.Set) JadxRuntimeException(jadx.core.utils.exceptions.JadxRuntimeException) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) Nullable(org.jetbrains.annotations.Nullable) List(java.util.List) BlockNode(jadx.core.dex.nodes.BlockNode) ExceptionHandler(jadx.core.dex.trycatch.ExceptionHandler) TypeCompare(jadx.core.dex.visitors.typeinference.TypeCompare) ArrayDeque(java.util.ArrayDeque) Comparator(java.util.Comparator) NotNull(org.jetbrains.annotations.NotNull) InsnRemover(jadx.core.utils.InsnRemover) Collections(java.util.Collections) TryCatchBlockAttr(jadx.core.dex.trycatch.TryCatchBlockAttr)

Example 3 with TryCatchBlockAttr

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

the class BlockExceptionHandler method prepareTryBlocks.

private static List<TryCatchBlockAttr> prepareTryBlocks(MethodNode mth) {
    Map<ExceptionHandler, List<BlockNode>> blocksByHandler = new HashMap<>();
    for (BlockNode block : mth.getBasicBlocks()) {
        CatchAttr catchAttr = block.get(AType.EXC_CATCH);
        if (catchAttr != null) {
            for (ExceptionHandler eh : catchAttr.getHandlers()) {
                blocksByHandler.computeIfAbsent(eh, c -> new ArrayList<>()).add(block);
            }
        }
    }
    if (Consts.DEBUG_EXC_HANDLERS) {
        LOG.debug("Input exception handlers:");
        blocksByHandler.forEach((eh, blocks) -> LOG.debug(" {}, throw blocks: {}, handler blocks: {}", eh, blocks, eh.getBlocks()));
    }
    if (blocksByHandler.isEmpty()) {
        // no catch blocks -> remove all handlers
        mth.getExceptionHandlers().forEach(eh -> removeExcHandler(mth, eh));
    } else {
        // remove handlers without blocks in catch attribute
        blocksByHandler.forEach((eh, blocks) -> {
            if (blocks.isEmpty()) {
                removeExcHandler(mth, eh);
            }
        });
    }
    BlockSplitter.detachMarkedBlocks(mth);
    mth.clearExceptionHandlers();
    if (mth.isNoExceptionHandlers()) {
        return Collections.emptyList();
    }
    blocksByHandler.forEach((eh, blocks) -> {
        // remove catches from same handler
        blocks.removeAll(eh.getBlocks());
    });
    List<TryCatchBlockAttr> tryBlocks = new ArrayList<>();
    blocksByHandler.forEach((eh, blocks) -> {
        List<ExceptionHandler> handlers = new ArrayList<>(1);
        handlers.add(eh);
        tryBlocks.add(new TryCatchBlockAttr(tryBlocks.size(), handlers, blocks));
    });
    if (tryBlocks.size() > 1) {
        // merge or mark as outer/inner
        while (true) {
            boolean restart = combineTryCatchBlocks(tryBlocks);
            if (!restart) {
                break;
            }
        }
    }
    checkForMultiCatch(mth, tryBlocks);
    clearTryBlocks(mth, tryBlocks);
    sortHandlers(mth, tryBlocks);
    if (Consts.DEBUG_EXC_HANDLERS) {
        LOG.debug("Result try-catch blocks:");
        tryBlocks.forEach(tryBlock -> LOG.debug(" {}", tryBlock));
    }
    return tryBlocks;
}
Also used : ExceptionHandler(jadx.core.dex.trycatch.ExceptionHandler) BlockNode(jadx.core.dex.nodes.BlockNode) ArgType(jadx.core.dex.instructions.args.ArgType) MethodNode(jadx.core.dex.nodes.MethodNode) Consts(jadx.core.Consts) AType(jadx.core.dex.attributes.AType) AFlag(jadx.core.dex.attributes.AFlag) TmpEdgeAttr(jadx.core.dex.attributes.nodes.TmpEdgeAttr) LoggerFactory(org.slf4j.LoggerFactory) InsnType(jadx.core.dex.instructions.InsnType) CatchAttr(jadx.core.dex.trycatch.CatchAttr) HashMap(java.util.HashMap) ClassInfo(jadx.core.dex.info.ClassInfo) Deque(java.util.Deque) BlockUtils(jadx.core.utils.BlockUtils) NamedArg(jadx.core.dex.instructions.args.NamedArg) ArrayList(java.util.ArrayList) ExcHandlerAttr(jadx.core.dex.trycatch.ExcHandlerAttr) Utils(jadx.api.plugins.utils.Utils) ListUtils(jadx.core.utils.ListUtils) Map(java.util.Map) InsnNode(jadx.core.dex.nodes.InsnNode) TryCatchBlockAttr(jadx.core.dex.trycatch.TryCatchBlockAttr) InsnArg(jadx.core.dex.instructions.args.InsnArg) RegisterArg(jadx.core.dex.instructions.args.RegisterArg) Logger(org.slf4j.Logger) Predicate(java.util.function.Predicate) Set(java.util.Set) JadxRuntimeException(jadx.core.utils.exceptions.JadxRuntimeException) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) Nullable(org.jetbrains.annotations.Nullable) List(java.util.List) BlockNode(jadx.core.dex.nodes.BlockNode) ExceptionHandler(jadx.core.dex.trycatch.ExceptionHandler) TypeCompare(jadx.core.dex.visitors.typeinference.TypeCompare) ArrayDeque(java.util.ArrayDeque) Comparator(java.util.Comparator) NotNull(org.jetbrains.annotations.NotNull) InsnRemover(jadx.core.utils.InsnRemover) Collections(java.util.Collections) HashMap(java.util.HashMap) TryCatchBlockAttr(jadx.core.dex.trycatch.TryCatchBlockAttr) ArrayList(java.util.ArrayList) ArrayList(java.util.ArrayList) List(java.util.List) CatchAttr(jadx.core.dex.trycatch.CatchAttr)

Example 4 with TryCatchBlockAttr

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

the class BlockExceptionHandler method checkForMultiCatch.

private static void checkForMultiCatch(MethodNode mth, List<TryCatchBlockAttr> tryBlocks) {
    boolean merged = false;
    for (TryCatchBlockAttr tryBlock : tryBlocks) {
        if (mergeMultiCatch(mth, tryBlock)) {
            merged = true;
        }
    }
    if (merged) {
        BlockSplitter.detachMarkedBlocks(mth);
        mth.clearExceptionHandlers();
    }
}
Also used : TryCatchBlockAttr(jadx.core.dex.trycatch.TryCatchBlockAttr)

Example 5 with TryCatchBlockAttr

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

the class BlockExceptionHandler method wrapBlocksWithTryCatch.

private static boolean wrapBlocksWithTryCatch(MethodNode mth, TryCatchBlockAttr tryCatchBlock) {
    List<BlockNode> blocks = tryCatchBlock.getBlocks();
    BlockNode top = searchTopBlock(mth, blocks);
    if (top.getPredecessors().isEmpty() && top != mth.getEnterBlock()) {
        return false;
    }
    BlockNode bottom = searchBottomBlock(mth, blocks);
    if (Consts.DEBUG_EXC_HANDLERS) {
        LOG.debug("TryCatch #{} split: top {}, bottom: {}", tryCatchBlock.id(), top, bottom);
    }
    BlockNode topSplitterBlock = getTopSplitterBlock(mth, top);
    topSplitterBlock.add(AFlag.EXC_TOP_SPLITTER);
    topSplitterBlock.add(AFlag.SYNTHETIC);
    int totalHandlerBlocks = tryCatchBlock.getHandlers().stream().mapToInt(eh -> eh.getBlocks().size()).sum();
    BlockNode bottomSplitterBlock;
    if (bottom == null || totalHandlerBlocks == 0) {
        bottomSplitterBlock = null;
    } else {
        BlockNode existBottomSplitter = BlockUtils.getBlockWithFlag(bottom.getSuccessors(), AFlag.EXC_BOTTOM_SPLITTER);
        bottomSplitterBlock = existBottomSplitter != null ? existBottomSplitter : BlockSplitter.startNewBlock(mth, -1);
        bottomSplitterBlock.add(AFlag.EXC_BOTTOM_SPLITTER);
        bottomSplitterBlock.add(AFlag.SYNTHETIC);
        BlockSplitter.connect(bottom, bottomSplitterBlock);
    }
    if (Consts.DEBUG_EXC_HANDLERS) {
        LOG.debug("TryCatch #{} result splitters: top {}, bottom: {}", tryCatchBlock.id(), topSplitterBlock, bottomSplitterBlock);
    }
    connectSplittersAndHandlers(tryCatchBlock, topSplitterBlock, bottomSplitterBlock);
    for (BlockNode block : blocks) {
        TryCatchBlockAttr currentTCBAttr = block.get(AType.TRY_BLOCK);
        if (currentTCBAttr == null || currentTCBAttr.getInnerTryBlocks().contains(tryCatchBlock)) {
            block.addAttr(tryCatchBlock);
        }
    }
    tryCatchBlock.setTopSplitter(topSplitterBlock);
    topSplitterBlock.updateCleanSuccessors();
    if (bottomSplitterBlock != null) {
        bottomSplitterBlock.updateCleanSuccessors();
    }
    return true;
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) ArgType(jadx.core.dex.instructions.args.ArgType) MethodNode(jadx.core.dex.nodes.MethodNode) Consts(jadx.core.Consts) AType(jadx.core.dex.attributes.AType) AFlag(jadx.core.dex.attributes.AFlag) TmpEdgeAttr(jadx.core.dex.attributes.nodes.TmpEdgeAttr) LoggerFactory(org.slf4j.LoggerFactory) InsnType(jadx.core.dex.instructions.InsnType) CatchAttr(jadx.core.dex.trycatch.CatchAttr) HashMap(java.util.HashMap) ClassInfo(jadx.core.dex.info.ClassInfo) Deque(java.util.Deque) BlockUtils(jadx.core.utils.BlockUtils) NamedArg(jadx.core.dex.instructions.args.NamedArg) ArrayList(java.util.ArrayList) ExcHandlerAttr(jadx.core.dex.trycatch.ExcHandlerAttr) Utils(jadx.api.plugins.utils.Utils) ListUtils(jadx.core.utils.ListUtils) Map(java.util.Map) InsnNode(jadx.core.dex.nodes.InsnNode) TryCatchBlockAttr(jadx.core.dex.trycatch.TryCatchBlockAttr) InsnArg(jadx.core.dex.instructions.args.InsnArg) RegisterArg(jadx.core.dex.instructions.args.RegisterArg) Logger(org.slf4j.Logger) Predicate(java.util.function.Predicate) Set(java.util.Set) JadxRuntimeException(jadx.core.utils.exceptions.JadxRuntimeException) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) Nullable(org.jetbrains.annotations.Nullable) List(java.util.List) BlockNode(jadx.core.dex.nodes.BlockNode) ExceptionHandler(jadx.core.dex.trycatch.ExceptionHandler) TypeCompare(jadx.core.dex.visitors.typeinference.TypeCompare) ArrayDeque(java.util.ArrayDeque) Comparator(java.util.Comparator) NotNull(org.jetbrains.annotations.NotNull) InsnRemover(jadx.core.utils.InsnRemover) Collections(java.util.Collections) TryCatchBlockAttr(jadx.core.dex.trycatch.TryCatchBlockAttr)

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