Search in sources :

Example 1 with JadxRuntimeException

use of jadx.core.utils.exceptions.JadxRuntimeException 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");
        }
    }
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) ExceptionHandler(jadx.core.dex.trycatch.ExceptionHandler) SplitterBlockAttr(jadx.core.dex.trycatch.SplitterBlockAttr) BitSet(java.util.BitSet) TryCatchBlock(jadx.core.dex.trycatch.TryCatchBlock) CatchAttr(jadx.core.dex.trycatch.CatchAttr) JadxRuntimeException(jadx.core.utils.exceptions.JadxRuntimeException) HashSet(java.util.HashSet)

Example 2 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 3 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 4 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 5 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)

Aggregations

JadxRuntimeException (jadx.core.utils.exceptions.JadxRuntimeException)115 BlockNode (jadx.core.dex.nodes.BlockNode)25 ArrayList (java.util.ArrayList)25 InsnNode (jadx.core.dex.nodes.InsnNode)24 ArgType (jadx.core.dex.instructions.args.ArgType)20 RegisterArg (jadx.core.dex.instructions.args.RegisterArg)17 BitSet (java.util.BitSet)11 ClassNode (jadx.core.dex.nodes.ClassNode)10 MethodNode (jadx.core.dex.nodes.MethodNode)9 InsnArg (jadx.core.dex.instructions.args.InsnArg)8 SSAVar (jadx.core.dex.instructions.args.SSAVar)8 IOException (java.io.IOException)8 List (java.util.List)8 File (java.io.File)7 IRegion (jadx.core.dex.nodes.IRegion)6 Path (java.nio.file.Path)6 IndexInsnNode (jadx.core.dex.instructions.IndexInsnNode)5 PhiInsn (jadx.core.dex.instructions.PhiInsn)5 LiteralArg (jadx.core.dex.instructions.args.LiteralArg)5 FieldNode (jadx.core.dex.nodes.FieldNode)5