Search in sources :

Example 21 with IntList

use of com.taobao.android.dx.util.IntList in project atlas by alibaba.

the class StdCatchBuilder method handlersFor.

/**
 * Makes the {@link CatchHandlerList} for the given basic block.
 *
 * @param block {@code non-null;} block to get entries for
 * @param addresses {@code non-null;} address objects for each block
 * @return {@code non-null;} array of entries
 */
private static CatchHandlerList handlersFor(BasicBlock block, BlockAddresses addresses) {
    IntList successors = block.getSuccessors();
    int succSize = successors.size();
    int primary = block.getPrimarySuccessor();
    TypeList catches = block.getLastInsn().getCatches();
    int catchSize = catches.size();
    if (catchSize == 0) {
        return CatchHandlerList.EMPTY;
    }
    if (((primary == -1) && (succSize != catchSize)) || ((primary != -1) && ((succSize != (catchSize + 1)) || (primary != successors.get(catchSize))))) {
        /*
             * Blocks that throw are supposed to list their primary
             * successor -- if any -- last in the successors list, but
             * that constraint appears to be violated here.
             */
        throw new RuntimeException("shouldn't happen: weird successors list");
    }
    /*
         * Reduce the effective catchSize if we spot a catch-all that
         * isn't at the end.
         */
    for (int i = 0; i < catchSize; i++) {
        Type type = catches.getType(i);
        if (type.equals(Type.OBJECT)) {
            catchSize = i + 1;
            break;
        }
    }
    CatchHandlerList result = new CatchHandlerList(catchSize);
    for (int i = 0; i < catchSize; i++) {
        CstType oneType = new CstType(catches.getType(i));
        CodeAddress oneHandler = addresses.getStart(successors.get(i));
        result.set(i, oneType, oneHandler.getAddress());
    }
    result.setImmutable();
    return result;
}
Also used : CstType(com.taobao.android.dx.rop.cst.CstType) Type(com.taobao.android.dx.rop.type.Type) CstType(com.taobao.android.dx.rop.cst.CstType) TypeList(com.taobao.android.dx.rop.type.TypeList) IntList(com.taobao.android.dx.util.IntList)

Example 22 with IntList

use of com.taobao.android.dx.util.IntList in project atlas by alibaba.

the class Ropper method deleteUnreachableBlocks.

/**
 * Deletes all blocks that cannot be reached. This is run to delete
 * original subroutine blocks after subroutine inlining.
 */
private void deleteUnreachableBlocks() {
    final IntList reachableLabels = new IntList(result.size());
    // subroutine inlining is done now and we won't update this list here
    resultSubroutines.clear();
    forEachNonSubBlockDepthFirst(getSpecialLabel(PARAM_ASSIGNMENT), new BasicBlock.Visitor() {

        public void visitBlock(BasicBlock b) {
            reachableLabels.add(b.getLabel());
        }
    });
    reachableLabels.sort();
    for (int i = result.size() - 1; i >= 0; i--) {
        if (reachableLabels.indexOf(result.get(i).getLabel()) < 0) {
            result.remove(i);
        // unnecessary here really, since subroutine inlining is done
        // resultSubroutines.remove(i);
        }
    }
}
Also used : BasicBlock(com.taobao.android.dx.rop.code.BasicBlock) IntList(com.taobao.android.dx.util.IntList)

Example 23 with IntList

use of com.taobao.android.dx.util.IntList in project atlas by alibaba.

the class Ropper method removeBlockAndSpecialSuccessors.

/**
 * Helper for {@link #addOrReplaceBlock} which recursively removes
 * the given block and all blocks that are (direct and indirect)
 * successors of it whose labels indicate that they are not in the
 * normally-translated range.
 *
 * @param idx {@code non-null;} block to remove (etc.)
 */
private void removeBlockAndSpecialSuccessors(int idx) {
    int minLabel = getMinimumUnreservedLabel();
    BasicBlock block = result.get(idx);
    IntList successors = block.getSuccessors();
    int sz = successors.size();
    result.remove(idx);
    resultSubroutines.remove(idx);
    for (int i = 0; i < sz; i++) {
        int label = successors.get(i);
        if (label >= minLabel) {
            idx = labelToResultIndex(label);
            if (idx < 0) {
                throw new RuntimeException("Invalid label " + Hex.u2(label));
            }
            removeBlockAndSpecialSuccessors(idx);
        }
    }
}
Also used : BasicBlock(com.taobao.android.dx.rop.code.BasicBlock) IntList(com.taobao.android.dx.util.IntList)

