use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.
the class BlockExceptionHandler method removeMonitorExitFromExcHandler.
private static void removeMonitorExitFromExcHandler(MethodNode mth, ExceptionHandler excHandler) {
for (BlockNode excBlock : excHandler.getBlocks()) {
InsnRemover remover = new InsnRemover(mth, excBlock);
for (InsnNode insn : excBlock.getInstructions()) {
if (insn.getType() == InsnType.MONITOR_ENTER) {
break;
}
if (insn.getType() == InsnType.MONITOR_EXIT) {
remover.addAndUnbind(insn);
}
}
remover.perform();
}
}
use of jadx.core.dex.nodes.BlockNode 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;
}
use of jadx.core.dex.nodes.BlockNode 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;
}
use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.
the class BlockExceptionHandler method initExcHandlers.
@SuppressWarnings("ForLoopReplaceableByForEach")
private static void initExcHandlers(MethodNode mth) {
List<BlockNode> blocks = mth.getBasicBlocks();
int blocksCount = blocks.size();
for (int i = 0; i < blocksCount; i++) {
// will add new blocks to list end
BlockNode block = blocks.get(i);
InsnNode firstInsn = BlockUtils.getFirstInsn(block);
if (firstInsn == null) {
continue;
}
ExcHandlerAttr excHandlerAttr = firstInsn.get(AType.EXC_HANDLER);
if (excHandlerAttr == null) {
continue;
}
firstInsn.remove(AType.EXC_HANDLER);
TmpEdgeAttr tmpEdgeAttr = block.get(AType.TMP_EDGE);
if (tmpEdgeAttr != null) {
// remove temp connection
BlockSplitter.removeConnection(tmpEdgeAttr.getBlock(), block);
block.remove(AType.TMP_EDGE);
}
ExceptionHandler excHandler = excHandlerAttr.getHandler();
if (block.getPredecessors().isEmpty()) {
excHandler.setHandlerBlock(block);
block.addAttr(excHandlerAttr);
excHandler.addBlock(block);
BlockUtils.collectBlocksDominatedByWithExcHandlers(mth, block, block).forEach(excHandler::addBlock);
} else {
// ignore already connected handlers -> make catch empty
BlockNode emptyHandlerBlock = BlockSplitter.startNewBlock(mth, block.getStartOffset());
emptyHandlerBlock.add(AFlag.SYNTHETIC);
emptyHandlerBlock.addAttr(excHandlerAttr);
BlockSplitter.connect(emptyHandlerBlock, block);
excHandler.setHandlerBlock(emptyHandlerBlock);
excHandler.addBlock(emptyHandlerBlock);
}
fixMoveExceptionInsn(block, excHandlerAttr);
}
}
use of jadx.core.dex.nodes.BlockNode 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;
}
Aggregations