Search in sources :

Example 6 with SwitchElement

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

the class MutableMethodImplementation method newBuilderPackedSwitchPayload.

@Nonnull
private BuilderPackedSwitchPayload newBuilderPackedSwitchPayload(@Nonnull MethodLocation location, @Nonnull int[] codeAddressToIndex, @Nonnull PackedSwitchPayload instruction) {
    List<? extends SwitchElement> switchElements = instruction.getSwitchElements();
    if (switchElements.size() == 0) {
        return new BuilderPackedSwitchPayload(0, null);
    }
    MethodLocation switchLocation = findSwitchForPayload(location);
    int baseAddress;
    if (switchLocation == null) {
        baseAddress = 0;
    } else {
        baseAddress = switchLocation.codeAddress;
    }
    List<Label> labels = Lists.newArrayList();
    for (SwitchElement element : switchElements) {
        labels.add(newLabel(codeAddressToIndex, element.getOffset() + baseAddress));
    }
    return new BuilderPackedSwitchPayload(switchElements.get(0).getKey(), labels);
}
Also used : SwitchElement(org.jf.dexlib2.iface.instruction.SwitchElement) Nonnull(javax.annotation.Nonnull)

Example 7 with SwitchElement

use of org.jf.dexlib2.iface.instruction.SwitchElement 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 8 with SwitchElement

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

the class InstructionWriter method write.

public void write(@Nonnull PackedSwitchPayload instruction) {
    try {
        writer.writeUbyte(0);
        writer.writeUbyte(getOpcodeValue(instruction.getOpcode()) >> 8);
        List<? extends SwitchElement> elements = instruction.getSwitchElements();
        writer.writeUshort(elements.size());
        if (elements.size() == 0) {
            writer.writeInt(0);
        } else {
            writer.writeInt(elements.get(0).getKey());
            for (SwitchElement element : elements) {
                writer.writeInt(element.getOffset());
            }
        }
    } catch (IOException ex) {
        throw new RuntimeException(ex);
    }
}
Also used : SwitchElement(org.jf.dexlib2.iface.instruction.SwitchElement) IOException(java.io.IOException)

Example 9 with SwitchElement

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

the class InstructionWriter method write.

public void write(@Nonnull SparseSwitchPayload instruction) {
    try {
        writer.writeUbyte(0);
        writer.writeUbyte(getOpcodeValue(instruction.getOpcode()) >> 8);
        List<? extends SwitchElement> elements = Ordering.from(switchElementComparator).immutableSortedCopy(instruction.getSwitchElements());
        writer.writeUshort(elements.size());
        for (SwitchElement element : elements) {
            writer.writeInt(element.getKey());
        }
        for (SwitchElement element : elements) {
            writer.writeInt(element.getOffset());
        }
    } catch (IOException ex) {
        throw new RuntimeException(ex);
    }
}
Also used : SwitchElement(org.jf.dexlib2.iface.instruction.SwitchElement) IOException(java.io.IOException)

Example 10 with SwitchElement

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

the class SmalideaMethodTest method testPackedSwitch.

public void testPackedSwitch() {
    String text = ".class public LFormat31t;\n" + ".super Ljava/lang/Object;\n" + ".source \"Format31t.smali\"" + "\n" + ".method public test_packed-switch()V\n" + "    .registers 1\n" + "    .annotation runtime Lorg/junit/Test;\n" + "    .end annotation\n" + "\n" + "    const v0, 12\n" + "\n" + ":switch\n" + "    packed-switch v0, :PackedSwitch\n" + "\n" + ":Label10\n" + "    invoke-static {}, Lorg/junit/Assert;->fail()V\n" + "    return-void\n" + "\n" + ":Label11\n" + "    invoke-static {}, Lorg/junit/Assert;->fail()V\n" + "    return-void\n" + "\n" + ":Label12\n" + "    return-void\n" + "\n" + ":Label13\n" + "    invoke-static {}, Lorg/junit/Assert;->fail()V\n" + "    return-void\n" + "\n" + ":PackedSwitch\n" + "    .packed-switch 10\n" + "        :Label10\n" + "        :Label11\n" + "        :Label12\n" + "        :Label13\n" + "    .end packed-switch\n" + ".end method";
    SmaliFile file = (SmaliFile) myFixture.addFileToProject("my/pkg/blah.smali", text);
    SmaliClass smaliClass = file.getPsiClass();
    SmaliMethod smaliMethod = smaliClass.getMethods()[0];
    SmalideaMethod method = new SmalideaMethod(smaliMethod);
    MethodImplementation impl = method.getImplementation();
    Assert.assertNotNull(impl);
    List<Instruction> instructions = Lists.newArrayList(impl.getInstructions());
    PackedSwitchPayload packedSwitchPayload = (PackedSwitchPayload) instructions.get(9);
    List<? extends SwitchElement> switchElements = packedSwitchPayload.getSwitchElements();
    Assert.assertEquals(4, switchElements.size());
    checkSwitchElement(switchElements.get(0), 10, 6);
    checkSwitchElement(switchElements.get(1), 11, 14);
    checkSwitchElement(switchElements.get(2), 12, 22);
    checkSwitchElement(switchElements.get(3), 13, 24);
}
Also used : SmaliFile(org.jf.smalidea.psi.impl.SmaliFile) MethodImplementation(org.jf.dexlib2.iface.MethodImplementation) SmaliClass(org.jf.smalidea.psi.impl.SmaliClass) SmaliMethod(org.jf.smalidea.psi.impl.SmaliMethod) Instruction(org.jf.dexlib2.iface.instruction.Instruction)

Aggregations

SwitchElement (org.jf.dexlib2.iface.instruction.SwitchElement)6 Nonnull (javax.annotation.Nonnull)5 IOException (java.io.IOException)2 MethodImplementation (org.jf.dexlib2.iface.MethodImplementation)2 Instruction (org.jf.dexlib2.iface.instruction.Instruction)2 SmaliClass (org.jf.smalidea.psi.impl.SmaliClass)2 SmaliFile (org.jf.smalidea.psi.impl.SmaliFile)2 SmaliMethod (org.jf.smalidea.psi.impl.SmaliMethod)2 BitSet (java.util.BitSet)1 Nullable (javax.annotation.Nullable)1 Opcode (org.jf.dexlib2.Opcode)1 DexReader (org.jf.dexlib2.dexbacked.DexReader)1 DexBackedInstruction (org.jf.dexlib2.dexbacked.instruction.DexBackedInstruction)1 AnnotatedBytes (org.jf.dexlib2.util.AnnotatedBytes)1 ExceptionWithContext (org.jf.util.ExceptionWithContext)1