Example 24 with IntList

use of com.taobao.android.dx.util.IntList in project atlas by alibaba.

the class Ropper method isSubroutineCaller.

/**
 * Checks to see if the basic block is a subroutine caller block.
 *
 * @param bb {@code non-null;} the basic block in question
 * @return true if this block calls a subroutine
 */
private boolean isSubroutineCaller(BasicBlock bb) {
    IntList successors = bb.getSuccessors();
    if (successors.size() < 2)
        return false;
    int subLabel = successors.get(1);
    return (subLabel < subroutines.length) && (subroutines[subLabel] != null);
}
Also used : IntList(com.taobao.android.dx.util.IntList)

Example 25 with IntList

use of com.taobao.android.dx.util.IntList in project atlas by alibaba.

the class Ropper method processBlock.

/**
 * Processes the given block.
 *
 * @param block {@code non-null;} block to process
 * @param frame {@code non-null;} start frame for the block
 * @param workSet {@code non-null;} bits representing work to do,
 * which this method may add to
 */
private void processBlock(ByteBlock block, Frame frame, int[] workSet) {
    // Prepare the list of caught exceptions for this block.
    ByteCatchList catches = block.getCatches();
    machine.startBlock(catches.toRopCatchList());
    /*
         * Using a copy of the given frame, simulate each instruction,
         * calling into machine for each.
         */
    frame = frame.copy();
    sim.simulate(block, frame);
    frame.setImmutable();
    int extraBlockCount = machine.getExtraBlockCount();
    ArrayList<Insn> insns = machine.getInsns();
    int insnSz = insns.size();
    /*
         * Merge the frame into each possible non-exceptional
         * successor.
         */
    int catchSz = catches.size();
    IntList successors = block.getSuccessors();
    int startSuccessorIndex;
    Subroutine calledSubroutine = null;
    if (machine.hasJsr()) {
        /*
             * If this frame ends in a JSR, only merge our frame with
             * the subroutine start, not the subroutine's return target.
             */
        startSuccessorIndex = 1;
        int subroutineLabel = successors.get(1);
        if (subroutines[subroutineLabel] == null) {
            subroutines[subroutineLabel] = new Subroutine(subroutineLabel);
        }
        subroutines[subroutineLabel].addCallerBlock(block.getLabel());
        calledSubroutine = subroutines[subroutineLabel];
    } else if (machine.hasRet()) {
        /*
             * This block ends in a ret, which means it's the final block
             * in some subroutine. Ultimately, this block will be copied
             * and inlined for each call and then disposed of.
             */
        ReturnAddress ra = machine.getReturnAddress();
        int subroutineLabel = ra.getSubroutineAddress();
        if (subroutines[subroutineLabel] == null) {
            subroutines[subroutineLabel] = new Subroutine(subroutineLabel, block.getLabel());
        } else {
            subroutines[subroutineLabel].addRetBlock(block.getLabel());
        }
        successors = subroutines[subroutineLabel].getSuccessors();
        subroutines[subroutineLabel].mergeToSuccessors(frame, workSet);
        // Skip processing below since we just did it.
        startSuccessorIndex = successors.size();
    } else if (machine.wereCatchesUsed()) {
        /*
             * If there are catches, then the first successors
             * (which will either be all of them or all but the last one)
             * are catch targets.
             */
        startSuccessorIndex = catchSz;
    } else {
        startSuccessorIndex = 0;
    }
    int succSz = successors.size();
    for (int i = startSuccessorIndex; i < succSz; i++) {
        int succ = successors.get(i);
        try {
            mergeAndWorkAsNecessary(succ, block.getLabel(), calledSubroutine, frame, workSet);
        } catch (SimException ex) {
            ex.addContext("...while merging to block " + Hex.u2(succ));
            throw ex;
        }
    }
    if ((succSz == 0) && machine.returns()) {
        /*
             * The block originally contained a return, but it has
             * been made to instead end with a goto, and we need to
             * tell it at this point that its sole successor is the
             * return block. This has to happen after the merge loop
             * above, since, at this point, the return block doesn't
             * actually exist; it gets synthesized at the end of
             * processing the original blocks.
             */
        successors = IntList.makeImmutable(getSpecialLabel(RETURN));
        succSz = 1;
    }
    int primarySucc;
    if (succSz == 0) {
        primarySucc = -1;
    } else {
        primarySucc = machine.getPrimarySuccessorIndex();
        if (primarySucc >= 0) {
            primarySucc = successors.get(primarySucc);
        }
    }
    /*
         * This variable is true only when the method is synchronized and
         * the block being processed can possibly throw an exception.
         */
    boolean synch = isSynchronized() && machine.canThrow();
    if (synch || (catchSz != 0)) {
        /*
             * Deal with exception handlers: Merge an exception-catch
             * frame into each possible exception handler, and
             * construct a new set of successors to point at the
             * exception handler setup blocks (which get synthesized
             * at the very end of processing).
             */
        boolean catchesAny = false;
        IntList newSucc = new IntList(succSz);
        for (int i = 0; i < catchSz; i++) {
            ByteCatchList.Item one = catches.get(i);
            CstType exceptionClass = one.getExceptionClass();
            int targ = one.getHandlerPc();
            catchesAny |= (exceptionClass == CstType.OBJECT);
            Frame f = frame.makeExceptionHandlerStartFrame(exceptionClass);
            try {
                mergeAndWorkAsNecessary(targ, block.getLabel(), null, f, workSet);
            } catch (SimException ex) {
                ex.addContext("...while merging exception to block " + Hex.u2(targ));
                throw ex;
            }
            /*
                 * Set up the exception handler type.
                 */
            CatchInfo handlers = catchInfos[targ];
            if (handlers == null) {
                handlers = new CatchInfo();
                catchInfos[targ] = handlers;
            }
            ExceptionHandlerSetup handler = handlers.getSetup(exceptionClass.getClassType());
            /*
                 * The synthesized exception setup block will have the label given by handler.
                 */
            newSucc.add(handler.getLabel());
        }
        if (synch && !catchesAny) {
            /*
                 * The method is synchronized and this block doesn't
                 * already have a catch-all handler, so add one to the
                 * end, both in the successors and in the throwing
                 * instruction(s) at the end of the block (which is where
                 * the caught classes live).
                 */
            newSucc.add(getSpecialLabel(SYNCH_CATCH_1));
            synchNeedsExceptionHandler = true;
            for (int i = insnSz - extraBlockCount - 1; i < insnSz; i++) {
                Insn insn = insns.get(i);
                if (insn.canThrow()) {
                    insn = insn.withAddedCatch(Type.OBJECT);
                    insns.set(i, insn);
                }
            }
        }
        if (primarySucc >= 0) {
            newSucc.add(primarySucc);
        }
        newSucc.setImmutable();
        successors = newSucc;
    }
    // Construct the final resulting block(s), and store it (them).
    int primarySuccListIndex = successors.indexOf(primarySucc);
    /*
         * If there are any extra blocks, work backwards through the
         * list of instructions, adding single-instruction blocks, and
         * resetting the successors variables as appropriate.
         */
    for (; /*extraBlockCount*/
    extraBlockCount > 0; extraBlockCount--) {
        /*
             * Some of the blocks that the RopperMachine wants added
             * are for move-result insns, and these need goto insns as well.
             */
        Insn extraInsn = insns.get(--insnSz);
        boolean needsGoto = extraInsn.getOpcode().getBranchingness() == Rop.BRANCH_NONE;
        InsnList il = new InsnList(needsGoto ? 2 : 1);
        IntList extraBlockSuccessors = successors;
        il.set(0, extraInsn);
        if (needsGoto) {
            il.set(1, new PlainInsn(Rops.GOTO, extraInsn.getPosition(), null, RegisterSpecList.EMPTY));
            /*
                 * Obviously, this block won't be throwing an exception
                 * so it should only have one successor.
                 */
            extraBlockSuccessors = IntList.makeImmutable(primarySucc);
        }
        il.setImmutable();
        int label = getAvailableLabel();
        BasicBlock bb = new BasicBlock(label, il, extraBlockSuccessors, primarySucc);
        // All of these extra blocks will be in the same subroutine
        addBlock(bb, frame.getSubroutines());
        successors = successors.mutableCopy();
        successors.set(primarySuccListIndex, label);
        successors.setImmutable();
        primarySucc = label;
    }
    Insn lastInsn = (insnSz == 0) ? null : insns.get(insnSz - 1);
    /*
         * Add a goto to the end of the block if it doesn't already
         * end with a branch, to maintain the invariant that all
         * blocks end with a branch of some sort or other. Note that
         * it is possible for there to be blocks for which no
         * instructions were ever output (e.g., only consist of pop*
         * in the original Java bytecode).
         */
    if ((lastInsn == null) || (lastInsn.getOpcode().getBranchingness() == Rop.BRANCH_NONE)) {
        SourcePosition pos = (lastInsn == null) ? SourcePosition.NO_INFO : lastInsn.getPosition();
        insns.add(new PlainInsn(Rops.GOTO, pos, null, RegisterSpecList.EMPTY));
        insnSz++;
    }
    /*
         * Construct a block for the remaining instructions (which in
         * the usual case is all of them).
         */
    InsnList il = new InsnList(insnSz);
    for (int i = 0; i < insnSz; i++) {
        il.set(i, insns.get(i));
    }
    il.setImmutable();
    BasicBlock bb = new BasicBlock(block.getLabel(), il, successors, primarySucc);
    addOrReplaceBlock(bb, frame.getSubroutines());
}
Also used : Insn(com.taobao.android.dx.rop.code.Insn) PlainCstInsn(com.taobao.android.dx.rop.code.PlainCstInsn) PlainInsn(com.taobao.android.dx.rop.code.PlainInsn) ThrowingInsn(com.taobao.android.dx.rop.code.ThrowingInsn) ThrowingCstInsn(com.taobao.android.dx.rop.code.ThrowingCstInsn) BasicBlock(com.taobao.android.dx.rop.code.BasicBlock) InsnList(com.taobao.android.dx.rop.code.InsnList) IntList(com.taobao.android.dx.util.IntList) PlainInsn(com.taobao.android.dx.rop.code.PlainInsn) CstType(com.taobao.android.dx.rop.cst.CstType) SourcePosition(com.taobao.android.dx.rop.code.SourcePosition)

