private boolean isAllowedOdex(@Nonnull Opcode opcode) { baksmaliOptions options = methodDef.classDef.options; if (options.allowOdex) { return true; } if (methodDef.classDef.options.apiLevel >= 14) { return false; } return opcode.isOdexedInstanceVolatile() || opcode.isOdexedStaticVolatile() || opcode == Opcode.THROW_VERIFICATION_ERROR; }
@Override public boolean writeTo(IndentingWriter writer) throws IOException { Opcode opcode = instruction.getOpcode(); String verificationErrorName = null; String referenceString = null; boolean commentOutInstruction = false; if (instruction instanceof Instruction20bc) { int verificationError = ((Instruction20bc) instruction).getVerificationError(); verificationErrorName = VerificationError.getVerificationErrorName(verificationError); if (verificationErrorName == null) { writer.write("#was invalid verification error type: "); writer.printSignedIntAsDec(verificationError); writer.write("\n"); verificationErrorName = "generic-error"; } } if (instruction instanceof ReferenceInstruction) { ReferenceInstruction referenceInstruction = (ReferenceInstruction) instruction; try { Reference reference = referenceInstruction.getReference(); String classContext = null; if (methodDef.classDef.options.useImplicitReferences) { classContext = methodDef.method.getDefiningClass(); } referenceString = ReferenceUtil.getReferenceString(reference, classContext); assert referenceString != null; } catch (InvalidItemIndex ex) { writer.write("#"); writer.write(ex.getMessage()); writer.write("\n"); commentOutInstruction = true; referenceString = String.format( "%s@%d", ReferenceType.toString(referenceInstruction.getReferenceType()), ex.getInvalidIndex()); } catch (ReferenceType.InvalidReferenceTypeException ex) { writer.write("#invalid reference type: "); writer.printSignedIntAsDec(ex.getReferenceType()); commentOutInstruction = true; referenceString = "invalid_reference"; } } if (instruction instanceof Instruction31t) { boolean validPayload = true; switch (instruction.getOpcode()) { case PACKED_SWITCH: int baseAddress = methodDef.getPackedSwitchBaseAddress( this.codeAddress + ((Instruction31t) instruction).getCodeOffset()); if (baseAddress == -1) { validPayload = false; } break; case SPARSE_SWITCH: baseAddress = methodDef.getSparseSwitchBaseAddress( this.codeAddress + ((Instruction31t) instruction).getCodeOffset()); if (baseAddress == -1) { validPayload = false; } break; case FILL_ARRAY_DATA: try { methodDef.findPayloadOffset( this.codeAddress + ((Instruction31t) instruction).getCodeOffset(), Opcode.ARRAY_PAYLOAD); } catch (InvalidSwitchPayload ex) { validPayload = false; } break; default: throw new ExceptionWithContext("Invalid 31t opcode: %s", instruction.getOpcode()); } if (!validPayload) { writer.write("#invalid payload reference\n"); commentOutInstruction = true; } } if (opcode.odexOnly()) { if (!isAllowedOdex(opcode)) { writer.write("#disallowed odex opcode\n"); commentOutInstruction = true; } } if (commentOutInstruction) { writer.write("#"); } switch (instruction.getOpcode().format) { case Format10t: writeOpcode(writer); writer.write(' '); writeTargetLabel(writer); break; case Format10x: if (instruction instanceof UnknownInstruction) { writer.write("#unknown opcode: 0x"); writer.printUnsignedLongAsHex(((UnknownInstruction) instruction).getOriginalOpcode()); writer.write('\n'); } writeOpcode(writer); break; case Format11n: writeOpcode(writer); writer.write(' '); writeFirstRegister(writer); writer.write(", "); writeLiteral(writer); break; case Format11x: writeOpcode(writer); writer.write(' '); writeFirstRegister(writer); break; case Format12x: writeOpcode(writer); writer.write(' '); writeFirstRegister(writer); writer.write(", "); writeSecondRegister(writer); break; case Format20bc: writeOpcode(writer); writer.write(' '); writer.write(verificationErrorName); writer.write(", "); writer.write(referenceString); break; case Format20t: case Format30t: writeOpcode(writer); writer.write(' '); writeTargetLabel(writer); break; case Format21c: case Format31c: writeOpcode(writer); writer.write(' '); writeFirstRegister(writer); writer.write(", "); writer.write(referenceString); break; case Format21ih: case Format21lh: case Format21s: case Format31i: case Format51l: writeOpcode(writer); writer.write(' '); writeFirstRegister(writer); writer.write(", "); writeLiteral(writer); if (instruction.getOpcode().setsWideRegister()) { writeCommentIfLikelyDouble(writer); } else { boolean isResourceId = writeCommentIfResourceId(writer); if (!isResourceId) writeCommentIfLikelyFloat(writer); } break; case Format21t: case Format31t: writeOpcode(writer); writer.write(' '); writeFirstRegister(writer); writer.write(", "); writeTargetLabel(writer); break; case Format22b: case Format22s: writeOpcode(writer); writer.write(' '); writeFirstRegister(writer); writer.write(", "); writeSecondRegister(writer); writer.write(", "); writeLiteral(writer); break; case Format22c: writeOpcode(writer); writer.write(' '); writeFirstRegister(writer); writer.write(", "); writeSecondRegister(writer); writer.write(", "); writer.write(referenceString); break; case Format22cs: writeOpcode(writer); writer.write(' '); writeFirstRegister(writer); writer.write(", "); writeSecondRegister(writer); writer.write(", "); writeFieldOffset(writer); break; case Format22t: writeOpcode(writer); writer.write(' '); writeFirstRegister(writer); writer.write(", "); writeSecondRegister(writer); writer.write(", "); writeTargetLabel(writer); break; case Format22x: case Format32x: writeOpcode(writer); writer.write(' '); writeFirstRegister(writer); writer.write(", "); writeSecondRegister(writer); break; case Format23x: writeOpcode(writer); writer.write(' '); writeFirstRegister(writer); writer.write(", "); writeSecondRegister(writer); writer.write(", "); writeThirdRegister(writer); break; case Format25x: writeOpcode(writer); writer.write(' '); writeInvoke25xRegisters(writer); // vC, {vD, ...} break; case Format35c: writeOpcode(writer); writer.write(' '); writeInvokeRegisters(writer); writer.write(", "); writer.write(referenceString); break; case Format35mi: writeOpcode(writer); writer.write(' '); writeInvokeRegisters(writer); writer.write(", "); writeInlineIndex(writer); break; case Format35ms: writeOpcode(writer); writer.write(' '); writeInvokeRegisters(writer); writer.write(", "); writeVtableIndex(writer); break; case Format3rc: writeOpcode(writer); writer.write(' '); writeInvokeRangeRegisters(writer); writer.write(", "); writer.write(referenceString); break; case Format3rmi: writeOpcode(writer); writer.write(' '); writeInvokeRangeRegisters(writer); writer.write(", "); writeInlineIndex(writer); break; case Format3rms: writeOpcode(writer); writer.write(' '); writeInvokeRangeRegisters(writer); writer.write(", "); writeVtableIndex(writer); break; default: assert false; return false; } if (commentOutInstruction) { writer.write("\nnop"); } return true; }