use of jadx.core.dex.regions.loops.LoopRegion in project jadx by skylot.
the class ProcessTryCatchRegions method wrapBlocks.
/**
* Extract all block dominated by 'dominator' to separate region and mark as try/catch block
*/
private static boolean wrapBlocks(IRegion replaceRegion, TryCatchBlock tb, BlockNode dominator) {
if (replaceRegion == null) {
return false;
}
if (replaceRegion instanceof LoopRegion) {
LoopRegion loop = (LoopRegion) replaceRegion;
return wrapBlocks(loop.getBody(), tb, dominator);
}
if (replaceRegion instanceof IBranchRegion) {
return wrapBlocks(replaceRegion.getParent(), tb, dominator);
}
Region tryRegion = new Region(replaceRegion);
List<IContainer> subBlocks = replaceRegion.getSubBlocks();
for (IContainer cont : subBlocks) {
if (RegionUtils.hasPathThroughBlock(dominator, cont)) {
if (isHandlerPath(tb, cont)) {
break;
}
tryRegion.getSubBlocks().add(cont);
}
}
if (tryRegion.getSubBlocks().isEmpty()) {
return false;
}
TryCatchRegion tryCatchRegion = new TryCatchRegion(replaceRegion, tryRegion);
tryRegion.setParent(tryCatchRegion);
tryCatchRegion.setTryCatchBlock(tb.getCatchAttr().getTryBlock());
// replace first node by region
IContainer firstNode = tryRegion.getSubBlocks().get(0);
if (!replaceRegion.replaceSubBlock(firstNode, tryCatchRegion)) {
return false;
}
subBlocks.removeAll(tryRegion.getSubBlocks());
// fix parents for tryRegion sub blocks
for (IContainer cont : tryRegion.getSubBlocks()) {
if (cont instanceof AbstractRegion) {
AbstractRegion aReg = (AbstractRegion) cont;
aReg.setParent(tryRegion);
}
}
return true;
}
use of jadx.core.dex.regions.loops.LoopRegion in project jadx by skylot.
the class RegionMaker method makeEndlessLoop.
private BlockNode makeEndlessLoop(IRegion curRegion, RegionStack stack, LoopInfo loop, BlockNode loopStart) {
LoopRegion loopRegion = new LoopRegion(curRegion, loop, null, false);
curRegion.getSubBlocks().add(loopRegion);
loopStart.remove(AType.LOOP);
stack.push(loopRegion);
BlockNode loopExit = null;
// insert 'break' for exits
List<Edge> exitEdges = loop.getExitEdges();
for (Edge exitEdge : exitEdges) {
BlockNode exit = exitEdge.getTarget();
if (insertBreak(stack, exit, exitEdge)) {
BlockNode nextBlock = getNextBlock(exit);
if (nextBlock != null) {
stack.addExit(nextBlock);
loopExit = nextBlock;
}
}
}
Region body = makeRegion(loopStart, stack);
BlockNode loopEnd = loop.getEnd();
if (!RegionUtils.isRegionContainsBlock(body, loopEnd) && !loopEnd.contains(AType.EXC_HANDLER) && !inExceptionHandlerBlocks(loopEnd)) {
body.getSubBlocks().add(loopEnd);
}
loopRegion.setBody(body);
if (loopExit == null) {
BlockNode next = getNextBlock(loopEnd);
loopExit = RegionUtils.isRegionContainsBlock(body, next) ? null : next;
}
stack.pop();
loopStart.addAttr(AType.LOOP, loop);
return loopExit;
}
use of jadx.core.dex.regions.loops.LoopRegion in project jadx by skylot.
the class RegionMaker method processLoop.
private BlockNode processLoop(IRegion curRegion, LoopInfo loop, RegionStack stack) {
BlockNode loopStart = loop.getStart();
Set<BlockNode> exitBlocksSet = loop.getExitNodes();
// set exit blocks scan order priority
// this can help if loop have several exits (after using 'break' or 'return' in loop)
List<BlockNode> exitBlocks = new ArrayList<BlockNode>(exitBlocksSet.size());
BlockNode nextStart = getNextBlock(loopStart);
if (nextStart != null && exitBlocksSet.remove(nextStart)) {
exitBlocks.add(nextStart);
}
if (exitBlocksSet.remove(loopStart)) {
exitBlocks.add(loopStart);
}
if (exitBlocksSet.remove(loop.getEnd())) {
exitBlocks.add(loop.getEnd());
}
exitBlocks.addAll(exitBlocksSet);
LoopRegion loopRegion = makeLoopRegion(curRegion, loop, exitBlocks);
if (loopRegion == null) {
BlockNode exit = makeEndlessLoop(curRegion, stack, loop, loopStart);
insertContinue(loop);
return exit;
}
curRegion.getSubBlocks().add(loopRegion);
IRegion outerRegion = stack.peekRegion();
stack.push(loopRegion);
IfInfo condInfo = makeIfInfo(loopRegion.getHeader());
condInfo = searchNestedIf(condInfo);
confirmMerge(condInfo);
if (!loop.getLoopBlocks().contains(condInfo.getThenBlock())) {
// invert loop condition if 'then' points to exit
condInfo = IfInfo.invert(condInfo);
}
loopRegion.setCondition(condInfo.getCondition());
exitBlocks.removeAll(condInfo.getMergedBlocks());
if (!exitBlocks.isEmpty()) {
BlockNode loopExit = condInfo.getElseBlock();
if (loopExit != null) {
// add 'break' instruction before path cross between main loop exit and sub-exit
for (Edge exitEdge : loop.getExitEdges()) {
if (!exitBlocks.contains(exitEdge.getSource())) {
continue;
}
insertBreak(stack, loopExit, exitEdge);
}
}
}
BlockNode out;
if (loopRegion.isConditionAtEnd()) {
BlockNode thenBlock = condInfo.getThenBlock();
out = thenBlock == loopStart ? condInfo.getElseBlock() : thenBlock;
loopStart.remove(AType.LOOP);
loop.getEnd().add(AFlag.SKIP);
stack.addExit(loop.getEnd());
loopRegion.setBody(makeRegion(loopStart, stack));
loopStart.addAttr(AType.LOOP, loop);
loop.getEnd().remove(AFlag.SKIP);
} else {
out = condInfo.getElseBlock();
if (outerRegion != null && out.contains(AFlag.LOOP_START) && !out.getAll(AType.LOOP).contains(loop) && RegionUtils.isRegionContainsBlock(outerRegion, out)) {
// exit to already processed outer loop
out = null;
}
stack.addExit(out);
BlockNode loopBody = condInfo.getThenBlock();
Region body = makeRegion(loopBody, stack);
// add blocks from loop start to first condition block
BlockNode conditionBlock = condInfo.getIfBlock();
if (loopStart != conditionBlock) {
Set<BlockNode> blocks = BlockUtils.getAllPathsBlocks(loopStart, conditionBlock);
blocks.remove(conditionBlock);
for (BlockNode block : blocks) {
if (block.getInstructions().isEmpty() && !block.contains(AFlag.SKIP) && !RegionUtils.isRegionContainsBlock(body, block)) {
body.add(block);
}
}
}
loopRegion.setBody(body);
}
stack.pop();
insertContinue(loop);
return out;
}
use of jadx.core.dex.regions.loops.LoopRegion in project jadx by skylot.
the class CheckRegions method visit.
@Override
public void visit(MethodNode mth) throws JadxException {
if (mth.isNoCode() || mth.getBasicBlocks().isEmpty() || mth.contains(AType.JADX_ERROR)) {
return;
}
// check if all blocks included in regions
final Set<BlockNode> blocksInRegions = new HashSet<BlockNode>();
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 (!block.contains(AFlag.RETURN) && !block.contains(AFlag.SKIP) && !block.contains(AFlag.SYNTHETIC) && !block.getInstructions().isEmpty()) {
// TODO
// mth.add(AFlag.INCONSISTENT_CODE);
LOG.debug(" Duplicated block: {} in {}", block, mth);
}
}
});
if (mth.getBasicBlocks().size() != blocksInRegions.size()) {
for (BlockNode block : mth.getBasicBlocks()) {
if (!blocksInRegions.contains(block) && !block.getInstructions().isEmpty() && !block.contains(AFlag.SKIP)) {
mth.add(AFlag.INCONSISTENT_CODE);
LOG.debug(" Missing block: {} in {}", block, mth);
}
}
}
// check loop conditions
DepthRegionTraversal.traverse(mth, new AbstractRegionVisitor() {
@Override
public boolean enterRegion(MethodNode mth, IRegion region) {
if (region instanceof LoopRegion) {
BlockNode loopHeader = ((LoopRegion) region).getHeader();
if (loopHeader != null && loopHeader.getInstructions().size() != 1) {
ErrorsCounter.methodError(mth, "Incorrect condition in loop: " + loopHeader);
}
}
return true;
}
});
}
use of jadx.core.dex.regions.loops.LoopRegion in project jadx by skylot.
the class RegionMaker method makeLoopRegion.
/**
* Select loop exit and construct LoopRegion
*/
private LoopRegion makeLoopRegion(IRegion curRegion, LoopInfo loop, List<BlockNode> exitBlocks) {
for (BlockNode block : exitBlocks) {
if (block.contains(AType.EXC_HANDLER) || block.getInstructions().size() != 1 || block.getInstructions().get(0).getType() != InsnType.IF) {
continue;
}
List<LoopInfo> loops = block.getAll(AType.LOOP);
if (!loops.isEmpty() && loops.get(0) != loop) {
// skip nested loop condition
continue;
}
LoopRegion loopRegion = new LoopRegion(curRegion, loop, block, block == loop.getEnd());
boolean found;
if (block == loop.getStart() || block == loop.getEnd() || BlockUtils.isEmptySimplePath(loop.getStart(), block)) {
found = true;
} else if (block.getPredecessors().contains(loop.getStart())) {
loopRegion.setPreCondition(loop.getStart());
// if we can't merge pre-condition this is not correct header
found = loopRegion.checkPreCondition();
} else {
found = false;
}
if (found) {
List<LoopInfo> list = mth.getAllLoopsForBlock(block);
if (list.size() >= 2) {
// bad condition if successors going out of all loops
boolean allOuter = true;
for (BlockNode outerBlock : block.getCleanSuccessors()) {
List<LoopInfo> outLoopList = mth.getAllLoopsForBlock(outerBlock);
outLoopList.remove(loop);
if (!outLoopList.isEmpty()) {
// goes to outer loop
allOuter = false;
break;
}
}
if (allOuter) {
found = false;
}
}
}
if (found) {
return loopRegion;
}
}
// no exit found => endless loop
return null;
}
Aggregations