Search in sources :

Example 16 with JadxRuntimeException

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;
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) BitSet(java.util.BitSet) LinkedHashMap(java.util.LinkedHashMap) LoopInfo(jadx.core.dex.attributes.nodes.LoopInfo) Region(jadx.core.dex.regions.Region) IRegion(jadx.core.dex.nodes.IRegion) SwitchRegion(jadx.core.dex.regions.SwitchRegion) SynchronizedRegion(jadx.core.dex.regions.SynchronizedRegion) LoopRegion(jadx.core.dex.regions.loops.LoopRegion) IfRegion(jadx.core.dex.regions.conditions.IfRegion) SwitchRegion(jadx.core.dex.regions.SwitchRegion) List(java.util.List) ArrayList(java.util.ArrayList) JadxRuntimeException(jadx.core.utils.exceptions.JadxRuntimeException) Map(java.util.Map) LinkedHashMap(java.util.LinkedHashMap)

Example 17 with JadxRuntimeException

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);
    }
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) BitSet(java.util.BitSet) JadxRuntimeException(jadx.core.utils.exceptions.JadxRuntimeException)

Example 18 with JadxRuntimeException

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);
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) LoopInfo(jadx.core.dex.attributes.nodes.LoopInfo) ArrayList(java.util.ArrayList) JadxRuntimeException(jadx.core.utils.exceptions.JadxRuntimeException) Edge(jadx.core.dex.nodes.Edge)

Example 19 with JadxRuntimeException

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;
}
Also used : ZipFile(java.util.zip.ZipFile) InputStream(java.io.InputStream) Dex(com.android.dex.Dex) ZipEntry(java.util.zip.ZipEntry) FileOutputStream(java.io.FileOutputStream) JadxRuntimeException(jadx.core.utils.exceptions.JadxRuntimeException) File(java.io.File) ZipFile(java.util.zip.ZipFile)

Example 20 with JadxRuntimeException

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);
}
Also used : ImageIcon(javax.swing.ImageIcon) JadxRuntimeException(jadx.core.utils.exceptions.JadxRuntimeException) URL(java.net.URL)

Aggregations

JadxRuntimeException (jadx.core.utils.exceptions.JadxRuntimeException)35 BlockNode (jadx.core.dex.nodes.BlockNode)14 InsnNode (jadx.core.dex.nodes.InsnNode)8 RegisterArg (jadx.core.dex.instructions.args.RegisterArg)6 ArrayList (java.util.ArrayList)6 ArgType (jadx.core.dex.instructions.args.ArgType)5 BitSet (java.util.BitSet)5 SSAVar (jadx.core.dex.instructions.args.SSAVar)4 PhiInsn (jadx.core.dex.instructions.PhiInsn)3 InsnArg (jadx.core.dex.instructions.args.InsnArg)3 ClassNode (jadx.core.dex.nodes.ClassNode)3 IContainer (jadx.core.dex.nodes.IContainer)3 IRegion (jadx.core.dex.nodes.IRegion)3 File (java.io.File)3 ZipEntry (java.util.zip.ZipEntry)3 LoopInfo (jadx.core.dex.attributes.nodes.LoopInfo)2 PhiListAttr (jadx.core.dex.attributes.nodes.PhiListAttr)2 LiteralArg (jadx.core.dex.instructions.args.LiteralArg)2 FieldNode (jadx.core.dex.nodes.FieldNode)2 IBlock (jadx.core.dex.nodes.IBlock)2