Search in sources :

Example 16 with ExceptionHandler

use of org.jf.dexlib2.iface.ExceptionHandler in project smali by JesusFreke.

the class TryListBuilderTest method testHandlerMerge_MergeSame.

@Test
public void testHandlerMerge_MergeSame() {
    TryListBuilder tlb = new TryListBuilder();
    tlb.addHandler(0, 15, new ImmutableExceptionHandler(null, 6));
    tlb.addHandler(10, 20, new ImmutableExceptionHandler("LException1;", 5));
    tlb.addHandler(20, 30, new ImmutableExceptionHandler("LException1;", 5));
    tlb.addHandler(25, 40, new ImmutableExceptionHandler(null, 6));
    List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
    List<? extends TryBlock> expected = ImmutableList.of(new ImmutableTryBlock(0, 10, ImmutableList.of(new ImmutableExceptionHandler(null, 6))), new ImmutableTryBlock(10, 5, ImmutableList.of(new ImmutableExceptionHandler(null, 6), new ImmutableExceptionHandler("LException1;", 5))), new ImmutableTryBlock(15, 10, ImmutableList.of(new ImmutableExceptionHandler("LException1;", 5))), new ImmutableTryBlock(25, 5, ImmutableList.of(new ImmutableExceptionHandler("LException1;", 5), new ImmutableExceptionHandler(null, 6))), new ImmutableTryBlock(30, 10, ImmutableList.of(new ImmutableExceptionHandler(null, 6))));
    Assert.assertEquals(expected, tryBlocks);
}
Also used : ImmutableTryBlock(org.jf.dexlib2.immutable.ImmutableTryBlock) ImmutableExceptionHandler(org.jf.dexlib2.immutable.ImmutableExceptionHandler) Test(org.junit.Test)

Example 17 with ExceptionHandler

use of org.jf.dexlib2.iface.ExceptionHandler in project smali by JesusFreke.

the class TryListBuilderTest method testOverlap_Before_Before.

@Test
public void testOverlap_Before_Before() {
    TryListBuilder tlb = new TryListBuilder();
    tlb.addHandler(5, 10, new ImmutableExceptionHandler("LException1;", 5));
    tlb.addHandler(0, 3, new ImmutableExceptionHandler("LException2;", 6));
    List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
    List<? extends TryBlock> expected = ImmutableList.of(new ImmutableTryBlock(0, 3, ImmutableList.of(new ImmutableExceptionHandler("LException2;", 6))), new ImmutableTryBlock(5, 5, ImmutableList.of(new ImmutableExceptionHandler("LException1;", 5))));
    Assert.assertEquals(expected, tryBlocks);
}
Also used : ImmutableTryBlock(org.jf.dexlib2.immutable.ImmutableTryBlock) ImmutableExceptionHandler(org.jf.dexlib2.immutable.ImmutableExceptionHandler) Test(org.junit.Test)

Example 18 with ExceptionHandler

use of org.jf.dexlib2.iface.ExceptionHandler in project smali by JesusFreke.

the class TryListBuilderTest method testSingleCatchAll_Beginning.

@Test
public void testSingleCatchAll_Beginning() {
    TryListBuilder tlb = new TryListBuilder();
    tlb.addHandler(0, 10, new ImmutableExceptionHandler(null, 5));
    List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
    List<? extends TryBlock> expected = ImmutableList.of(new ImmutableTryBlock(0, 10, ImmutableList.of(new ImmutableExceptionHandler(null, 5))));
    Assert.assertEquals(expected, tryBlocks);
}
Also used : ImmutableTryBlock(org.jf.dexlib2.immutable.ImmutableTryBlock) ImmutableExceptionHandler(org.jf.dexlib2.immutable.ImmutableExceptionHandler) Test(org.junit.Test)

Example 19 with ExceptionHandler

use of org.jf.dexlib2.iface.ExceptionHandler in project smali by JesusFreke.

the class MethodAnalyzer method buildInstructionList.

