Code with Finding: |
class Utility {
/**
* Disassemble a stream of byte codes and return the
* string representation.
*
* @param bytes stream of bytes
* @param constant_pool Array of constants
* @param verbose be verbose, e.g. print constant pool index
* @return String representation of byte code
*
* @throws IOException if a failure from reading from the bytes argument occurs
*/
public static String codeToString( ByteSequence bytes, ConstantPool constant_pool,
boolean verbose ) throws IOException {
short opcode = (short) bytes.readUnsignedByte();
int default_offset = 0;
int low;
int high;
int npairs;
int index;
int vindex;
int constant;
int[] match;
int[] jump_table;
int no_pad_bytes = 0;
int offset;
StringBuilder buf = new StringBuilder(Const.getOpcodeName(opcode));
/* Special case: Skip (0-3) padding bytes, i.e., the
* following bytes are 4-byte-aligned
*/
if ((opcode == Const.TABLESWITCH) || (opcode == Const.LOOKUPSWITCH)) {
int remainder = bytes.getIndex() % 4;
no_pad_bytes = (remainder == 0) ? 0 : 4 - remainder;
for (int i = 0; i < no_pad_bytes; i++) {
byte b;
if ((b = bytes.readByte()) != 0) {
System.err.println("Warning: Padding byte != 0 in "
+ Const.getOpcodeName(opcode) + ":" + b);
}
}
// Both cases have a field default_offset in common
default_offset = bytes.readInt();
}
switch (opcode) {
/* Table switch has variable length arguments.
*/
case Const.TABLESWITCH:
low = bytes.readInt();
high = bytes.readInt();
offset = bytes.getIndex() - 12 - no_pad_bytes - 1;
default_offset += offset;
buf.append("\tdefault = ").append(default_offset).append(", low = ").append(low)
.append(", high = ").append(high).append("(");
jump_table = new int[high - low + 1];
for (int i = 0; i < jump_table.length; i++) {
jump_table[i] = offset + bytes.readInt();
buf.append(jump_table[i]);
if (i < jump_table.length - 1) {
buf.append(", ");
}
}
buf.append(")");
break;
/* Lookup switch has variable length arguments.
*/
case Const.LOOKUPSWITCH: {
npairs = bytes.readInt();
offset = bytes.getIndex() - 8 - no_pad_bytes - 1;
match = new int[npairs];
jump_table = new int[npairs];
default_offset += offset;
buf.append("\tdefault = ").append(default_offset).append(", npairs = ").append(
npairs).append(" (");
for (int i = 0; i < npairs; i++) {
match[i] = bytes.readInt();
jump_table[i] = offset + bytes.readInt();
buf.append("(").append(match[i]).append(", ").append(jump_table[i]).append(")");
if (i < npairs - 1) {
buf.append(", ");
}
}
buf.append(")");
}
break;
/* Two address bytes + offset from start of byte stream form the
* jump target
*/
case Const.GOTO:
case Const.IFEQ:
case Const.IFGE:
case Const.IFGT:
case Const.IFLE:
case Const.IFLT:
case Const.JSR:
case Const.IFNE:
case Const.IFNONNULL:
case Const.IFNULL:
case Const.IF_ACMPEQ:
case Const.IF_ACMPNE:
case Const.IF_ICMPEQ:
case Const.IF_ICMPGE:
case Const.IF_ICMPGT:
case Const.IF_ICMPLE:
case Const.IF_ICMPLT:
case Const.IF_ICMPNE:
buf.append("\t\t#").append((bytes.getIndex() - 1) + bytes.readShort());
break;
/* 32-bit wide jumps
*/
case Const.GOTO_W:
case Const.JSR_W:
buf.append("\t\t#").append((bytes.getIndex() - 1) + bytes.readInt());
break;
/* Index byte references local variable (register)
*/
case Const.ALOAD:
case Const.ASTORE:
case Const.DLOAD:
case Const.DSTORE:
case Const.FLOAD:
case Const.FSTORE:
case Const.ILOAD:
case Const.ISTORE:
case Const.LLOAD:
case Const.LSTORE:
case Const.RET:
if (wide) {
vindex = bytes.readUnsignedShort();
wide = false; // Clear flag
} else {
vindex = bytes.readUnsignedByte();
}
buf.append("\t\t%").append(vindex);
break;
/*
* Remember wide byte which is used to form a 16-bit address in the
* following instruction. Relies on that the method is called again with
* the following opcode.
*/
case Const.WIDE:
wide = true;
buf.append("\t(wide)");
break;
/* Array of basic type.
*/
case Const.NEWARRAY:
buf.append("\t\t<").append(Const.getTypeName(bytes.readByte())).append(">");
break;
/* Access object/class fields.
*/
case Const.GETFIELD:
case Const.GETSTATIC:
case Const.PUTFIELD:
case Const.PUTSTATIC:
index = bytes.readUnsignedShort();
buf.append("\t\t").append(
constant_pool.constantToString(index, Const.CONSTANT_Fieldref)).append(
verbose ? " (" + index + ")" : "");
break;
/* Operands are references to classes in constant pool
*/
case Const.NEW:
case Const.CHECKCAST:
buf.append("\t");
//$FALL-THROUGH$
case Const.INSTANCEOF:
index = bytes.readUnsignedShort();
buf.append("\t<").append(
constant_pool.constantToString(index, Const.CONSTANT_Class))
.append(">").append(verbose ? " (" + index + ")" : "");
break;
/* Operands are references to methods in constant pool
*/
case Const.INVOKESPECIAL:
case Const.INVOKESTATIC:
index = bytes.readUnsignedShort();
Constant c = constant_pool.getConstant(index);
// With Java8 operand may be either a CONSTANT_Methodref
// or a CONSTANT_InterfaceMethodref. (markro)
buf.append("\t").append(
constant_pool.constantToString(index, c.getTag()))
.append(verbose ? " (" + index + ")" : "");
break;
case Const.INVOKEVIRTUAL:
index = bytes.readUnsignedShort();
buf.append("\t").append(
constant_pool.constantToString(index, Const.CONSTANT_Methodref))
.append(verbose ? " (" + index + ")" : "");
break;
case Const.INVOKEINTERFACE:
index = bytes.readUnsignedShort();
int nargs = bytes.readUnsignedByte(); // historical, redundant
buf.append("\t").append(
constant_pool
.constantToString(index, Const.CONSTANT_InterfaceMethodref))
.append(verbose ? " (" + index + ")\t" : "").append(nargs).append("\t")
.append(bytes.readUnsignedByte()); // Last byte is a reserved space
break;
case Const.INVOKEDYNAMIC:
index = bytes.readUnsignedShort();
buf.append("\t").append(
constant_pool
.constantToString(index, Const.CONSTANT_InvokeDynamic))
.append(verbose ? " (" + index + ")\t" : "")
.append(bytes.readUnsignedByte()) // Thrid byte is a reserved space
.append(bytes.readUnsignedByte()); // Last byte is a reserved space
break;
/* Operands are references to items in constant pool
*/
case Const.LDC_W:
case Const.LDC2_W:
index = bytes.readUnsignedShort();
buf.append("\t\t").append(
constant_pool.constantToString(index, constant_pool.getConstant(index)
.getTag())).append(verbose ? " (" + index + ")" : "");
break;
case Const.LDC:
index = bytes.readUnsignedByte();
buf.append("\t\t").append(
constant_pool.constantToString(index, constant_pool.getConstant(index)
.getTag())).append(verbose ? " (" + index + ")" : "");
break;
/* Array of references.
*/
case Const.ANEWARRAY:
index = bytes.readUnsignedShort();
buf.append("\t\t<").append(
compactClassName(constant_pool.getConstantString(index,
Const.CONSTANT_Class), false)).append(">").append(
verbose ? " (" + index + ")" : "");
break;
/* Multidimensional array of references.
*/
case Const.MULTIANEWARRAY: {
index = bytes.readUnsignedShort();
int dimensions = bytes.readUnsignedByte();
buf.append("\t<").append(
compactClassName(constant_pool.getConstantString(index,
Const.CONSTANT_Class), false)).append(">\t").append(dimensions)
.append(verbose ? " (" + index + ")" : "");
}
break;
/* Increment local variable.
*/
case Const.IINC:
if (wide) {
vindex = bytes.readUnsignedShort();
constant = bytes.readShort();
wide = false;
} else {
vindex = bytes.readUnsignedByte();
constant = bytes.readByte();
}
buf.append("\t\t%").append(vindex).append("\t").append(constant);
break;
default:
if (Const.getNoOfOperands(opcode) > 0) {
for (int i = 0; i < Const.getOperandTypeCount(opcode); i++) {
buf.append("\t\t");
switch (Const.getOperandType(opcode, i)) {
case Const.T_BYTE:
buf.append(bytes.readByte());
break;
case Const.T_SHORT:
buf.append(bytes.readShort());
break;
case Const.T_INT:
buf.append(bytes.readInt());
break;
default: // Never reached
System.err.println("Unreachable default case reached!");
System.exit(-1);
}
}
}
}
return buf.toString();
}
}
|