use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.
the class MarkFinallyVisitor method checkBlocksTree.
private static boolean checkBlocksTree(BlockNode dupBlock, BlockNode finallyBlock, InsnsSlice dupSlice, FinallyExtractInfo extractInfo) {
InsnsSlice finallySlice = extractInfo.getFinallyInsnsSlice();
List<BlockNode> finallyCS = getSuccessorsWithoutLoop(finallyBlock);
List<BlockNode> dupCS = getSuccessorsWithoutLoop(dupBlock);
if (finallyCS.size() == dupCS.size()) {
for (int i = 0; i < finallyCS.size(); i++) {
BlockNode finSBlock = finallyCS.get(i);
BlockNode dupSBlock = dupCS.get(i);
if (extractInfo.getAllHandlerBlocks().contains(finSBlock)) {
if (!compareBlocks(dupSBlock, finSBlock, dupSlice, extractInfo)) {
return false;
}
if (!checkBlocksTree(dupSBlock, finSBlock, dupSlice, extractInfo)) {
return false;
}
dupSlice.addBlock(dupSBlock);
finallySlice.addBlock(finSBlock);
}
}
}
dupSlice.setComplete(true);
finallySlice.setComplete(true);
return true;
}
use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.
the class ModVisitor method iterativeRemoveStep.
private static void iterativeRemoveStep(MethodNode mth) {
boolean changed;
do {
changed = false;
for (BlockNode block : mth.getBasicBlocks()) {
for (InsnNode insn : block.getInstructions()) {
if (insn.getType() == InsnType.MOVE && insn.isAttrStorageEmpty() && isResultArgNotUsed(insn)) {
InsnRemover.remove(mth, block, insn);
changed = true;
break;
}
}
}
} while (changed);
}
use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.
the class ModVisitor method removeStep.
/**
* Remove unnecessary instructions
*/
private static void removeStep(MethodNode mth, InsnRemover remover) {
for (BlockNode block : mth.getBasicBlocks()) {
remover.setBlock(block);
for (InsnNode insn : block.getInstructions()) {
switch(insn.getType()) {
case NOP:
case GOTO:
case NEW_INSTANCE:
remover.addAndUnbind(insn);
break;
default:
if (insn.contains(AFlag.REMOVE)) {
remover.addAndUnbind(insn);
}
break;
}
}
remover.perform();
}
}
use of jadx.core.dex.nodes.BlockNode 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.nodes.BlockNode in project jadx by skylot.
the class CheckRegions method visit.
@Override
public void visit(MethodNode mth) throws JadxException {
if (mth.isNoCode() || mth.getRegion() == null || mth.getBasicBlocks().isEmpty() || mth.contains(AType.JADX_ERROR)) {
return;
}
// check if all blocks included in regions
Set<BlockNode> blocksInRegions = new HashSet<>();
DepthRegionTraversal.traverse(mth, new AbstractRegionVisitor() {
@Override
public void processBlock(MethodNode mth, IBlock container) {
if (!(container instanceof BlockNode)) {
return;
}
BlockNode block = (BlockNode) container;
if (blocksInRegions.add(block)) {
return;
}
if (LOG.isDebugEnabled() && !block.contains(AFlag.RETURN) && !block.contains(AFlag.REMOVE) && !block.contains(AFlag.SYNTHETIC) && !block.getInstructions().isEmpty()) {
LOG.debug("Duplicated block: {} - {}", mth, block);
}
}
});
if (mth.getBasicBlocks().size() != blocksInRegions.size()) {
for (BlockNode block : mth.getBasicBlocks()) {
if (!blocksInRegions.contains(block) && !block.getInstructions().isEmpty() && !block.contains(AFlag.ADDED_TO_REGION) && !block.contains(AFlag.DONT_GENERATE) && !block.contains(AFlag.REMOVE)) {
String blockCode = getBlockInsnStr(mth, block).replace("*/", "*\\/");
mth.addWarn("Code restructure failed: missing block: " + block + ", code lost:" + blockCode);
}
}
}
DepthRegionTraversal.traverse(mth, new AbstractRegionVisitor() {
@Override
public boolean enterRegion(MethodNode mth, IRegion region) {
if (region instanceof LoopRegion) {
// check loop conditions
BlockNode loopHeader = ((LoopRegion) region).getHeader();
if (loopHeader != null && loopHeader.getInstructions().size() != 1) {
mth.addWarn("Incorrect condition in loop: " + loopHeader);
}
}
return true;
}
});
}
Aggregations