use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.
the class ProcessTryCatchRegions method checkAndWrap.
private static boolean checkAndWrap(MethodNode mth, Map<BlockNode, TryCatchBlock> tryBlocksMap, IRegion region) {
// search dominator blocks in this region (don't need to go deeper)
for (Map.Entry<BlockNode, TryCatchBlock> entry : tryBlocksMap.entrySet()) {
BlockNode dominator = entry.getKey();
if (region.getSubBlocks().contains(dominator)) {
TryCatchBlock tb = tryBlocksMap.get(dominator);
if (!wrapBlocks(region, tb, dominator)) {
ErrorsCounter.methodError(mth, "Can't wrap try/catch for " + region);
}
tryBlocksMap.remove(dominator);
return true;
}
}
return false;
}
use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.
the class ProcessTryCatchRegions method searchTryCatchDominators.
private static void searchTryCatchDominators(MethodNode mth, Map<BlockNode, TryCatchBlock> tryBlocksMap) {
Set<TryCatchBlock> tryBlocks = new HashSet<TryCatchBlock>();
// collect all try/catch blocks
for (BlockNode block : mth.getBasicBlocks()) {
CatchAttr c = block.get(AType.CATCH_BLOCK);
if (c != null) {
tryBlocks.add(c.getTryBlock());
}
}
// for each try block search nearest dominator block
for (TryCatchBlock tb : tryBlocks) {
if (tb.getHandlersCount() == 0) {
LOG.warn("No exception handlers in catch block, method: {}", mth);
continue;
}
BitSet bs = new BitSet(mth.getBasicBlocks().size());
for (ExceptionHandler excHandler : tb.getHandlers()) {
SplitterBlockAttr splitter = excHandler.getHandlerBlock().get(AType.SPLITTER_BLOCK);
if (splitter != null) {
BlockNode block = splitter.getBlock();
bs.set(block.getId());
}
}
List<BlockNode> domBlocks = BlockUtils.bitSetToBlocks(mth, bs);
BlockNode domBlock;
if (domBlocks.size() != 1) {
domBlock = BlockUtils.getTopBlock(domBlocks);
if (domBlock == null) {
throw new JadxRuntimeException("Exception block dominator not found, method:" + mth + ". bs: " + domBlocks);
}
} else {
domBlock = domBlocks.get(0);
}
TryCatchBlock prevTB = tryBlocksMap.put(domBlock, tb);
if (prevTB != null) {
ErrorsCounter.methodError(mth, "Failed to process nested try/catch");
}
}
}
use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.
the class RegionMaker method processExcHandler.
private void processExcHandler(ExceptionHandler handler, Set<BlockNode> exits) {
BlockNode start = handler.getHandlerBlock();
if (start == null) {
return;
}
RegionStack stack = new RegionStack(mth);
BlockNode dom;
if (handler.isFinally()) {
SplitterBlockAttr splitterAttr = start.get(AType.SPLITTER_BLOCK);
if (splitterAttr == null) {
return;
}
dom = splitterAttr.getBlock();
} else {
dom = start;
stack.addExits(exits);
}
BitSet domFrontier = dom.getDomFrontier();
List<BlockNode> handlerExits = BlockUtils.bitSetToBlocks(mth, domFrontier);
boolean inLoop = mth.getLoopForBlock(start) != null;
for (BlockNode exit : handlerExits) {
if ((!inLoop || BlockUtils.isPathExists(start, exit)) && RegionUtils.isRegionContainsBlock(mth.getRegion(), exit)) {
stack.addExit(exit);
}
}
handler.setHandlerRegion(makeRegion(start, stack));
ExcHandlerAttr excHandlerAttr = start.get(AType.EXC_HANDLER);
if (excHandlerAttr == null) {
LOG.warn("Missing exception handler attribute for start block");
} else {
handler.getHandlerRegion().addAttr(excHandlerAttr);
}
}
use of jadx.core.dex.nodes.BlockNode 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.BlockNode in project jadx by skylot.
the class ModVisitor method replaceStep.
private static void replaceStep(MethodNode mth, InstructionRemover remover) {
ClassNode parentClass = mth.getParentClass();
for (BlockNode block : mth.getBasicBlocks()) {
remover.setBlock(block);
int size = block.getInstructions().size();
for (int i = 0; i < size; i++) {
InsnNode insn = block.getInstructions().get(i);
switch(insn.getType()) {
case INVOKE:
processInvoke(mth, block, i, remover);
break;
case CONST:
case CONST_STR:
case CONST_CLASS:
{
FieldNode f;
if (insn.getType() == InsnType.CONST_STR) {
String s = ((ConstStringNode) insn).getString();
f = parentClass.getConstField(s);
} else if (insn.getType() == InsnType.CONST_CLASS) {
ArgType t = ((ConstClassNode) insn).getClsType();
f = parentClass.getConstField(t);
} else {
f = parentClass.getConstFieldByLiteralArg((LiteralArg) insn.getArg(0));
}
if (f != null) {
InsnNode inode = new IndexInsnNode(InsnType.SGET, f.getFieldInfo(), 0);
inode.setResult(insn.getResult());
replaceInsn(block, i, inode);
}
break;
}
case SWITCH:
SwitchNode sn = (SwitchNode) insn;
for (int k = 0; k < sn.getCasesCount(); k++) {
FieldNode f = parentClass.getConstField(sn.getKeys()[k]);
if (f != null) {
sn.getKeys()[k] = f;
}
}
break;
case NEW_ARRAY:
// create array in 'fill-array' instruction
int next = i + 1;
if (next < size) {
InsnNode ni = block.getInstructions().get(next);
if (ni.getType() == InsnType.FILL_ARRAY) {
ni.getResult().merge(mth.dex(), insn.getResult());
ArgType arrType = ((NewArrayNode) insn).getArrayType();
((FillArrayNode) ni).mergeElementType(mth.dex(), arrType.getArrayElement());
remover.add(insn);
}
}
break;
case FILL_ARRAY:
InsnNode filledArr = makeFilledArrayInsn(mth, (FillArrayNode) insn);
replaceInsn(block, i, filledArr);
break;
case MOVE_EXCEPTION:
processMoveException(mth, block, insn, remover);
break;
case ARITH:
ArithNode arithNode = (ArithNode) insn;
if (arithNode.getArgsCount() == 2) {
InsnArg litArg = arithNode.getArg(1);
if (litArg.isLiteral()) {
FieldNode f = parentClass.getConstFieldByLiteralArg((LiteralArg) litArg);
if (f != null) {
InsnNode fGet = new IndexInsnNode(InsnType.SGET, f.getFieldInfo(), 0);
insn.replaceArg(litArg, InsnArg.wrapArg(fGet));
}
}
}
break;
default:
break;
}
}
remover.perform();
}
}
Aggregations