Search in sources :

Example 1 with BlocksRemoveInfo

use of jadx.core.dex.visitors.blocksmaker.helpers.BlocksRemoveInfo in project jadx by skylot.

the class BlockFinallyExtract method extractFinally.

/**
	 * Search and remove common code from 'catch' and 'handlers'.
	 */
private static boolean extractFinally(MethodNode mth, ExceptionHandler handler) {
    int count = handler.getBlocks().size();
    BitSet bs = new BitSet(count);
    List<BlockNode> blocks = new ArrayList<BlockNode>(count);
    for (BlockNode block : handler.getBlocks()) {
        List<InsnNode> insns = block.getInstructions();
        if (!insns.isEmpty()) {
            if (insns.get(0).getType() != InsnType.MOVE_EXCEPTION) {
                blocks.add(block);
            }
            bs.set(block.getId());
        }
    }
    if (blocks.isEmpty()) {
        // nothing to do
        return false;
    }
    List<BlocksRemoveInfo> removes = new LinkedList<BlocksRemoveInfo>();
    Set<BlockNode> splitters = new HashSet<BlockNode>();
    // remove 'finally' from handlers
    TryCatchBlock tryBlock = handler.getTryBlock();
    if (tryBlock.getHandlersCount() > 1) {
        for (ExceptionHandler otherHandler : tryBlock.getHandlers()) {
            if (otherHandler == handler) {
                continue;
            }
            for (BlockNode hb : otherHandler.getBlocks()) {
                BlocksRemoveInfo removeInfo = removeInsns(mth, hb, blocks, bs);
                if (removeInfo != null) {
                    removes.add(removeInfo);
                    break;
                }
            }
        }
        if (removes.size() != tryBlock.getHandlersCount() - 1) {
            return false;
        }
    }
    for (ExceptionHandler otherHandler : tryBlock.getHandlers()) {
        SplitterBlockAttr splitterAttr = otherHandler.getHandlerBlock().get(AType.SPLITTER_BLOCK);
        if (splitterAttr != null) {
            BlockNode splBlock = splitterAttr.getBlock();
            if (!splBlock.getCleanSuccessors().isEmpty()) {
                splitters.add(splBlock);
            }
        }
    }
    // remove 'finally' from 'try' blocks (dominated by splitter block)
    boolean removed = false;
    for (BlockNode splitter : splitters) {
        BlockNode start = splitter.getCleanSuccessors().get(0);
        List<BlockNode> list = BlockUtils.collectBlocksDominatedBy(splitter, start);
        for (BlockNode block : list) {
            if (bs.get(block.getId())) {
                continue;
            }
            BlocksRemoveInfo removeInfo = removeInsns(mth, block, blocks, bs);
            if (removeInfo != null) {
                removes.add(removeInfo);
                removed = true;
                break;
            }
        }
    }
    if (!removed) {
        return false;
    }
    // 'finally' extract confirmed, run remove steps
    LiveVarAnalysis laBefore = null;
    boolean runReMap = isReMapNeeded(removes);
    if (runReMap) {
        laBefore = new LiveVarAnalysis(mth);
        laBefore.runAnalysis();
    }
    for (BlocksRemoveInfo removeInfo : removes) {
        if (!applyRemove(mth, removeInfo)) {
            return false;
        }
    }
    LiveVarAnalysis laAfter = null;
    // remove 'move-exception' instruction
    BlockNode handlerBlock = handler.getHandlerBlock();
    InsnNode me = BlockUtils.getLastInsn(handlerBlock);
    if (me != null && me.getType() == InsnType.MOVE_EXCEPTION) {
        boolean replaced = false;
        List<InsnNode> insnsList = handlerBlock.getInstructions();
        if (!handlerBlock.getCleanSuccessors().isEmpty()) {
            laAfter = new LiveVarAnalysis(mth);
            laAfter.runAnalysis();
            RegisterArg resArg = me.getResult();
            BlockNode succ = handlerBlock.getCleanSuccessors().get(0);
            if (laAfter.isLive(succ, resArg.getRegNum())) {
                // kill variable
                InsnNode kill = new InsnNode(InsnType.NOP, 0);
                kill.setResult(resArg);
                kill.add(AFlag.REMOVE);
                insnsList.set(insnsList.size() - 1, kill);
                replaced = true;
            }
        }
        if (!replaced) {
            insnsList.remove(insnsList.size() - 1);
            handlerBlock.add(AFlag.SKIP);
        }
    }
    // generate 'move' instruction for mapped register pairs
    if (runReMap) {
        if (laAfter == null) {
            laAfter = new LiveVarAnalysis(mth);
            laAfter.runAnalysis();
        }
        performVariablesReMap(mth, removes, laBefore, laAfter);
    }
    handler.setFinally(true);
    return true;
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) BitSet(java.util.BitSet) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) ExceptionHandler(jadx.core.dex.trycatch.ExceptionHandler) InsnNode(jadx.core.dex.nodes.InsnNode) RegisterArg(jadx.core.dex.instructions.args.RegisterArg) SplitterBlockAttr(jadx.core.dex.trycatch.SplitterBlockAttr) LiveVarAnalysis(jadx.core.dex.visitors.ssa.LiveVarAnalysis) TryCatchBlock(jadx.core.dex.trycatch.TryCatchBlock) BlocksRemoveInfo(jadx.core.dex.visitors.blocksmaker.helpers.BlocksRemoveInfo) HashSet(java.util.HashSet)