private void buildInstructionList() {
    int registerCount = methodImpl.getRegisterCount();
    ImmutableList<Instruction> instructions = ImmutableList.copyOf(methodImpl.getInstructions());
    analyzedInstructions.ensureCapacity(instructions.size());
    //first, create all the instructions and populate the instructionAddresses array
    int currentCodeAddress = 0;
    for (int i = 0; i < instructions.size(); i++) {
        Instruction instruction = instructions.get(i);
        analyzedInstructions.append(currentCodeAddress, new AnalyzedInstruction(this, instruction, i, registerCount));
        assert analyzedInstructions.indexOfKey(currentCodeAddress) == i;
        currentCodeAddress += instruction.getCodeUnits();
    }
    //next, populate the exceptionHandlers array. The array item for each instruction that can throw an exception
    //and is covered by a try block should be set to a list of the first instructions of each exception handler
    //for the try block covering the instruction
    List<? extends TryBlock<? extends ExceptionHandler>> tries = methodImpl.getTryBlocks();
    tries = TryListBuilder.massageTryBlocks(tries);
    int triesIndex = 0;
    TryBlock currentTry = null;
    AnalyzedInstruction[] currentExceptionHandlers = null;
    AnalyzedInstruction[][] exceptionHandlers = new AnalyzedInstruction[instructions.size()][];
    if (tries != null) {
        for (int i = 0; i < analyzedInstructions.size(); i++) {
            AnalyzedInstruction instruction = analyzedInstructions.valueAt(i);
            Opcode instructionOpcode = instruction.instruction.getOpcode();
            currentCodeAddress = getInstructionAddress(instruction);
            //check if we have gone past the end of the current try
            if (currentTry != null) {
                if (currentTry.getStartCodeAddress() + currentTry.getCodeUnitCount() <= currentCodeAddress) {
                    currentTry = null;
                    triesIndex++;
                }
            }
            //check if the next try is applicable yet
            if (currentTry == null && triesIndex < tries.size()) {
                TryBlock<? extends ExceptionHandler> tryBlock = tries.get(triesIndex);
                if (tryBlock.getStartCodeAddress() <= currentCodeAddress) {
                    assert (tryBlock.getStartCodeAddress() + tryBlock.getCodeUnitCount() > currentCodeAddress);
                    currentTry = tryBlock;
                    currentExceptionHandlers = buildExceptionHandlerArray(tryBlock);
                }
            }
            //for the current instruction
            if (currentTry != null && instructionOpcode.canThrow()) {
                exceptionHandlers[i] = currentExceptionHandlers;
            }
        }
    }
    //and no reachable code will have an unreachable predessor or successor
    assert analyzedInstructions.size() > 0;
    BitSet instructionsToProcess = new BitSet(instructions.size());
    addPredecessorSuccessor(startOfMethod, analyzedInstructions.valueAt(0), exceptionHandlers, instructionsToProcess);
    while (!instructionsToProcess.isEmpty()) {
        int currentInstructionIndex = instructionsToProcess.nextSetBit(0);
        instructionsToProcess.clear(currentInstructionIndex);
        AnalyzedInstruction instruction = analyzedInstructions.valueAt(currentInstructionIndex);
        Opcode instructionOpcode = instruction.instruction.getOpcode();
        int instructionCodeAddress = getInstructionAddress(instruction);
        if (instruction.instruction.getOpcode().canContinue()) {
            if (currentInstructionIndex == analyzedInstructions.size() - 1) {
                throw new AnalysisException("Execution can continue past the last instruction");
            }
            AnalyzedInstruction nextInstruction = analyzedInstructions.valueAt(currentInstructionIndex + 1);
            addPredecessorSuccessor(instruction, nextInstruction, exceptionHandlers, instructionsToProcess);
        }
        if (instruction.instruction instanceof OffsetInstruction) {
            OffsetInstruction offsetInstruction = (OffsetInstruction) instruction.instruction;
            if (instructionOpcode == Opcode.PACKED_SWITCH || instructionOpcode == Opcode.SPARSE_SWITCH) {
                AnalyzedInstruction analyzedSwitchPayload = analyzedInstructions.get(instructionCodeAddress + offsetInstruction.getCodeOffset());
                if (analyzedSwitchPayload == null) {
                    throw new AnalysisException("Invalid switch payload offset");
                }
                SwitchPayload switchPayload = (SwitchPayload) analyzedSwitchPayload.instruction;
                for (SwitchElement switchElement : switchPayload.getSwitchElements()) {
                    AnalyzedInstruction targetInstruction = analyzedInstructions.get(instructionCodeAddress + switchElement.getOffset());
                    if (targetInstruction == null) {
                        throw new AnalysisException("Invalid switch target offset");
                    }
                    addPredecessorSuccessor(instruction, targetInstruction, exceptionHandlers, instructionsToProcess);
                }
            } else if (instructionOpcode != Opcode.FILL_ARRAY_DATA) {
                int targetAddressOffset = offsetInstruction.getCodeOffset();
                AnalyzedInstruction targetInstruction = analyzedInstructions.get(instructionCodeAddress + targetAddressOffset);
                addPredecessorSuccessor(instruction, targetInstruction, exceptionHandlers, instructionsToProcess);
            }
        }
    }
}
Also used : BitSet(java.util.BitSet) Opcode(org.jf.dexlib2.Opcode)

