use of org.jf.dexlib2.iface.instruction.formats.ArrayPayload in project smali by JesusFreke.
the class CodeItem method makeAnnotator.
@Nonnull
public static SectionAnnotator makeAnnotator(@Nonnull DexAnnotator annotator, @Nonnull MapItem mapItem) {
return new SectionAnnotator(annotator, mapItem) {
private SectionAnnotator debugInfoAnnotator = null;
@Override
public void annotateSection(@Nonnull AnnotatedBytes out) {
debugInfoAnnotator = annotator.getAnnotator(ItemType.DEBUG_INFO_ITEM);
super.annotateSection(out);
}
@Nonnull
@Override
public String getItemName() {
return "code_item";
}
@Override
public int getItemAlignment() {
return 4;
}
@Override
public void annotateItem(@Nonnull AnnotatedBytes out, int itemIndex, @Nullable String itemIdentity) {
try {
DexReader reader = dexFile.readerAt(out.getCursor());
int registers = reader.readUshort();
out.annotate(2, "registers_size = %d", registers);
int inSize = reader.readUshort();
out.annotate(2, "ins_size = %d", inSize);
int outSize = reader.readUshort();
out.annotate(2, "outs_size = %d", outSize);
int triesCount = reader.readUshort();
out.annotate(2, "tries_size = %d", triesCount);
int debugInfoOffset = reader.readInt();
out.annotate(4, "debug_info_off = 0x%x", debugInfoOffset);
if (debugInfoOffset > 0) {
addDebugInfoIdentity(debugInfoOffset, itemIdentity);
}
int instructionSize = reader.readSmallUint();
out.annotate(4, "insns_size = 0x%x", instructionSize);
out.annotate(0, "instructions:");
out.indent();
out.setLimit(out.getCursor(), out.getCursor() + instructionSize * 2);
int end = reader.getOffset() + instructionSize * 2;
try {
while (reader.getOffset() < end) {
Instruction instruction = DexBackedInstruction.readFrom(reader);
// if we read past the end of the instruction list
if (reader.getOffset() > end) {
out.annotateTo(end, "truncated instruction");
reader.setOffset(end);
} else {
switch(instruction.getOpcode().format) {
case Format10x:
annotateInstruction10x(out, instruction);
break;
case Format35c:
annotateInstruction35c(out, (Instruction35c) instruction);
break;
case Format3rc:
annotateInstruction3rc(out, (Instruction3rc) instruction);
break;
case ArrayPayload:
annotateArrayPayload(out, (ArrayPayload) instruction);
break;
case PackedSwitchPayload:
annotatePackedSwitchPayload(out, (PackedSwitchPayload) instruction);
break;
case SparseSwitchPayload:
annotateSparseSwitchPayload(out, (SparseSwitchPayload) instruction);
break;
default:
annotateDefaultInstruction(out, instruction);
break;
}
}
assert reader.getOffset() == out.getCursor();
}
} catch (ExceptionWithContext ex) {
ex.printStackTrace(System.err);
out.annotate(0, "annotation error: %s", ex.getMessage());
out.moveTo(end);
reader.setOffset(end);
} finally {
out.clearLimit();
out.deindent();
}
if (triesCount > 0) {
if ((reader.getOffset() % 4) != 0) {
reader.readUshort();
out.annotate(2, "padding");
}
out.annotate(0, "try_items:");
out.indent();
try {
for (int i = 0; i < triesCount; i++) {
out.annotate(0, "try_item[%d]:", i);
out.indent();
try {
int startAddr = reader.readSmallUint();
out.annotate(4, "start_addr = 0x%x", startAddr);
int instructionCount = reader.readUshort();
out.annotate(2, "insn_count = 0x%x", instructionCount);
int handlerOffset = reader.readUshort();
out.annotate(2, "handler_off = 0x%x", handlerOffset);
} finally {
out.deindent();
}
}
} finally {
out.deindent();
}
int handlerListCount = reader.readSmallUleb128();
out.annotate(0, "encoded_catch_handler_list:");
out.annotateTo(reader.getOffset(), "size = %d", handlerListCount);
out.indent();
try {
for (int i = 0; i < handlerListCount; i++) {
out.annotate(0, "encoded_catch_handler[%d]", i);
out.indent();
try {
int handlerCount = reader.readSleb128();
out.annotateTo(reader.getOffset(), "size = %d", handlerCount);
boolean hasCatchAll = handlerCount <= 0;
handlerCount = Math.abs(handlerCount);
if (handlerCount != 0) {
out.annotate(0, "handlers:");
out.indent();
try {
for (int j = 0; j < handlerCount; j++) {
out.annotate(0, "encoded_type_addr_pair[%d]", i);
out.indent();
try {
int typeIndex = reader.readSmallUleb128();
out.annotateTo(reader.getOffset(), TypeIdItem.getReferenceAnnotation(dexFile, typeIndex));
int handlerAddress = reader.readSmallUleb128();
out.annotateTo(reader.getOffset(), "addr = 0x%x", handlerAddress);
} finally {
out.deindent();
}
}
} finally {
out.deindent();
}
}
if (hasCatchAll) {
int catchAllAddress = reader.readSmallUleb128();
out.annotateTo(reader.getOffset(), "catch_all_addr = 0x%x", catchAllAddress);
}
} finally {
out.deindent();
}
}
} finally {
out.deindent();
}
}
} catch (ExceptionWithContext ex) {
out.annotate(0, "annotation error: %s", ex.getMessage());
}
}
private String formatRegister(int registerNum) {
return String.format("v%d", registerNum);
}
private void annotateInstruction10x(@Nonnull AnnotatedBytes out, @Nonnull Instruction instruction) {
out.annotate(2, instruction.getOpcode().name);
}
private void annotateInstruction35c(@Nonnull AnnotatedBytes out, @Nonnull Instruction35c instruction) {
List<String> args = Lists.newArrayList();
int registerCount = instruction.getRegisterCount();
if (registerCount == 1) {
args.add(formatRegister(instruction.getRegisterC()));
} else if (registerCount == 2) {
args.add(formatRegister(instruction.getRegisterC()));
args.add(formatRegister(instruction.getRegisterD()));
} else if (registerCount == 3) {
args.add(formatRegister(instruction.getRegisterC()));
args.add(formatRegister(instruction.getRegisterD()));
args.add(formatRegister(instruction.getRegisterE()));
} else if (registerCount == 4) {
args.add(formatRegister(instruction.getRegisterC()));
args.add(formatRegister(instruction.getRegisterD()));
args.add(formatRegister(instruction.getRegisterE()));
args.add(formatRegister(instruction.getRegisterF()));
} else if (registerCount == 5) {
args.add(formatRegister(instruction.getRegisterC()));
args.add(formatRegister(instruction.getRegisterD()));
args.add(formatRegister(instruction.getRegisterE()));
args.add(formatRegister(instruction.getRegisterF()));
args.add(formatRegister(instruction.getRegisterG()));
}
String reference = ReferenceUtil.getReferenceString(instruction.getReference());
out.annotate(6, String.format("%s {%s}, %s", instruction.getOpcode().name, Joiner.on(", ").join(args), reference));
}
private void annotateInstruction3rc(@Nonnull AnnotatedBytes out, @Nonnull Instruction3rc instruction) {
int startRegister = instruction.getStartRegister();
int endRegister = startRegister + instruction.getRegisterCount() - 1;
String reference = ReferenceUtil.getReferenceString(instruction.getReference());
out.annotate(6, String.format("%s {%s .. %s}, %s", instruction.getOpcode().name, formatRegister(startRegister), formatRegister(endRegister), reference));
}
private void annotateDefaultInstruction(@Nonnull AnnotatedBytes out, @Nonnull Instruction instruction) {
List<String> args = Lists.newArrayList();
if (instruction instanceof OneRegisterInstruction) {
args.add(formatRegister(((OneRegisterInstruction) instruction).getRegisterA()));
if (instruction instanceof TwoRegisterInstruction) {
args.add(formatRegister(((TwoRegisterInstruction) instruction).getRegisterB()));
if (instruction instanceof ThreeRegisterInstruction) {
args.add(formatRegister(((ThreeRegisterInstruction) instruction).getRegisterC()));
}
}
} else if (instruction instanceof VerificationErrorInstruction) {
String verificationError = VerificationError.getVerificationErrorName(((VerificationErrorInstruction) instruction).getVerificationError());
if (verificationError != null) {
args.add(verificationError);
} else {
args.add("invalid verification error type");
}
}
if (instruction instanceof ReferenceInstruction) {
args.add(ReferenceUtil.getReferenceString(((ReferenceInstruction) instruction).getReference()));
} else if (instruction instanceof OffsetInstruction) {
int offset = ((OffsetInstruction) instruction).getCodeOffset();
String sign = offset >= 0 ? "+" : "-";
args.add(String.format("%s0x%x", sign, Math.abs(offset)));
} else if (instruction instanceof NarrowLiteralInstruction) {
int value = ((NarrowLiteralInstruction) instruction).getNarrowLiteral();
if (NumberUtils.isLikelyFloat(value)) {
args.add(String.format("%d # %f", value, Float.intBitsToFloat(value)));
} else {
args.add(String.format("%d", value));
}
} else if (instruction instanceof WideLiteralInstruction) {
long value = ((WideLiteralInstruction) instruction).getWideLiteral();
if (NumberUtils.isLikelyDouble(value)) {
args.add(String.format("%d # %f", value, Double.longBitsToDouble(value)));
} else {
args.add(String.format("%d", value));
}
} else if (instruction instanceof FieldOffsetInstruction) {
int fieldOffset = ((FieldOffsetInstruction) instruction).getFieldOffset();
args.add(String.format("field@0x%x", fieldOffset));
} else if (instruction instanceof VtableIndexInstruction) {
int vtableIndex = ((VtableIndexInstruction) instruction).getVtableIndex();
args.add(String.format("vtable@%d", vtableIndex));
} else if (instruction instanceof InlineIndexInstruction) {
int inlineIndex = ((InlineIndexInstruction) instruction).getInlineIndex();
args.add(String.format("inline@%d", inlineIndex));
}
out.annotate(instruction.getCodeUnits() * 2, "%s %s", instruction.getOpcode().name, Joiner.on(", ").join(args));
}
private void annotateArrayPayload(@Nonnull AnnotatedBytes out, @Nonnull ArrayPayload instruction) {
List<Number> elements = instruction.getArrayElements();
int elementWidth = instruction.getElementWidth();
out.annotate(2, instruction.getOpcode().name);
out.indent();
out.annotate(2, "element_width = %d", elementWidth);
out.annotate(4, "size = %d", elements.size());
out.annotate(0, "elements:");
out.indent();
for (int i = 0; i < elements.size(); i++) {
if (elementWidth == 8) {
long value = elements.get(i).longValue();
if (NumberUtils.isLikelyDouble(value)) {
out.annotate(elementWidth, "element[%d] = %d # %f", i, value, Double.longBitsToDouble(value));
} else {
out.annotate(elementWidth, "element[%d] = %d", i, value);
}
} else {
int value = elements.get(i).intValue();
if (NumberUtils.isLikelyFloat(value)) {
out.annotate(elementWidth, "element[%d] = %d # %f", i, value, Float.intBitsToFloat(value));
} else {
out.annotate(elementWidth, "element[%d] = %d", i, value);
}
}
}
if (out.getCursor() % 2 != 0) {
out.annotate(1, "padding");
}
out.deindent();
out.deindent();
}
private void annotatePackedSwitchPayload(@Nonnull AnnotatedBytes out, @Nonnull PackedSwitchPayload instruction) {
List<? extends SwitchElement> elements = instruction.getSwitchElements();
out.annotate(2, instruction.getOpcode().name);
out.indent();
out.annotate(2, "size = %d", elements.size());
if (elements.size() == 0) {
out.annotate(4, "first_key");
} else {
out.annotate(4, "first_key = %d", elements.get(0).getKey());
out.annotate(0, "targets:");
out.indent();
for (int i = 0; i < elements.size(); i++) {
out.annotate(4, "target[%d] = %d", i, elements.get(i).getOffset());
}
out.deindent();
}
out.deindent();
}
private void annotateSparseSwitchPayload(@Nonnull AnnotatedBytes out, @Nonnull SparseSwitchPayload instruction) {
List<? extends SwitchElement> elements = instruction.getSwitchElements();
out.annotate(2, instruction.getOpcode().name);
out.indent();
out.annotate(2, "size = %d", elements.size());
if (elements.size() > 0) {
out.annotate(0, "keys:");
out.indent();
for (int i = 0; i < elements.size(); i++) {
out.annotate(4, "key[%d] = %d", i, elements.get(i).getKey());
}
out.deindent();
out.annotate(0, "targets:");
out.indent();
for (int i = 0; i < elements.size(); i++) {
out.annotate(4, "target[%d] = %d", i, elements.get(i).getOffset());
}
out.deindent();
}
out.deindent();
}
private void addDebugInfoIdentity(int debugInfoOffset, String methodString) {
if (debugInfoAnnotator != null) {
debugInfoAnnotator.setItemIdentity(debugInfoOffset, methodString);
}
}
};
}
use of org.jf.dexlib2.iface.instruction.formats.ArrayPayload in project smali by JesusFreke.
the class SmalideaMethodTest method testArrayData.
public void testArrayData() {
String text = ".class public LFormat31t;\n" + ".super Ljava/lang/Object;\n" + ".source \"Format31t.smali\"" + "\n" + ".method public test_fill-array-data()V\n" + " .registers 3\n" + " .annotation runtime Lorg/junit/Test;\n" + " .end annotation\n" + "\n" + " const v0, 6\n" + " new-array v0, v0, [I\n" + " fill-array-data v0, :ArrayData\n" + "\n" + " const v1, 0\n" + " aget v2, v0, v1\n" + " const v1, 1\n" + " invoke-static {v1, v2}, LAssert;->assertEquals(II)V\n" + "\n" + " const v1, 1\n" + " aget v2, v0, v1\n" + " const v1, 2\n" + " invoke-static {v1, v2}, LAssert;->assertEquals(II)V\n" + "\n" + " const v1, 2\n" + " aget v2, v0, v1\n" + " const v1, 3\n" + " invoke-static {v1, v2}, LAssert;->assertEquals(II)V\n" + "\n" + " const v1, 3\n" + " aget v2, v0, v1\n" + " const v1, 4\n" + " invoke-static {v1, v2}, LAssert;->assertEquals(II)V\n" + "\n" + " const v1, 4\n" + " aget v2, v0, v1\n" + " const v1, 5\n" + " invoke-static {v1, v2}, LAssert;->assertEquals(II)V\n" + "\n" + " const v1, 5\n" + " aget v2, v0, v1\n" + " const v1, 6\n" + " invoke-static {v1, v2}, LAssert;->assertEquals(II)V\n" + "\n" + " return-void\n" + "\n" + ":ArrayData\n" + " .array-data 4\n" + " 1 2 128 -256 65536 0x7fffffff\n" + " .end array-data\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());
ArrayPayload arrayPayload = (ArrayPayload) instructions.get(28);
Assert.assertEquals(4, arrayPayload.getElementWidth());
List<Number> elements = arrayPayload.getArrayElements();
Assert.assertEquals(6, elements.size());
Assert.assertEquals(1L, elements.get(0).longValue());
Assert.assertEquals(2L, elements.get(1).longValue());
Assert.assertEquals(128L, elements.get(2));
Assert.assertEquals(-256L, elements.get(3));
Assert.assertEquals(65536L, elements.get(4));
Assert.assertEquals(0x7fffffffL, elements.get(5));
}
use of org.jf.dexlib2.iface.instruction.formats.ArrayPayload in project soot by Sable.
the class FillArrayDataInstruction method jimplify.
@Override
public void jimplify(DexBody body) {
if (!(instruction instanceof Instruction31t))
throw new IllegalArgumentException("Expected Instruction31t but got: " + instruction.getClass());
Instruction31t fillArrayInstr = (Instruction31t) instruction;
int destRegister = fillArrayInstr.getRegisterA();
int offset = fillArrayInstr.getCodeOffset();
int targetAddress = codeAddress + offset;
Instruction referenceTable = body.instructionAtAddress(targetAddress).instruction;
if (!(referenceTable instanceof ArrayPayload)) {
throw new RuntimeException("Address " + targetAddress + "refers to an invalid PseudoInstruction.");
}
ArrayPayload arrayTable = (ArrayPayload) referenceTable;
// NopStmt nopStmtBeginning = Jimple.v().newNopStmt();
// body.add(nopStmtBeginning);
Local arrayReference = body.getRegisterLocal(destRegister);
List<Number> elements = arrayTable.getArrayElements();
int numElements = elements.size();
Stmt firstAssign = null;
for (int i = 0; i < numElements; i++) {
ArrayRef arrayRef = Jimple.v().newArrayRef(arrayReference, IntConstant.v(i));
NumericConstant element = getArrayElement(elements.get(i), body, destRegister);
if (// array was not defined -> element type can not be found (obfuscated bytecode?)
element == null)
break;
AssignStmt assign = Jimple.v().newAssignStmt(arrayRef, element);
addTags(assign);
body.add(assign);
if (i == 0) {
firstAssign = assign;
}
}
if (firstAssign == null) {
// if numElements == 0. Is it possible?
firstAssign = Jimple.v().newNopStmt();
body.add(firstAssign);
}
// NopStmt nopStmtEnd = Jimple.v().newNopStmt();
// body.add(nopStmtEnd);
// defineBlock(nopStmtBeginning, nopStmtEnd);
setUnit(firstAssign);
}
use of org.jf.dexlib2.iface.instruction.formats.ArrayPayload in project soot by Sable.
the class FillArrayDataInstruction method computeDataOffsets.
@Override
public void computeDataOffsets(DexBody body) {
if (!(instruction instanceof Instruction31t))
throw new IllegalArgumentException("Expected Instruction31t but got: " + instruction.getClass());
Instruction31t fillArrayInstr = (Instruction31t) instruction;
int offset = fillArrayInstr.getCodeOffset();
int targetAddress = codeAddress + offset;
Instruction referenceTable = body.instructionAtAddress(targetAddress).instruction;
if (!(referenceTable instanceof ArrayPayload)) {
throw new RuntimeException("Address 0x" + Integer.toHexString(targetAddress) + " refers to an invalid PseudoInstruction (" + referenceTable.getClass() + ").");
}
ArrayPayload arrayTable = (ArrayPayload) referenceTable;
int numElements = arrayTable.getArrayElements().size();
int widthElement = arrayTable.getElementWidth();
// addresses are on 16bits
int size = (widthElement * numElements) / 2;
// From org.jf.dexlib.Code.Format.ArrayDataPseudoInstruction we learn
// that there are 6 bytes after the magic number that we have to jump.
// 6 bytes to jump = address + 3
//
// out.writeByte(0x00); // magic
// out.writeByte(0x03); // number
// out.writeShort(elementWidth); // 2 bytes
// out.writeInt(elementCount); // 4 bytes
// out.write(encodedValues);
//
// address for 16 bits elements not 8 bits
setDataFirstByte(targetAddress + 3);
// - 1);
setDataLastByte(targetAddress + 3 + size);
setDataSize(size);
// TODO: how to handle this with dexlib2 ?
// ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
// arrayTable.write(out, targetAddress);
//
// byte[] outa = out.getArray();
// byte[] data = new byte[outa.length-6];
// for (int i=6; i<outa.length; i++) {
// data[i-6] = outa[i];
// }
// setData (data);
}
use of org.jf.dexlib2.iface.instruction.formats.ArrayPayload 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();
Opcode opcode = instruction.getOpcode();
int paramCount;
if (InstructionUtil.isInvokePolymorphic(opcode)) {
paramCount = ((VariableRegisterInstruction) instruction).getRegisterCount();
} else {
paramCount = MethodUtil.getParameterRegisterCount(methodRef, InstructionUtil.isInvokeStatic(opcode));
}
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, methodHandleSection, callSiteSection);
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 Format22cs:
instructionWriter.write((Instruction22cs) 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 Format35mi:
instructionWriter.write((Instruction35mi) instruction);
break;
case Format35ms:
instructionWriter.write((Instruction35ms) instruction);
break;
case Format3rc:
instructionWriter.write((Instruction3rc) instruction);
break;
case Format3rmi:
instructionWriter.write((Instruction3rmi) instruction);
break;
case Format3rms:
instructionWriter.write((Instruction3rms) 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