use of jadx.core.utils.exceptions.JadxRuntimeException 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.utils.exceptions.JadxRuntimeException in project jadx by skylot.
the class BlockProcessor method computeDominators.
private static void computeDominators(MethodNode mth) {
List<BlockNode> basicBlocks = mth.getBasicBlocks();
int nBlocks = basicBlocks.size();
for (int i = 0; i < nBlocks; i++) {
BlockNode block = basicBlocks.get(i);
block.setId(i);
block.setDoms(new BitSet(nBlocks));
block.getDoms().set(0, nBlocks);
}
BlockNode entryBlock = mth.getEnterBlock();
entryBlock.getDoms().clear();
entryBlock.getDoms().set(entryBlock.getId());
BitSet dset = new BitSet(nBlocks);
boolean changed;
do {
changed = false;
for (BlockNode block : basicBlocks) {
if (block == entryBlock) {
continue;
}
BitSet d = block.getDoms();
if (!changed) {
dset.clear();
dset.or(d);
}
for (BlockNode pred : block.getPredecessors()) {
d.and(pred.getDoms());
}
d.set(block.getId());
if (!changed && !d.equals(dset)) {
changed = true;
}
}
} while (changed);
markLoops(mth);
// clear self dominance
for (BlockNode block : basicBlocks) {
block.getDoms().clear(block.getId());
}
// calculate immediate dominators
for (BlockNode block : basicBlocks) {
if (block == entryBlock) {
continue;
}
BlockNode idom;
List<BlockNode> preds = block.getPredecessors();
if (preds.size() == 1) {
idom = preds.get(0);
} else {
BitSet bs = new BitSet(block.getDoms().length());
bs.or(block.getDoms());
for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) {
BlockNode dom = basicBlocks.get(i);
bs.andNot(dom.getDoms());
}
if (bs.cardinality() != 1) {
throw new JadxRuntimeException("Can't find immediate dominator for block " + block + " in " + bs + " preds:" + preds);
}
idom = basicBlocks.get(bs.nextSetBit(0));
}
block.setIDom(idom);
idom.addDominatesOn(block);
}
}
use of jadx.core.utils.exceptions.JadxRuntimeException in project jadx by skylot.
the class BlockProcessor method modifyBlocksTree.
private static boolean modifyBlocksTree(MethodNode mth) {
for (BlockNode block : mth.getBasicBlocks()) {
if (block.getPredecessors().isEmpty() && block != mth.getEnterBlock()) {
throw new JadxRuntimeException("Unreachable block: " + block);
}
// check loops
List<LoopInfo> loops = block.getAll(AType.LOOP);
if (loops.size() > 1) {
boolean oneHeader = true;
for (LoopInfo loop : loops) {
if (loop.getStart() != block) {
oneHeader = false;
break;
}
}
if (oneHeader) {
// several back edges connected to one loop header => make additional block
BlockNode newLoopHeader = BlockSplitter.startNewBlock(mth, block.getStartOffset());
newLoopHeader.add(AFlag.SYNTHETIC);
connect(newLoopHeader, block);
for (LoopInfo la : loops) {
BlockNode node = la.getEnd();
removeConnection(node, block);
connect(node, newLoopHeader);
}
return true;
}
}
if (loops.size() == 1) {
LoopInfo loop = loops.get(0);
// insert additional blocks for possible 'break' insertion
List<Edge> edges = loop.getExitEdges();
if (!edges.isEmpty()) {
boolean change = false;
for (Edge edge : edges) {
BlockNode target = edge.getTarget();
if (!target.contains(AFlag.SYNTHETIC)) {
BlockSplitter.insertBlockBetween(mth, edge.getSource(), target);
change = true;
}
}
if (change) {
return true;
}
}
// insert additional blocks for possible 'continue' insertion
BlockNode loopEnd = loop.getEnd();
if (loopEnd.getPredecessors().size() > 1) {
boolean change = false;
List<BlockNode> nodes = new ArrayList<BlockNode>(loopEnd.getPredecessors());
for (BlockNode pred : nodes) {
if (!pred.contains(AFlag.SYNTHETIC)) {
BlockSplitter.insertBlockBetween(mth, pred, loopEnd);
change = true;
}
}
if (change) {
return true;
}
}
}
}
return splitReturn(mth);
}
use of jadx.core.utils.exceptions.JadxRuntimeException in project jadx by skylot.
the class InputFile method loadFromZip.
private boolean loadFromZip(String ext) throws IOException, DecodeException {
ZipFile zf = new ZipFile(file);
int index = 0;
while (true) {
String entryName = "classes" + (index == 0 ? "" : index) + ext;
ZipEntry entry = zf.getEntry(entryName);
if (entry == null) {
break;
}
InputStream inputStream = zf.getInputStream(entry);
try {
if (ext.equals(".dex")) {
addDexFile(entryName, new Dex(inputStream));
} else if (ext.equals(".jar")) {
File jarFile = FileUtils.createTempFile(entryName);
FileOutputStream fos = new FileOutputStream(jarFile);
try {
IOUtils.copy(inputStream, fos);
} finally {
close(fos);
}
addDexFile(entryName, loadFromJar(jarFile));
} else {
throw new JadxRuntimeException("Unexpected extension in zip: " + ext);
}
} finally {
close(inputStream);
}
index++;
if (index == 1) {
index = 2;
}
}
zf.close();
return index > 0;
}
use of jadx.core.utils.exceptions.JadxRuntimeException in project jadx by skylot.
the class Utils method openIcon.
public static ImageIcon openIcon(String name) {
String iconPath = "/icons-16/" + name + ".png";
URL resource = Utils.class.getResource(iconPath);
if (resource == null) {
throw new JadxRuntimeException("Icon not found: " + iconPath);
}
return new ImageIcon(resource);
}
Aggregations