|
|
Using Mnemonics in the Disassembler
In Chapter 4, you saw method bodies printed as raw bytes. Although its possible to use Table 5-1 and a good memory to understand what those bytes mean, I certainly wouldnt recommend it. Instead, I expand the CodeAttribute class so that it uses mnemonics instead of raw bytes. This is shown in Listing 5-1.
Although Listing 5-1 looks frighteningly long, it is mostly one big switch statement that reads the next opcode and its arguments and returns a string. Because there are more than 200 opcodes, the readCode() method has to be quite long. However, most of the cases in the switch statement are very simple. Over half of them merely return an opcode. Most of the rest return an opcode and some literal data.
The three exceptions are the cases for the lookupswitch, tableswitch, and wide instructions. These are special because they have variable-length data encoded in the code array. I discuss them in more detail later in this chapter, when I discuss the meaning of those instructions.
Listing 5-1 The CodeAttribute class
import java.io.*;
public class CodeAttribute {
int nameIndex;
int maxStack;
int maxLocals;
byte[] code;
ExceptionTable[] exceptions;
AttributeInfo[] attributes;
public CodeAttribute(AttributeInfo ai) throws IOException {
nameIndex = ai.nameIndex();
ByteArrayInputStream bis = new ByteArrayInputStream(ai.data);
DataInputStream dis = new DataInputStream(bis);
maxStack = dis.readUnsignedShort();
maxLocals = dis.readUnsignedShort();
code = new byte[dis.readInt()];
dis.read(code);
exceptions = new ExceptionTable[dis.readUnsignedShort()];
for (int i = 0; i < exceptions.length; i++) {
exceptions[i] = new ExceptionTable(dis.readUnsignedShort(),
dis.readUnsignedShort(), dis.readUnsignedShort(),
dis.readUnsignedShort());
}
attributes = new AttributeInfo[dis.readUnsignedShort()];
for (int i = 0; i < exceptions.length; i++) {
attributes[i] = new AttributeInfo(dis);
}
}
public int nameIndex() {
return nameIndex;
}
// just print the code array
public String toString() {
ByteArrayInputStream bis = new ByteArrayInputStream(code);
DataInputStream dis = new DataInputStream(bis);
StringBuffer result = new StringBuffer(4*code.length);
try {
while (bis.available() > 0) {
result.append(readCode(dis));
result.append(\n);
}
} // end try
catch (IOException e) {
}
return result.toString();
}
String readCode(DataInputStream dis) throws IOException {
int pad, defaultByte;
int position = code.length - dis.available();
int opcode = dis.readUnsignedByte();
String result;
switch (opcode) {
case 0: return position + nop;
case 1: return position + aconst_null;
case 2: return position + iconst_m1;
case 3: return position + iconst_0;
case 4: return position + iconst_1;
case 5: return position + iconst_2;
case 6: return position + iconst_3;
case 7: return position + iconst_4;
case 8: return position + iconst_5;
case 9: return position + lconst_0;
case 10: return position + lconst_1;
case 11: return position + fconst_0;
case 12: return position + fconst_1;
case 13: return position + fconst_2;
case 14: return position + dconst_0;
case 15: return position + dconst_1;
case 16: return position + bipush + dis.readByte();
case 17: return position + sipush + dis.readShort();
case 18: return position + ldc + dis.readUnsignedByte();
case 19: return position + ldc_w + dis.readUnsignedShort();
case 20: return position + ldc2_w + dis.readUnsignedShort();
case 21: return position + iload + dis.readUnsignedByte();
case 22: return position + lload + dis.readUnsignedByte();
case 23: return position + fload + dis.readUnsignedByte();
case 24: return position + dload + dis.readUnsignedByte();
case 25: return position + aload + dis.readUnsignedByte();
case 26: return position + iload_0;
case 27: return position + iload_1;
case 28: return position + iload_2;
case 29: return position + iload_3;
case 30: return position + lload_0;
case 31: return position + lload_1;
case 32: return position + lload_2;
case 33: return position + lload_3;
case 34: return position + fload_0;
case 35: return position + fload_1;
case 36: return position + fload_2;
case 37: return position + fload_3;
case 38: return position + dload_0;
case 39: return position + dload_1;
case 40: return position + dload_2;
case 41: return position + dload_3;
case 42: return position + aload_0;
case 43: return position + aload_1;
case 44: return position + aload_2;
case 45: return position + aload_3;
case 46: return position + iaload;
case 47: return position + laload;
case 48: return position + faload;
case 49: return position + daload;
case 50: return position + aaload;
case 51: return position + baload;
case 52: return position + caload;
case 53: return position + saload;
case 54: return position + istore + dis.readUnsignedByte();
case 55: return position + lstore + dis.readUnsignedByte();
case 56: return position + fstore + dis.readUnsignedByte();
case 57: return position + dstore + dis.readUnsignedByte();
case 58: return position + astore + dis.readUnsignedByte();
case 59: return position + istore_0;
case 60: return position + istore_1;
case 61: return position + istore_2;
case 62: return position + istore_3;
case 63: return position + lstore_0;
case 64: return position + lstore_1;
case 65: return position + lstore_2;
case 66: return position + lstore_3;
case 67: return position + fstore_0;
case 68: return position + fstore_1;
case 69: return position + fstore_2;
case 70: return position + fstore_3;
case 71: return position + dstore_0;
case 72: return position + dstore_1;
case 73: return position + dstore_2;
case 74: return position + dstore_3;
case 75: return position + astore_0;
case 76: return position + astore_1;
case 77: return position + astore_2;
case 78: return position + astore_3;
case 79: return position + iastore;
case 80: return position + lastore;
case 81: return position + fastore;
case 82: return position + dastore;
case 83: return position + aastore;
case 84: return position + bastore;
case 85: return position + castore;
case 86: return position + sastore;
case 87: return position + pop;
case 88: return position + pop2;
case 89: return position + dup;
case 90: return position + dup_x1;
case 91: return position + dup_x2;
case 92: return position + dup2;
case 93: return position + dup2_x1;
case 94: return position + dup2_x2;
case 95: return position + swap;
case 96: return position + iadd;
case 97: return position + ladd;
case 98: return position + fadd;
case 99: return position + dadd;
case 100: return position + isub;
case 101: return position + lsub;
case 102: return position + fsub;
case 103: return position + dsub;
case 104: return position + imul;
case 105: return position + lmul;
case 106: return position + fmul;
case 107: return position + dmul;
case 108: return position + idiv;
case 109: return position + ldiv;
case 110: return position + fdiv;
case 111: return position + ddiv;
case 112: return position + irem;
case 113: return position + lrem;
case 114: return position + frem;
case 115: return position + drem;
case 116: return position + ineg;
case 117: return position + lneg;
case 118: return position + fneg;
case 119: return position + dneg;
case 120: return position + ishl;
case 121: return position + lshl;
case 122: return position + ishr;
case 123: return position + lshr;
case 124: return position + iushr;
case 125: return position + lushr;
case 126: return position + iand;
case 127: return position + land;
case 128: return position + ior;
case 129: return position + lor;
case 130: return position + ixor;
case 131: return position + lxor;
case 132: return position + iinc
+ dis.readUnsignedByte() + + dis.readUnsignedByte() ;
case 133: return position + i2l;
case 134: return position + i2f;
case 135: return position + i2d;
case 136: return position + l2i;
case 137: return position + l2f;
case 138: return position + l2d;
case 139: return position + f2i;
case 140: return position + f2l;
case 141: return position + f2d;
case 142: return position + d2i;
case 143: return position + d2l;
case 144: return position + d2f;
case 145: return position + i2b;
case 146: return position + i2c;
case 147: return position + i2s;
case 148: return position + lcmp;
case 149: return position + fcmpl;
case 150: return position + fcmpg;
case 151: return position + dcmpl;
case 152: return position + dcmpg;
case 153: return position + ifeq + dis.readShort();
case 154: return position + ifne + dis.readShort();
case 155: return position + iflt + dis.readShort();
case 156: return position + ifge + dis.readShort();
case 157: return position + ifgt + dis.readShort();
case 158: return position + ifle + dis.readShort();
case 159: return position + if_icmpeq + dis.readShort();
case 160: return position + if_icmpne + dis.readShort();
case 161: return position + if_icmplt + dis.readShort();
case 162: return position + if_icmpge + dis.readShort();
case 163: return position + if_icmpgt + dis.readShort();
case 164: return position + if_icmple + dis.readShort();
case 165: return position + if_acmpeq + dis.readShort();
case 166: return position + if_acmpne + dis.readShort();
case 167: return position + goto + dis.readShort();
case 168: return position + jsr + dis.readShort();
case 169: return position + ret + dis.readUnsignedByte();
case 170: // tableswitch
pad = 3 - (position % 4);
dis.skip(pad);
defaultByte = dis.readInt();
int low = dis.readInt();
int high = dis.readInt();
result = position + tableswitch
+ defaultByte + + low + + high;
for (int i = low; i < high; i++) {
int newPosition = position + pad + 12 + (i-low)*4;
result += \n + newPosition + + dis.readInt();
}
return result;
case 171: // lookupswitch
pad = 3 - (position % 4);
dis.skip(pad);
defaultByte = dis.readInt();
int npairs = dis.readInt();
result = position + lookupswitch + defaultByte + + npairs;
for (int i = 0; i < npairs; i++) {
int newPosition = position + pad + 12 + i*8;
result += \n + newPosition +
+ dis.readInt() + + dis.readInt();
}
return result;
case 172: return position + ireturn;
case 173: return position + lreturn;
case 174: return position + freturn;
case 175: return position + dreturn;
case 176: return position + areturn;
case 177: return position + return;
case 178: return position + getstatic + dis.readUnsignedShort();
case 179: return position + putstatic + dis.readUnsignedShort();
case 180: return position + getfield + dis.readUnsignedShort();
case 181: return position + putfield + dis.readUnsignedShort();
case 182: return position + invokevirtual + dis.readUnsignedShort();
case 183: return position + invokespecial + dis.readUnsignedShort();
case 184: return position + invokestatic + dis.readUnsignedShort();
case 185: return invokeinterface + dis.readUnsignedShort() +
+ dis.readUnsignedByte();
// 186 is unimplemented in Java 1.0.2
case 187: return position + new + dis.readUnsignedShort();
case 188: return position + newarray + dis.readByte();
case 189: return position + anewarray + dis.readUnsignedShort();
case 190: return position + arraylength;
case 191: return position + athrow;
case 192: return position + checkcast + dis.readUnsignedShort();
case 193: return position + instanceof + dis.readUnsignedShort();
case 194: return position + monitorenter;
case 195: return position + monitorexit;
case 196:
int nextCode = dis.readUnsignedByte();
switch(nextCode) {
case 132: // iinc
return wide\n + (position+1) + iinc + dis.readUnsignedShort()
+ + dis.readUnsignedShort();
case 21:
return wide\n + (position+1) + iload + dis.readUnsignedShort();
case 22:
return wide\n + (position+1) + lload + dis.readUnsignedShort();
case 23:
return wide\n + (position+1) + fload + dis.readUnsignedShort();
case 24:
return wide\n + (position+1) + dload + dis.readUnsignedShort();
case 25:
return wide\n + (position+1) + aload + dis.readUnsignedShort();
case 54:
return wide\n + (position+1) + istore
+ dis.readUnsignedShort();
case 55:
return wide\n + (position+1) + lstore
+ dis.readUnsignedShort();
case 56:
return wide\n + (position+1) + fstore
+ dis.readUnsignedShort();
case 57:
return wide\n + (position+1) + dstore
+ dis.readUnsignedShort();
case 58:
return wide\n + (position+1) + astore
+ dis.readUnsignedShort();
} // end switch
case 197:
return multianewarray + dis.readUnsignedShort() +
+ dis.readUnsignedByte();
case 198: return position + ifnull + dis.readShort();
case 199: return position + ifnonnull + dis.readShort();
case 200: return position + goto_w + dis.readInt();
default: return position + unknown_opcode + opcode;
} // end switch
}
}
|