Example 20 with ExceptionHandler

use of org.jf.dexlib2.iface.ExceptionHandler in project smali by JesusFreke.

the class DexWriter method writeCodeItem.

private int writeCodeItem(@Nonnull DexDataWriter writer, @Nonnull ByteArrayOutputStream ehBuf, @Nonnull MethodKey methodKey, @Nonnull List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks, @Nullable Iterable<? extends Instruction> instructions, int debugItemOffset) throws IOException {
    if (instructions == null && debugItemOffset == NO_OFFSET) {
        return -1;
    }
    numCodeItemItems++;
    writer.align();
    int codeItemOffset = writer.getPosition();
    writer.writeUshort(classSection.getRegisterCount(methodKey));
    boolean isStatic = AccessFlags.STATIC.isSet(classSection.getMethodAccessFlags(methodKey));
    Collection<? extends TypeKey> parameters = typeListSection.getTypes(protoSection.getParameters(methodSection.getPrototype(methodKey)));
    writer.writeUshort(MethodUtil.getParameterRegisterCount(parameters, isStatic));
    if (instructions != null) {
        tryBlocks = TryListBuilder.massageTryBlocks(tryBlocks);
        int outParamCount = 0;
        int codeUnitCount = 0;
        for (Instruction instruction : instructions) {
            codeUnitCount += instruction.getCodeUnits();
            if (instruction.getOpcode().referenceType == ReferenceType.METHOD) {
                ReferenceInstruction refInsn = (ReferenceInstruction) instruction;
                MethodReference methodRef = (MethodReference) refInsn.getReference();
                int paramCount = MethodUtil.getParameterRegisterCount(methodRef, InstructionUtil.isInvokeStatic(instruction.getOpcode()));
                if (paramCount > outParamCount) {
                    outParamCount = paramCount;
                }
            }
        }
        writer.writeUshort(outParamCount);
        writer.writeUshort(tryBlocks.size());
        writer.writeInt(debugItemOffset);
        InstructionWriter instructionWriter = InstructionWriter.makeInstructionWriter(opcodes, writer, stringSection, typeSection, fieldSection, methodSection, protoSection);
        writer.writeInt(codeUnitCount);
        int codeOffset = 0;
        for (Instruction instruction : instructions) {
            try {
                switch(instruction.getOpcode().format) {
                    case Format10t:
                        instructionWriter.write((Instruction10t) instruction);
                        break;
                    case Format10x:
                        instructionWriter.write((Instruction10x) instruction);
                        break;
                    case Format11n:
                        instructionWriter.write((Instruction11n) instruction);
                        break;
                    case Format11x:
                        instructionWriter.write((Instruction11x) instruction);
                        break;
                    case Format12x:
                        instructionWriter.write((Instruction12x) instruction);
                        break;
                    case Format20bc:
                        instructionWriter.write((Instruction20bc) instruction);
                        break;
                    case Format20t:
                        instructionWriter.write((Instruction20t) instruction);
                        break;
                    case Format21c:
                        instructionWriter.write((Instruction21c) instruction);
                        break;
                    case Format21ih:
                        instructionWriter.write((Instruction21ih) instruction);
                        break;
                    case Format21lh:
                        instructionWriter.write((Instruction21lh) instruction);
                        break;
                    case Format21s:
                        instructionWriter.write((Instruction21s) instruction);
                        break;
                    case Format21t:
                        instructionWriter.write((Instruction21t) instruction);
                        break;
                    case Format22b:
                        instructionWriter.write((Instruction22b) instruction);
                        break;
                    case Format22c:
                        instructionWriter.write((Instruction22c) instruction);
                        break;
                    case Format22s:
                        instructionWriter.write((Instruction22s) instruction);
                        break;
                    case Format22t:
                        instructionWriter.write((Instruction22t) instruction);
                        break;
                    case Format22x:
                        instructionWriter.write((Instruction22x) instruction);
                        break;
                    case Format23x:
                        instructionWriter.write((Instruction23x) instruction);
                        break;
                    case Format30t:
                        instructionWriter.write((Instruction30t) instruction);
                        break;
                    case Format31c:
                        instructionWriter.write((Instruction31c) instruction);
                        break;
                    case Format31i:
                        instructionWriter.write((Instruction31i) instruction);
                        break;
                    case Format31t:
                        instructionWriter.write((Instruction31t) instruction);
                        break;
                    case Format32x:
                        instructionWriter.write((Instruction32x) instruction);
                        break;
                    case Format35c:
                        instructionWriter.write((Instruction35c) instruction);
                        break;
                    case Format3rc:
                        instructionWriter.write((Instruction3rc) instruction);
                        break;
                    case Format45cc:
                        instructionWriter.write((Instruction45cc) instruction);
                        break;
                    case Format4rcc:
                        instructionWriter.write((Instruction4rcc) instruction);
                        break;
                    case Format51l:
                        instructionWriter.write((Instruction51l) instruction);
                        break;
                    case ArrayPayload:
                        instructionWriter.write((ArrayPayload) instruction);
                        break;
                    case PackedSwitchPayload:
                        instructionWriter.write((PackedSwitchPayload) instruction);
                        break;
                    case SparseSwitchPayload:
                        instructionWriter.write((SparseSwitchPayload) instruction);
                        break;
                    default:
                        throw new ExceptionWithContext("Unsupported instruction format: %s", instruction.getOpcode().format);
                }
            } catch (RuntimeException ex) {
                throw new ExceptionWithContext(ex, "Error while writing instruction at code offset 0x%x", codeOffset);
            }
            codeOffset += instruction.getCodeUnits();
        }
        if (tryBlocks.size() > 0) {
            writer.align();
            // filter out unique lists of exception handlers
            Map<List<? extends ExceptionHandler>, Integer> exceptionHandlerOffsetMap = Maps.newHashMap();
            for (TryBlock<? extends ExceptionHandler> tryBlock : tryBlocks) {
                exceptionHandlerOffsetMap.put(tryBlock.getExceptionHandlers(), 0);
            }
            DexDataWriter.writeUleb128(ehBuf, exceptionHandlerOffsetMap.size());
            for (TryBlock<? extends ExceptionHandler> tryBlock : tryBlocks) {
                int startAddress = tryBlock.getStartCodeAddress();
                int endAddress = startAddress + tryBlock.getCodeUnitCount();
                int tbCodeUnitCount = endAddress - startAddress;
                writer.writeInt(startAddress);
                writer.writeUshort(tbCodeUnitCount);
                if (tryBlock.getExceptionHandlers().size() == 0) {
                    throw new ExceptionWithContext("No exception handlers for the try block!");
                }
                Integer offset = exceptionHandlerOffsetMap.get(tryBlock.getExceptionHandlers());
                if (offset != 0) {
                    // exception handler has already been written out, just use it
                    writer.writeUshort(offset);
                } else {
                    // if offset has not been set yet, we are about to write out a new exception handler
                    offset = ehBuf.size();
                    writer.writeUshort(offset);
                    exceptionHandlerOffsetMap.put(tryBlock.getExceptionHandlers(), offset);
                    // check if the last exception handler is a catch-all and adjust the size accordingly
                    int ehSize = tryBlock.getExceptionHandlers().size();
                    ExceptionHandler ehLast = tryBlock.getExceptionHandlers().get(ehSize - 1);
                    if (ehLast.getExceptionType() == null) {
                        ehSize = ehSize * (-1) + 1;
                    }
                    // now let's layout the exception handlers, assuming that catch-all is always last
                    DexDataWriter.writeSleb128(ehBuf, ehSize);
                    for (ExceptionHandler eh : tryBlock.getExceptionHandlers()) {
                        TypeKey exceptionTypeKey = classSection.getExceptionType(eh);
                        int codeAddress = eh.getHandlerCodeAddress();
                        if (exceptionTypeKey != null) {
                            //regular exception handling
                            DexDataWriter.writeUleb128(ehBuf, typeSection.getItemIndex(exceptionTypeKey));
                            DexDataWriter.writeUleb128(ehBuf, codeAddress);
                        } else {
                            //catch-all
                            DexDataWriter.writeUleb128(ehBuf, codeAddress);
                        }
                    }
                }
            }
            if (ehBuf.size() > 0) {
                ehBuf.writeTo(writer);
                ehBuf.reset();
            }
        }
    } else {
        // no instructions, all we have is the debug item offset
        writer.writeUshort(0);
        writer.writeUshort(0);
        writer.writeInt(debugItemOffset);
        writer.writeInt(0);
    }
    return codeItemOffset;
}
Also used : ReferenceInstruction(org.jf.dexlib2.iface.instruction.ReferenceInstruction) OneRegisterInstruction(org.jf.dexlib2.iface.instruction.OneRegisterInstruction) Instruction(org.jf.dexlib2.iface.instruction.Instruction) ReferenceInstruction(org.jf.dexlib2.iface.instruction.ReferenceInstruction) ExceptionHandler(org.jf.dexlib2.iface.ExceptionHandler) ExceptionWithContext(org.jf.util.ExceptionWithContext)

