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;
}
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;
}
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);
}
}
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;
}
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);
}
Aggregations