Example 2 with BlocksRemoveInfo

use of jadx.core.dex.visitors.blocksmaker.helpers.BlocksRemoveInfo in project jadx by skylot.

the class BlockFinallyExtract method isStartBlock.

/**
	 * 'Finally' instructions can start in the middle of the first block.
	 */
private static BlocksRemoveInfo isStartBlock(BlockNode remBlock, BlockNode startBlock) {
    List<InsnNode> remInsns = remBlock.getInstructions();
    List<InsnNode> startInsns = startBlock.getInstructions();
    if (remInsns.size() < startInsns.size()) {
        return null;
    }
    // first - fast check
    int startPos = remInsns.size() - startInsns.size();
    int endPos = 0;
    if (!checkInsns(remInsns, startInsns, startPos, null)) {
        if (checkInsns(remInsns, startInsns, 0, null)) {
            startPos = 0;
            endPos = startInsns.size();
        } else {
            boolean found = false;
            for (int i = 1; i < startPos; i++) {
                if (checkInsns(remInsns, startInsns, i, null)) {
                    startPos = i;
                    endPos = startInsns.size() + i;
                    found = true;
                    break;
                }
            }
            if (!found) {
                return null;
            }
        }
    }
    BlocksPair startPair = new BlocksPair(remBlock, startBlock);
    BlocksRemoveInfo removeInfo = new BlocksRemoveInfo(startPair);
    removeInfo.setStartSplitIndex(startPos);
    removeInfo.setEndSplitIndex(endPos);
    if (endPos != 0) {
        removeInfo.setEnd(startPair);
    }
    // second - run checks again for collect registers mapping
    if (!checkInsns(remInsns, startInsns, startPos, removeInfo)) {
        return null;
    }
    return removeInfo;
}
Also used : InsnNode(jadx.core.dex.nodes.InsnNode) BlocksPair(jadx.core.dex.visitors.blocksmaker.helpers.BlocksPair) BlocksRemoveInfo(jadx.core.dex.visitors.blocksmaker.helpers.BlocksRemoveInfo)

Example 3 with BlocksRemoveInfo

use of jadx.core.dex.visitors.blocksmaker.helpers.BlocksRemoveInfo in project jadx by skylot.

the class BlockFinallyExtract method removeInsns.

private static BlocksRemoveInfo removeInsns(MethodNode mth, BlockNode remBlock, List<BlockNode> blocks, BitSet bs) {
    if (blocks.isEmpty()) {
        return null;
    }
    BlockNode startBlock = blocks.get(0);
    BlocksRemoveInfo removeInfo = checkFromFirstBlock(remBlock, startBlock, bs);
    if (removeInfo == null) {
        return null;
    }
    Set<BlocksPair> outs = removeInfo.getOuts();
    if (outs.size() == 1) {
        return removeInfo;
    }
    // check if several 'return' blocks maps to one out
    if (mergeReturns(mth, outs)) {
        return removeInfo;
    }
    LOG.debug("Unexpected finally block outs count: {}", outs);
    return null;
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) BlocksPair(jadx.core.dex.visitors.blocksmaker.helpers.BlocksPair) BlocksRemoveInfo(jadx.core.dex.visitors.blocksmaker.helpers.BlocksRemoveInfo)

