/** * Constructs a hex data dump of the given portion of {@link #bytes}. * * @param offset offset to start dumping at * @param len length to dump * @return {@code non-null;} the dump */ protected final String hexDump(int offset, int len) { return Hex.dump(bytes, offset, len, offset, hexCols, 4); }
/** * Helper method to return the comment for a branch. * * @param insn {@code non-null;} the instruction in question * @return {@code non-null;} the comment */ protected static String branchComment(DalvInsn insn) { TargetInsn ti = (TargetInsn) insn; int offset = ti.getTargetOffset(); return (offset == (short) offset) ? Hex.s2(offset) : Hex.s4(offset); }
/** {@inheritDoc} */ @Override public void visitInvalid(int opcode, int offset, int length) { throw new SimException("invalid opcode " + Hex.u1(opcode)); }
/** * Helper for {@link #utf8BytesToString}, which throws the right * exception for a bogus utf-8 byte. * * @param value the byte value * @param offset the file offset * @return never * @throws IllegalArgumentException always thrown */ private static String throwBadUtf8(int value, int offset) { throw new IllegalArgumentException("bad utf-8 byte " + Hex.u1(value) + " at offset " + Hex.u4(offset)); }
/** * Helper method to return a branch address string. * * @param insn {@code non-null;} the instruction in question * @return {@code non-null;} the string form of the instruction's * branch target */ protected static String branchString(DalvInsn insn) { TargetInsn ti = (TargetInsn) insn; int address = ti.getTargetAddress(); return (address == (char) address) ? Hex.u2(address) : Hex.u4(address); }
/** * Helper method to return a literal bits comment string. * * @param value the value * @param width the width of the constant, in bits (used for displaying * the uninterpreted bits; one of: {@code 4 8 16 32 64} * @return {@code non-null;} the comment */ protected static String literalBitsComment(CstLiteralBits value, int width) { StringBuffer sb = new StringBuffer(20); sb.append("#"); long bits; if (value instanceof CstLiteral64) { bits = ((CstLiteral64) value).getLongBits(); } else { bits = value.getIntBits(); } switch (width) { case 4: sb.append(Hex.uNibble((int) bits)); break; case 8: sb.append(Hex.u1((int) bits)); break; case 16: sb.append(Hex.u2((int) bits)); break; case 32: sb.append(Hex.u4((int) bits)); break; case 64: sb.append(Hex.u8(bits)); break; default: { throw new RuntimeException("shouldn't happen"); } } return sb.toString(); }
/** {@inheritDoc} */ public void visitLocal(int opcode, int offset, int length, int idx, Type type, int value) { String idxStr = (length <= 3) ? Hex.u1(idx) : Hex.u2(idx); boolean argComment = (length == 1); String valueStr = ""; if (opcode == ByteOps.IINC) { valueStr = ", #" + ((length <= 3) ? Hex.s1(value) : Hex.s2(value)); } String catStr = ""; if (type.isCategory2()) { catStr = (argComment ? "," : " //") + " category-2"; } observer.parsed(bytes, offset, length, header(offset) + (argComment ? " // " : " ") + idxStr + valueStr + catStr); }
/** * Gets the {@link Info} for the given opcode value. * * @param opcode {@code Opcodes.MIN_VALUE..Opcodes.MAX_VALUE;} the * opcode value * @return non-null; the associated opcode information instance */ public static Info get(int opcode) { int idx = opcode - Opcodes.MIN_VALUE; try { Info result = INFO[idx]; if (result != null) { return result; } } catch (ArrayIndexOutOfBoundsException ex) { // Fall through. } throw new IllegalArgumentException("bogus opcode: " + Hex.u2or4(opcode)); }
/** * Gets the literal value, masked to be a byte in size. This will * throw if the value is out of the range of a signed byte. */ public final int getLiteralByte() { if (literal != (byte) literal) { throw new DexException("Literal out of range: " + Hex.u8(literal)); } return (int) literal & 0xff; }
/** * @return the label of this block in rop form as a hex string */ public String getRopLabelString() { return Hex.u2(ropLabel); }
/** * Gets the short identifier for this instruction. This is its * address, if assigned, or its identity hashcode if not. * * @return {@code non-null;} the identifier */ public final String identifierString() { if (address != -1) { return String.format("%04x", address); } return Hex.u4(System.identityHashCode(this)); }
/** * Gets the target as a relative offset from the given base * address, as a code unit. This will throw if the value is out of * the range of a signed code unit. */ public final short getTargetUnit(int baseAddress) { int relativeTarget = getTarget(baseAddress); if (relativeTarget != (short) relativeTarget) { throw new DexException("Target out of range: " + Hex.s4(relativeTarget)); } return (short) relativeTarget; }
@Override public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException { int opcode = byte0(opcodeUnit); if (opcode != Opcodes.INVOKE_POLYMORPHIC) { // 45cc isn't currently used for anything other than invoke-polymorphic. // If that changes, add a more general DecodedInstruction for this format. throw new UnsupportedOperationException(String.valueOf(opcode)); } int g = nibble2(opcodeUnit); int registerCount = nibble3(opcodeUnit); int methodIndex = in.read(); int cdef = in.read(); int c = nibble0(cdef); int d = nibble1(cdef); int e = nibble2(cdef); int f = nibble3(cdef); int protoIndex = in.read(); IndexType indexType = OpcodeInfo.getIndexType(opcode); if (registerCount < 1 || registerCount > 5) { throw new DexException("bogus registerCount: " + Hex.uNibble(registerCount)); } int[] registers = {c, d, e, f, g}; registers = Arrays.copyOfRange(registers, 0, registerCount); return new InvokePolymorphicDecodedInstruction( this, opcode, methodIndex, indexType, protoIndex, registers); }
/** * Helper method to return a literal bits comment string. * * @param value the value * @param width the width of the constant, in bits (used for displaying * the uninterpreted bits; one of: {@code 4 8 16 32 64} * @return {@code non-null;} the comment */ protected static String literalBitsComment(CstLiteralBits value, int width) { StringBuffer sb = new StringBuffer(20); sb.append("#"); long bits; if (value instanceof CstLiteral64) { bits = ((CstLiteral64) value).getLongBits(); } else { bits = value.getIntBits(); } switch (width) { case 4: sb.append(Hex.uNibble((int) bits)); break; case 8: sb.append(Hex.u1((int) bits)); break; case 16: sb.append(Hex.u2((int) bits)); break; case 32: sb.append(Hex.u4((int) bits)); break; case 64: sb.append(Hex.u8(bits)); break; default: { throw new RuntimeException("shouldn't happen"); } } return sb.toString(); }
/** {@inheritDoc} */ @Override public void visitLocal(int opcode, int offset, int length, int idx, Type type, int value) { String idxStr = (length <= 3) ? Hex.u1(idx) : Hex.u2(idx); boolean argComment = (length == 1); String valueStr = ""; if (opcode == ByteOps.IINC) { valueStr = ", #" + ((length <= 3) ? Hex.s1(value) : Hex.s2(value)); } String catStr = ""; if (type.isCategory2()) { catStr = (argComment ? "," : " //") + " category-2"; } observer.parsed(bytes, offset, length, header(offset) + (argComment ? " // " : " ") + idxStr + valueStr + catStr); }
/** * Helper method to return a branch address string. * * @param insn {@code non-null;} the instruction in question * @return {@code non-null;} the string form of the instruction's * branch target */ protected static String branchString(DalvInsn insn) { TargetInsn ti = (TargetInsn) insn; int address = ti.getTargetAddress(); return (address == (char) address) ? Hex.u2(address) : Hex.u4(address); }
/** * Gets the {@link @Info} for the given opcode value. * * @param opcode {@code Opcodes.MIN_VALUE..Opcodes.MAX_VALUE;} the * opcode value * @return non-null; the associated opcode information instance */ public static Info get(int opcode) { int idx = opcode - Opcodes.MIN_VALUE; try { Info result = INFO[idx]; if (result != null) { return result; } } catch (ArrayIndexOutOfBoundsException ex) { // Fall through. } throw new IllegalArgumentException("bogus opcode: " + Hex.u2or4(opcode)); }
/** * Gets the literal value, masked to be a nibble in size. This * will throw if the value is out of the range of a signed nibble. */ public final int getLiteralNibble() { if ((literal < -8) || (literal > 7)) { throw new DexException("Literal out of range: " + Hex.u8(literal)); } return (int) literal & 0xf; }