Aggregations

IntList (com.taobao.android.dx.util.IntList)30 BasicBlock (com.taobao.android.dx.rop.code.BasicBlock)11 RopMethod (com.taobao.android.dx.rop.code.RopMethod)4 CstType (com.taobao.android.dx.rop.cst.CstType)4 BasicBlockList (com.taobao.android.dx.rop.code.BasicBlockList)3 DexTranslationAdvice (com.taobao.android.dx.rop.code.DexTranslationAdvice)3 Insn (com.taobao.android.dx.rop.code.Insn)3 TranslationAdvice (com.taobao.android.dx.rop.code.TranslationAdvice)3 BytecodeArray (com.taobao.android.dx.cf.code.BytecodeArray)2 ConcreteMethod (com.taobao.android.dx.cf.code.ConcreteMethod)2 Method (com.taobao.android.dx.cf.iface.Method)2 InsnList (com.taobao.android.dx.rop.code.InsnList)2 PlainCstInsn (com.taobao.android.dx.rop.code.PlainCstInsn)2 PlainInsn (com.taobao.android.dx.rop.code.PlainInsn)2 RegisterSpec (com.taobao.android.dx.rop.code.RegisterSpec)2 SourcePosition (com.taobao.android.dx.rop.code.SourcePosition)2 ThrowingCstInsn (com.taobao.android.dx.rop.code.ThrowingCstInsn)2 ThrowingInsn (com.taobao.android.dx.rop.code.ThrowingInsn)2 Type (com.taobao.android.dx.rop.type.Type)2 TypeList (com.taobao.android.dx.rop.type.TypeList)2