Example 4 with BlocksRemoveInfo

use of jadx.core.dex.visitors.blocksmaker.helpers.BlocksRemoveInfo in project jadx by skylot.

the class BlockFinallyExtract method performVariablesReMap.

private static void performVariablesReMap(MethodNode mth, List<BlocksRemoveInfo> removes, LiveVarAnalysis laBefore, LiveVarAnalysis laAfter) {
    BitSet processed = new BitSet(mth.getRegsCount());
    for (BlocksRemoveInfo removeInfo : removes) {
        processed.clear();
        BlocksPair start = removeInfo.getStart();
        BlockNode insertBlockBefore = start.getFirst();
        BlockNode insertBlock = start.getSecond();
        if (removeInfo.getRegMap().isEmpty() || insertBlock == null) {
            continue;
        }
        for (Map.Entry<RegisterArg, RegisterArg> entry : removeInfo.getRegMap().entrySet()) {
            RegisterArg fromReg = entry.getKey();
            RegisterArg toReg = entry.getValue();
            int fromRegNum = fromReg.getRegNum();
            int toRegNum = toReg.getRegNum();
            if (!processed.get(fromRegNum)) {
                boolean liveFromBefore = laBefore.isLive(insertBlockBefore, fromRegNum);
                boolean liveFromAfter = laAfter.isLive(insertBlock, fromRegNum);
                // boolean liveToBefore = laBefore.isLive(insertBlock, toRegNum);
                boolean liveToAfter = laAfter.isLive(insertBlock, toRegNum);
                if (liveToAfter && liveFromBefore) {
                    // merge 'to' and 'from' registers
                    InsnNode merge = new InsnNode(InsnType.MERGE, 2);
                    merge.setResult(toReg.duplicate());
                    merge.addArg(toReg.duplicate());
                    merge.addArg(fromReg.duplicate());
                    injectInsn(mth, insertBlock, merge);
                } else if (liveFromBefore) {
                    // remap variable
                    InsnNode move = new InsnNode(InsnType.MOVE, 1);
                    move.setResult(toReg.duplicate());
                    move.addArg(fromReg.duplicate());
                    injectInsn(mth, insertBlock, move);
                } else if (liveFromAfter) {
                    // kill variable
                    InsnNode kill = new InsnNode(InsnType.NOP, 0);
                    kill.setResult(fromReg.duplicate());
                    kill.add(AFlag.REMOVE);
                    injectInsn(mth, insertBlock, kill);
                }
                processed.set(fromRegNum);
            }
        }
    }
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) InsnNode(jadx.core.dex.nodes.InsnNode) RegisterArg(jadx.core.dex.instructions.args.RegisterArg) BitSet(java.util.BitSet) BlocksPair(jadx.core.dex.visitors.blocksmaker.helpers.BlocksPair) Map(java.util.Map) BlocksRemoveInfo(jadx.core.dex.visitors.blocksmaker.helpers.BlocksRemoveInfo)

Aggregations

BlocksRemoveInfo (jadx.core.dex.visitors.blocksmaker.helpers.BlocksRemoveInfo)4 BlockNode (jadx.core.dex.nodes.BlockNode)3 InsnNode (jadx.core.dex.nodes.InsnNode)3 BlocksPair (jadx.core.dex.visitors.blocksmaker.helpers.BlocksPair)3 RegisterArg (jadx.core.dex.instructions.args.RegisterArg)2 BitSet (java.util.BitSet)2 ExceptionHandler (jadx.core.dex.trycatch.ExceptionHandler)1 SplitterBlockAttr (jadx.core.dex.trycatch.SplitterBlockAttr)1 TryCatchBlock (jadx.core.dex.trycatch.TryCatchBlock)1 LiveVarAnalysis (jadx.core.dex.visitors.ssa.LiveVarAnalysis)1 ArrayList (java.util.ArrayList)1 HashSet (java.util.HashSet)1 LinkedList (java.util.LinkedList)1 Map (java.util.Map)1