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);
}
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);
}
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);
}
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);
}
}
}
}
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;
}
Aggregations