#include #include #include char *opcode[256] = { "nop", "aconst_null", "iconst_m1", "iconst_0", "iconst_1", "iconst_2", "iconst_3", "iconst_4", "iconst_5", "lconst_0", "lconst_1", "fconst_0", "fconst_1", "fconst_2", "dconst_0", "dconst_1", "bipush", "sipush", "ldc", "ldc_w", "ldc2_w", "iload", "lload", "fload", "dload", "aload", "iload_0", "iload_1", "iload_2", "iload_3", "lload_0", "lload_1", "lload_2", "lload_3", "fload_0", "fload_1", "fload_2", "fload_3", "dload_0", "dload_1", "dload_2", "dload_3", "aload_0", "aload_1", "aload_2", "aload_3", "iaload", "laload", "faload", "daload", "aaload", "baload", "caload", "saload", "istore", "lstore", "fstore", "dstore", "astore", "istore_0", "istore_1", "istore_2", "istore_3", "lstore_0", "lstore_1", "lstore_2", "lstore_3", "fstore_0", "fstore_1", "fstore_2", "fstore_3", "dstore_0", "dstore_1", "dstore_2", "dstore_3", "astore_0", "astore_1", "astore_2", "astore_3", "iastore", "lastore", "fastore", "dastore", "aastore", "bastore", "castore", "sastore", "pop", "pop2", "dup", "dup_x1", "dup_x2", "dup2", "dup2_x1", "dup2_x2", "swap", "iadd", "ladd", "fadd", "dadd", "isub", "lsub", "fsub", "dsub", "imul", "lmul", "fmul", "dmul", "idiv", "ldiv", "fdiv", "ddiv", "irem", "lrem", "frem", "drem", "ineg", "lneg", "fneg", "dneg", "ishl", "lshl", "ishr", "lshr", "iushr", "lushr", "iand", "land", "ior", "lor", "ixor", "lxor", "iinc", "i2l", "i2f", "i2d", "l2i", "l2f", "l2d", "f2i", "f2l", "f2d", "d2i", "d2l", "d2f", "i2b", "i2c", "i2s", "lcmp", "fcmpl", "fcmpg", "dcmpl", "dcmpg", "ifeq", "ifne", "iflt", "ifge", "ifgt", "ifle", "if_icmpeq", "if_icmpne", "if_icmplt", "if_icmpge", "if_icmpgt", "if_icmple", "if_acmpeq", "if_acmpne", "goto", "jsr", "ret", "tableswitch", "lookupswitch", "ireturn", "lreturn", "freturn", "dreturn", "areturn", "return", "getstatic", "putstatic", "getfield", "putfield", "invokevirtual", "invokespecial", "invokestatic", "invokeinterface", "xxx_unused_xxx", "new", "newarray", "anewarray", "arraylength", "athrow", "checkcast", "instanceof", "monitorenter", "monitorexit", "wide", "multianewarray", "ifnull", "ifnonnull", "goto_w", "jsr_w", "breakpoint", "XXX", "XXX","XXX", "XXX", "XXX", "XXX","XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX","XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX","XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX","XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX","XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX","XXX", "XXX", "XXX", "XXX", "XXX", "impdep1", "impdep2" }; char *atype[] = { "???", "???", "???", "???", "T_BOOLEAN", "T_CHAR", "T_FLOAT", "T_DOUBLE", "T_BYTE", "T_SHORT", "T_INT", "T_LONG" }; #define TO_32(b) ((b[0]<<24)|(b[1]<<16)|(b[2]<<8)|(b[3])) #define TO_16(b) ((b[0]<<8)|(b[1])) int CodeAttrName, ConstantAttrName, ExceptAttrName, InnerClassAttrName, SyntheticAttrName, SourceAttrName, LineNumAttrName, LocalVarAttrName; unsigned char buf[256]; void DumpAttr(int fd, int name, int len) { if (name == CodeAttrName) { unsigned short max_stack, max_locals, cnt, val; signed short sval; int ival, defval, lval, hval, pad; unsigned long code_len, pc; printf("Code:"); read(fd, buf, 2); max_stack = TO_16(buf); printf(" max_stack %d", max_stack); read(fd, buf, 2); max_locals = TO_16(buf); printf(" max_locals %d", max_locals); read(fd, buf, 4); code_len = TO_32(buf); printf(" code_len %u\n", code_len); for (pc = 0; pc < code_len; pc++) { read(fd, buf, 1); printf("\t\t\t\t%06u[0x%04X]: %s", pc, pc, opcode[buf[0]]); switch (buf[0]) { case 0x19: // local var index8 case 0x3A: case 0x18: case 0x39: case 0x17: case 0x38: case 0x84: case 0x15: case 0x36: case 0x16: case 0x37: case 0xA9: read(fd, buf+1, 1); printf(" %u", buf[1]); if (buf[0] == 0x84) // , const { read(fd, buf, 1); printf(" %d", (signed char)buf[0]); pc++; } pc++; break; case 0xC4: // wide local var index16 read(fd, buf, 1); if (buf[0] == 0x84) { read(fd, buf, 2); val = TO_16(buf); printf(" iinc %u", val); read(fd, buf, 2); val = TO_16(buf); printf(" %d", val); pc += 5; } else { printf(" %s", opcode[buf[0]]); read(fd, buf, 2); val = TO_16(buf); printf(" %u", val); pc += 3; } break; case 0x12: // class const pool index8 read(fd, buf+1, 1); printf(" #%u", buf[1]); pc++; break; case 0xBD: // class const pool index16 case 0xC0: case 0xB4: case 0xB2: case 0xC1: case 0xB7: case 0xB8: case 0xB6: case 0x13: case 0x14: case 0xBB: case 0xB5: case 0xB3: case 0xB9: case 0xC5: buf[2] = buf[0]; read(fd, buf, 2); val = TO_16(buf); printf(" #%u", val); if (buf[2] == 0xC5) // , dimensions { read(fd, buf, 1); printf(" %d", buf[0]); pc++; } if (buf[2] == 0xB9) // , count, 0 { read(fd, buf, 2); printf(" %d", buf[0]); pc += 2; } pc += 2; break; case 0x10: // byte read(fd, buf, 1); printf(" %d", buf[0]); pc++; break; case 0xBC: // atype read(fd, buf, 1); printf(" %d (%s)", buf[0], atype[buf[0]]); pc++; break; case 0x11: // short read(fd, buf, 2); val = TO_16(buf); printf(" %d", val); pc += 2; break; case 0xA7: // branch16 case 0xA5: case 0xA6: case 0x9F: case 0xA0: case 0xA1: case 0xA2: case 0xA3: case 0xA4: case 0x99: case 0x9A: case 0x9B: case 0x9C: case 0x9D: case 0x9E: case 0xC7: case 0xC6: case 0xA8: read(fd, buf, 2); sval = TO_16(buf); printf(" %+d (%06u)", sval, pc + sval); pc += 2; break; case 0xC9: // branch32 case 0xC8: read(fd, buf, 4); ival = TO_32(buf); printf(" %+d (%06u)", ival, pc + ival); pc += 4; break; case 0xAB: // lookupswitch pad = ((pc + 1) & 0x03); if (pad) { pad = 4 - pad; read(fd, buf, pad); // padding } read(fd, buf, 4); defval = TO_32(buf); // default read(fd, buf, 4); hval = TO_32(buf); // num pairs printf(" %d:\n", hval); for (cnt = 0; cnt < hval; cnt++) { read(fd, buf, 4); ival = TO_32(buf); // match read(fd, buf, 4); lval = TO_32(buf); // offsets printf("\t\t\t\t\t%d: %+d (%06u)\n", ival, lval, pc + lval); } printf("\t\t\t\t\tdefault: %+d (%06u)", defval, pc + defval); pc += pad + 8 + 8 * hval; break; case 0xAA: // tableswitch pad = ((pc + 1) & 0x03); if (pad) { pad = 4 - pad; read(fd, buf, pad); // padding } read(fd, buf, 4); defval = TO_32(buf); // default read(fd, buf, 4); lval = TO_32(buf); // low value read(fd, buf, 4); hval = TO_32(buf); // high value printf(" %d to %d:\n", lval, hval); for (cnt = lval; cnt <= hval; cnt++) { read(fd, buf, 4); ival = TO_32(buf); // offsets printf("\t\t\t\t\t%d: %+d (%06u)\n", cnt, ival, pc + ival); } printf("\t\t\t\t\tdefault: %+d (%06u)", defval, pc + defval); pc += pad + 12 + 4 * (hval - lval + 1); break; } printf("\n"); } read(fd, buf, 2); cnt = TO_16(buf); printf("\t\t\texcept_len: %d\n", cnt); while (cnt--) { read(fd, buf, 2); val = TO_16(buf); printf("\t\t\t\tfrom %06u", val); read(fd, buf, 2); val = TO_16(buf); printf(" to %06u", val); read(fd, buf, 2); val = TO_16(buf); printf(" handler %06u", val); read(fd, buf, 2); val = TO_16(buf); printf(" type %d\n", val); } read(fd, buf, 2); cnt = TO_16(buf); while (cnt--) { read(fd, buf, 2); name = TO_16(buf); read(fd, buf, 4); len = TO_32(buf); printf("\t\t\tcode_attr: "); DumpAttr(fd, name, len); } } else if (name == ConstantAttrName) { unsigned short idx; if (len != 2) { fprintf(stderr, "\nError: Bad attribute length for ConstantValue.\n"); exit(1); } read(fd, buf, 2); idx = TO_16(buf); printf("ConstantValue: #%d\n", idx); } else if (name == ExceptAttrName) { unsigned short except_cnt, except_idx; read(fd, buf, 2); except_cnt = TO_16(buf); printf("Exceptions count: %d\n", except_cnt); while (except_cnt--) { read(fd, buf, 2); except_idx = TO_16(buf); printf("\t\t\t\t# %d\n", except_idx); } } else { if (name == InnerClassAttrName) printf("InnerClasses: "); else if (name == SyntheticAttrName) printf("Synthetic: "); else if (name == SourceAttrName) printf("SourceFile: "); else if (name == LineNumAttrName) printf("LineNumberTable: "); else if (name == LocalVarAttrName) printf("LocalVariableTable: "); else printf("name #%d ", name); printf("len %d\n", len); while (len > 256) { read(fd, buf, 256); len -= 256; } if (len) read(fd, buf, len); } } int main(int argc, char **argv) { int cf, fd, cc, ii, cnt, idx; long long long_val; float float_val; double double_val; unsigned int magic; unsigned short minor_version; unsigned short major_version; unsigned short const_pool_count, iface_count, fields_count, methods_count, attribs_count; unsigned short access_flags; unsigned short this_class, super_class; if (argc < 2) { printf("Usage: %s [classfile2] ...\n", argv[0]); return (1); } for (cf = 1; cf < argc; cf++) { if ((fd = open(argv[cf], O_RDONLY, 0)) > 0) { printf("Class file: %s\n", argv[cf]); read(fd, buf, 4); magic = TO_32(buf); printf("\tmagic: 0x%08X\n", magic); read(fd, buf, 2); minor_version = TO_16(buf); read(fd, buf, 2); major_version = TO_16(buf); printf("\tmajor.minor: %d.%d\n", major_version, minor_version); read(fd, buf, 2); const_pool_count = TO_16(buf); printf("\tconst_pool_count: %d\n", const_pool_count); for (cc = 1; cc < const_pool_count; cc++) { printf("\t\t[%02d] ", cc); read(fd, buf, 1); switch (buf[0]) { case 0: // BAD printf("Bad tag 0"); read(fd, buf, 1); break; case 1: // CONSTANT_Utf8 printf("Utf8: "); read(fd, buf, 2); idx = TO_16(buf); read(fd, buf, idx); buf[idx] = '\0'; printf("%s", buf); if (strcmp(buf, "Code") == 0) CodeAttrName = cc; else if (strcmp(buf, "ConstantValue") == 0) ConstantAttrName = cc; else if (strcmp(buf, "Exceptions") == 0) ExceptAttrName = cc; else if (strcmp(buf, "InnerClasses") == 0) InnerClassAttrName = cc; else if (strcmp(buf, "Synthetic") == 0) SyntheticAttrName = cc; else if (strcmp(buf, "SourceFile") == 0) SourceAttrName = cc; else if (strcmp(buf, "LineNumberTable") == 0) LineNumAttrName = cc; else if (strcmp(buf, "LocalVariableTable") == 0) LocalVarAttrName = cc; break; case 3: // CONSTANT_Integer printf("Integer: "); read(fd, buf, 4); idx = TO_32(buf); printf("%d", idx); break; case 4: // CONSTANT_Float printf("Float: "); read(fd, buf, 4); idx = TO_32(buf); float_val = *(float *)(&idx); printf("%f", float_val); break; case 5: // CONSTANT_Long printf("Long: "); read(fd, buf, 8); idx = TO_32((buf+4)); printf("%d", idx); cc++; break; case 6: // CONSTANT_Double printf("Double: "); read(fd, buf, 8); cc++; break; case 7: // CONSTANT_Class printf("Class: "); read(fd, buf, 2); idx = TO_16(buf); printf("#%d", idx); break; case 8: // CONSTANT_String printf("String: "); read(fd, buf, 2); idx = TO_16(buf); printf("#%d", idx); break; case 9: // CONSTANT_Fieldref printf("Fieldref: "); read(fd, buf, 2); idx = TO_16(buf); printf("class #%d", idx); read(fd, buf, 2); idx = TO_16(buf); printf(" name_type #%d", idx); break; case 10: // CONSTANT_Methodref printf("Methodref: "); read(fd, buf, 2); idx = TO_16(buf); printf("class #%d", idx); read(fd, buf, 2); idx = TO_16(buf); printf(" name_type #%d", idx); break; case 11: // CONSTANT_InterfaceMethodref printf("InterfaceMethodref: "); read(fd, buf, 2); idx = TO_16(buf); printf("class #%d", idx); read(fd, buf, 2); idx = TO_16(buf); printf(" name_type #%d", idx); break; case 12: // CONSTANT_NameAndType printf("NameAndType: "); read(fd, buf, 2); idx = TO_16(buf); printf("name #%d", idx); read(fd, buf, 2); idx = TO_16(buf); printf(" desc #%d", idx); break; default: printf("Bad tag %d", buf[0]); read(fd, buf, 1); break; } printf("\n"); } read(fd, buf, 2); access_flags = TO_16(buf); printf("\taccess_flags: 0x%04X\n", access_flags); read(fd, buf, 2); this_class = TO_16(buf); printf("\tthis_class: %d\n", this_class); read(fd, buf, 2); super_class = TO_16(buf); printf("\tsuper_class: %d\n", super_class); read(fd, buf, 2); iface_count = TO_16(buf); printf("\tinterfaces_count: %d\n", iface_count); for (cc = 0; cc < iface_count; cc++) { printf("\t\t[%02d] ", cc); read(fd, buf, 2); idx = TO_16(buf); printf("#%d\n", idx); } read(fd, buf, 2); fields_count = TO_16(buf); printf("\tfields_count: %d\n", fields_count); for (cc = 0; cc < fields_count; cc++) { printf("\t\t[%02d] ", cc); read(fd, buf, 2); idx = TO_16(buf); printf("access 0x%02X ", idx); read(fd, buf, 2); idx = TO_16(buf); printf("name #%d ", idx); read(fd, buf, 2); idx = TO_16(buf); printf("desc #%d ", idx); read(fd, buf, 2); cnt = TO_16(buf); printf("attr_cnt %d\n", cnt); for (ii = 0; ii < cnt; ii++) { int nm, len; printf("\t\t\t[%02d] ", ii); read(fd, buf, 2); nm = TO_16(buf); read(fd, buf, 4); len = TO_32(buf); DumpAttr(fd, nm, len); } } read(fd, buf, 2); methods_count = TO_16(buf); printf("\tmethods_count: %d\n", methods_count); for (cc = 0; cc < methods_count; cc++) { printf("\t\t[%02d] ", cc); read(fd, buf, 2); idx = TO_16(buf); printf("access 0x%02X ", idx); read(fd, buf, 2); idx = TO_16(buf); printf("name #%d ", idx); read(fd, buf, 2); idx = TO_16(buf); printf("desc #%d ", idx); read(fd, buf, 2); cnt = TO_16(buf); printf("attr_cnt %d\n", cnt); for (ii = 0; ii < cnt; ii++) { int nm, len; printf("\t\t\t[%02d] ", ii); read(fd, buf, 2); nm = TO_16(buf); read(fd, buf, 4); len = TO_32(buf); DumpAttr(fd, nm, len); } } read(fd, buf, 2); attribs_count = TO_16(buf); printf("\tattributes_count: %d\n", attribs_count); for (cc = 0; cc < attribs_count; cc++) { int nm, len; printf("\t\t[%02d] ", cc); read(fd, buf, 2); nm = TO_16(buf); read(fd, buf, 4); len = TO_32(buf); DumpAttr(fd, nm, len); } close(fd); } } return (0); }