Aggregations

Test (org.junit.Test)26 ImmutableExceptionHandler (org.jf.dexlib2.immutable.ImmutableExceptionHandler)24 ImmutableTryBlock (org.jf.dexlib2.immutable.ImmutableTryBlock)24 Instruction (org.jf.dexlib2.iface.instruction.Instruction)5 ReferenceInstruction (org.jf.dexlib2.iface.instruction.ReferenceInstruction)4 ExceptionWithContext (org.jf.util.ExceptionWithContext)4 ExceptionHandler (org.jf.dexlib2.iface.ExceptionHandler)3 Opcode (org.jf.dexlib2.Opcode)2 MutableMethodImplementation (org.jf.dexlib2.builder.MutableMethodImplementation)2 MethodImplementation (org.jf.dexlib2.iface.MethodImplementation)2 OneRegisterInstruction (org.jf.dexlib2.iface.instruction.OneRegisterInstruction)2 SmaliMethod (org.jf.smalidea.psi.impl.SmaliMethod)2 ByteArrayOutputStream (java.io.ByteArrayOutputStream)1 BitSet (java.util.BitSet)1 Nonnull (javax.annotation.Nonnull)1 Nullable (org.jetbrains.annotations.Nullable)1 BuilderInstruction10t (org.jf.dexlib2.builder.instruction.BuilderInstruction10t)1 BuilderInstruction10x (org.jf.dexlib2.builder.instruction.BuilderInstruction10x)1 BuilderInstruction21c (org.jf.dexlib2.builder.instruction.BuilderInstruction21c)1 DexBackedDexFile (org.jf.dexlib2.dexbacked.DexBackedDexFile)1