use of jadx.core.dex.nodes.IRegion 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.nodes.IRegion in project jadx by skylot.
the class ProcessVariables method visit.
@Override
public void visit(MethodNode mth) throws JadxException {
if (mth.isNoCode()) {
return;
}
final Map<Variable, Usage> usageMap = new LinkedHashMap<Variable, Usage>();
for (RegisterArg arg : mth.getArguments(true)) {
addToUsageMap(arg, usageMap);
}
// collect all variables usage
IRegionVisitor collect = new CollectUsageRegionVisitor(usageMap);
DepthRegionTraversal.traverse(mth, collect);
// reduce assigns map
List<RegisterArg> mthArgs = mth.getArguments(true);
for (RegisterArg arg : mthArgs) {
usageMap.remove(new Variable(arg));
}
Iterator<Entry<Variable, Usage>> umIt = usageMap.entrySet().iterator();
while (umIt.hasNext()) {
Entry<Variable, Usage> entry = umIt.next();
Usage u = entry.getValue();
// if no assigns => remove
if (u.getAssigns().isEmpty()) {
umIt.remove();
continue;
}
// variable declared at 'catch' clause
InsnNode parentInsn = u.getArg().getParentInsn();
if (parentInsn == null || parentInsn.getType() == InsnType.MOVE_EXCEPTION) {
umIt.remove();
}
}
if (usageMap.isEmpty()) {
return;
}
Map<IContainer, Integer> regionsOrder = new HashMap<IContainer, Integer>();
calculateOrder(mth.getRegion(), regionsOrder, 0, true);
for (Iterator<Entry<Variable, Usage>> it = usageMap.entrySet().iterator(); it.hasNext(); ) {
Entry<Variable, Usage> entry = it.next();
Usage u = entry.getValue();
// check if variable can be declared at current assigns
for (IRegion assignRegion : u.getAssigns()) {
if (u.getArgRegion() == assignRegion && canDeclareInRegion(u, assignRegion, regionsOrder)) {
if (declareAtAssign(u)) {
it.remove();
break;
}
}
}
}
if (usageMap.isEmpty()) {
return;
}
// apply
for (Entry<Variable, Usage> entry : usageMap.entrySet()) {
Usage u = entry.getValue();
// find region which contain all usage regions
Set<IRegion> set = u.getUseRegions();
for (Iterator<IRegion> it = set.iterator(); it.hasNext(); ) {
IRegion r = it.next();
IRegion parent = r.getParent();
if (parent != null && set.contains(parent)) {
it.remove();
}
}
IRegion region = null;
if (!set.isEmpty()) {
region = set.iterator().next();
} else if (!u.getAssigns().isEmpty()) {
region = u.getAssigns().iterator().next();
}
if (region == null) {
continue;
}
IRegion parent = region;
boolean declared = false;
while (parent != null) {
if (canDeclareInRegion(u, region, regionsOrder)) {
declareVar(region, u.getArg());
declared = true;
break;
}
region = parent;
parent = region.getParent();
}
if (!declared) {
declareVar(mth.getRegion(), u.getArg());
}
}
}
use of jadx.core.dex.nodes.IRegion in project jadx by skylot.
the class ProcessVariables method calculateOrder.
private static int calculateOrder(IContainer container, Map<IContainer, Integer> regionsOrder, int id, boolean inc) {
if (!(container instanceof IRegion)) {
return id;
}
IRegion region = (IRegion) container;
Integer previous = regionsOrder.put(region, id);
if (previous != null) {
return id;
}
for (IContainer c : region.getSubBlocks()) {
if (c instanceof IBranchRegion) {
// on branch set for all inner regions same order id
id = calculateOrder(c, regionsOrder, inc ? id + 1 : id, false);
} else {
List<IContainer> handlers = RegionUtils.getExcHandlersForRegion(c);
if (!handlers.isEmpty()) {
for (IContainer handler : handlers) {
id = calculateOrder(handler, regionsOrder, inc ? id + 1 : id, inc);
}
}
id = calculateOrder(c, regionsOrder, inc ? id + 1 : id, inc);
}
}
return id;
}
use of jadx.core.dex.nodes.IRegion in project jadx by skylot.
the class RegionMaker method processSwitch.
private BlockNode processSwitch(IRegion currentRegion, BlockNode block, SwitchNode insn, RegionStack stack) {
SwitchRegion sw = new SwitchRegion(currentRegion, block);
currentRegion.getSubBlocks().add(sw);
int len = insn.getTargets().length;
// sort by target
Map<Integer, List<Object>> casesMap = new LinkedHashMap<Integer, List<Object>>(len);
for (int i = 0; i < len; i++) {
Object key = insn.getKeys()[i];
int targ = insn.getTargets()[i];
List<Object> keys = casesMap.get(targ);
if (keys == null) {
keys = new ArrayList<Object>(2);
casesMap.put(targ, keys);
}
keys.add(key);
}
Map<BlockNode, List<Object>> blocksMap = new LinkedHashMap<BlockNode, List<Object>>(len);
for (Map.Entry<Integer, List<Object>> entry : casesMap.entrySet()) {
BlockNode c = getBlockByOffset(entry.getKey(), block.getSuccessors());
if (c == null) {
throw new JadxRuntimeException("Switch block not found by offset: " + entry.getKey());
}
blocksMap.put(c, entry.getValue());
}
BlockNode defCase = getBlockByOffset(insn.getDefaultCaseOffset(), block.getSuccessors());
if (defCase != null) {
blocksMap.remove(defCase);
}
LoopInfo loop = mth.getLoopForBlock(block);
Map<BlockNode, BlockNode> fallThroughCases = new LinkedHashMap<BlockNode, BlockNode>();
List<BlockNode> basicBlocks = mth.getBasicBlocks();
BitSet outs = new BitSet(basicBlocks.size());
outs.or(block.getDomFrontier());
for (BlockNode s : block.getCleanSuccessors()) {
BitSet df = s.getDomFrontier();
// fall through case block
if (df.cardinality() > 1) {
if (df.cardinality() > 2) {
LOG.debug("Unexpected case pattern, block: {}, mth: {}", s, mth);
} else {
BlockNode first = basicBlocks.get(df.nextSetBit(0));
BlockNode second = basicBlocks.get(df.nextSetBit(first.getId() + 1));
if (second.getDomFrontier().get(first.getId())) {
fallThroughCases.put(s, second);
df = new BitSet(df.size());
df.set(first.getId());
} else if (first.getDomFrontier().get(second.getId())) {
fallThroughCases.put(s, first);
df = new BitSet(df.size());
df.set(second.getId());
}
}
}
outs.or(df);
}
outs.clear(block.getId());
if (loop != null) {
outs.clear(loop.getStart().getId());
}
stack.push(sw);
stack.addExits(BlockUtils.bitSetToBlocks(mth, outs));
// check cases order if fall through case exists
if (!fallThroughCases.isEmpty()) {
if (isBadCasesOrder(blocksMap, fallThroughCases)) {
LOG.debug("Fixing incorrect switch cases order, method: {}", mth);
blocksMap = reOrderSwitchCases(blocksMap, fallThroughCases);
if (isBadCasesOrder(blocksMap, fallThroughCases)) {
LOG.error("Can't fix incorrect switch cases order, method: {}", mth);
mth.add(AFlag.INCONSISTENT_CODE);
}
}
}
// filter 'out' block
if (outs.cardinality() > 1) {
// remove exception handlers
BlockUtils.cleanBitSet(mth, outs);
}
if (outs.cardinality() > 1) {
// filter loop start and successors of other blocks
for (int i = outs.nextSetBit(0); i >= 0; i = outs.nextSetBit(i + 1)) {
BlockNode b = basicBlocks.get(i);
outs.andNot(b.getDomFrontier());
if (b.contains(AFlag.LOOP_START)) {
outs.clear(b.getId());
} else {
for (BlockNode s : b.getCleanSuccessors()) {
outs.clear(s.getId());
}
}
}
}
if (loop != null && outs.cardinality() > 1) {
outs.clear(loop.getEnd().getId());
}
if (outs.cardinality() == 0) {
// run expensive algorithm for find 'out' block
for (BlockNode maybeOut : block.getSuccessors()) {
boolean allReached = true;
for (BlockNode s : block.getSuccessors()) {
if (!isPathExists(s, maybeOut)) {
allReached = false;
break;
}
}
if (allReached) {
outs.set(maybeOut.getId());
break;
}
}
}
BlockNode out = null;
if (outs.cardinality() == 1) {
out = basicBlocks.get(outs.nextSetBit(0));
stack.addExit(out);
} else if (loop == null && outs.cardinality() > 1) {
LOG.warn("Can't detect out node for switch block: {} in {}", block, mth);
}
if (loop != null) {
// check if 'continue' must be inserted
BlockNode end = loop.getEnd();
if (out != end && out != null) {
insertContinueInSwitch(block, out, end);
}
}
if (!stack.containsExit(defCase)) {
sw.setDefaultCase(makeRegion(defCase, stack));
}
for (Entry<BlockNode, List<Object>> entry : blocksMap.entrySet()) {
BlockNode caseBlock = entry.getKey();
if (stack.containsExit(caseBlock)) {
// empty case block
sw.addCase(entry.getValue(), new Region(stack.peekRegion()));
} else {
BlockNode next = fallThroughCases.get(caseBlock);
stack.addExit(next);
Region caseRegion = makeRegion(caseBlock, stack);
stack.removeExit(next);
if (next != null) {
next.add(AFlag.FALL_THROUGH);
caseRegion.add(AFlag.FALL_THROUGH);
}
sw.addCase(entry.getValue(), caseRegion);
// 'break' instruction will be inserted in RegionMakerVisitor.PostRegionVisitor
}
}
stack.pop();
return out;
}
use of jadx.core.dex.nodes.IRegion in project jadx by skylot.
the class RegionMaker method processHandlersOutBlocks.
/**
* Search handlers successor blocks not included in any region.
*/
protected IRegion processHandlersOutBlocks(MethodNode mth, Set<TryCatchBlock> tcs) {
Set<IBlock> allRegionBlocks = new HashSet<IBlock>();
RegionUtils.getAllRegionBlocks(mth.getRegion(), allRegionBlocks);
Set<IBlock> succBlocks = new HashSet<IBlock>();
for (TryCatchBlock 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;
}
Aggregations