//------------------------------------------------------------------------- //--- 010 Editor v2.1 Binary Template // // $Id: CLASSTemplate.bt 65 2007-03-08 16:22:35Z kogrover $ // // File: CLASSTemplate.bt // Author: Kevin O. Grover // Purpose: A template for parsing Java Class (JVM) Files // Version: $Rev: 65 $ // History: // 2007-02-26 kogrover Original Version // // This template was written to the "The Java Virtual Machine Specification", // Second Edition, by Tim Lindholm, Frank Yellin. // // The details used to write this Template came mainly from Chapter 4: // "The class File Format". // // You can get the document from the Sun Java Pages // JVM Spec (all Editions): http://java.sun.com/docs/books/jvms/ // JVM Spec (2nd Edition): // http://java.sun.com/docs/books/vmspec/2nd-edition/html/VMSpecTOC.doc.html //------------------------------------------------------------------------- BigEndian(); // Types used in the JVM Spec. // (To make this code as close to the text in the spec as possible.) typedef uint32 u4; typedef uint16 u2; typedef ubyte u1; typedef enum eACCESS_FLAGS { ACC_PUBLIC = 0x0001, // Declared public; may be accessed from outside its package. ACC_PRIVATE = 0x0002, // Declared private; usable only within the defining class. ACC_PROTECTED = 0x0004, // Declared protected; may be accessed within subclasses. ACC_STATIC = 0x0008, // Declared static. ACC_FINAL = 0x0010, // Declared final; no subclasses allowed. ACC_SUPER = 0x0020, // Treat superclass methods specially when invoked by the invokespecial instruction. ACC_VOLATILE = 0x0040, // Declared volatile; cannot be cached. ACC_TRANSIENT = 0x0080, // Declared transient; not written or read by a persistent object manager. ACC_NATIVE = 0x0100, // Declared native; implemented in a language other than Java. ACC_INTERFACE = 0x0200, // Is an interface, not a class. ACC_ABSTRACT = 0x0400, // Declared abstract; may not be instantiated. ACC_STRICT = 0x0800 // Declared strictfp; floating-point mode is FP-strict } AF ; string read_AF (local AF &af) { local string s = ""; local int commaNeeded = 0; local AF i = 1; SPrintf (s, "%d: ", af); // Iterate over all possible values the flags // if the given bit is set, add it's text representation to the // return string. // NOTE: There's probably a better way to do this. (More portable?) while (i < ACC_STRICT) { if (af && i) { if (commaNeeded) { s += ", "; } s += EnumToString(i); commaNeeded = 1; } i = i << 1; } return s; } // Constants for cp_info.tag ... typedef enum eCP_CONST { CONSTANT_Utf8 = 1, CONSTANT_Integer = 3, CONSTANT_Float = 4, CONSTANT_Long = 5, CONSTANT_Double = 6, CONSTANT_Class = 7, CONSTANT_String = 8, CONSTANT_Fieldref = 9, CONSTANT_Methodref = 10, CONSTANT_InterfaceMethodref = 11, CONSTANT_NameAndType = 12, } CP_CONST; // Constant Pool Table Structure // NOTE: These are NOT constant sized items. Although referenced // like an array in the main structure, you can not use position // to directly infer a byte offset because you do not know the // sizes of the items preceeding it. typedef struct { CP_CONST tag; switch(tag) { case CONSTANT_Class: u2 name_index; break; case CONSTANT_Methodref: case CONSTANT_Fieldref: case CONSTANT_InterfaceMethodref: u2 class_index; u2 name_and_type_index; break; case CONSTANT_Utf8: u2 length; char bytes[length]; break; case CONSTANT_Integer: case CONSTANT_Float: u4 bytes; break; case CONSTANT_Long: case CONSTANT_Double: u4 high_bytes; u4 low_bytes; break; case CONSTANT_String: u2 string_index; break; case CONSTANT_NameAndType: u2 name_index; u2 descriptor_index; break; default: local string s; SPrintf(s, "Unknown 'constant_pool' tag: %d", tag); Warning(s); return -3; } } cp_info ; /** * Reader for 'cp_info' * @param cp_info Constant Pool info structure */ string read_cp_info (local cp_info &i) { local string s = ""; s = EnumToString(i.tag); if (i.tag == CONSTANT_Utf8) { s += ": " + i.bytes; } return s; } typedef struct { u2 attribute_name_index; u4 attribute_length; u1 info[attribute_length]; } attribute_info ; typedef struct { AF access_flags; u2 name_index; u2 descriptor_index; u2 attributes_count; attribute_info attributes[attributes_count]; } field_info ; typedef struct { AF access_flags; u2 name_index; u2 descriptor_index; u2 attributes_count; attribute_info attributes[attributes_count]; } method_info ; // MAIN Structure typedef struct { u4 magic ; if (magic != 0xCAFEBABE) { // Check that 'magic' is correct Warning("Incorrect Magic Number. This is not a JVM Class. Template Terminated."); return -1; } u2 minor_version; u2 major_version; u2 constant_pool_count; cp_info constant_pool[constant_pool_count-1]; AF access_flags; u2 this_class; // Reference into constant_pool table if (this_class < 1 || this_class > constant_pool_count-1) { local string s; SPrintf(s,"Bad 'this_class' reference (%d). It should be in the range [1..%d]", this_class, constant_pool_count-1); Warning(s); return -2; } u2 super_class; // Reference into constant_pool table if (super_class < 1 || super_class > constant_pool_count-1) { local string s; SPrintf(s,"Bad 'super_class' reference (%d). It should be in the range [1..%d]", super_class, constant_pool_count-1); Warning(s); return -2; } u2 interfaces_count; u2 interfaces[interfaces_count]; u2 fields_count; field_info fields[fields_count]; u2 methods_count; method_info methods[methods_count]; u2 attributes_count; attribute_info attributes[attributes_count]; } JVMClass ; /** * Reader for 'JVMClass' * Returns the JVM Version: major.minor and the Java version (if it can * calculate it from the JVM Version. * @param j JVMClass The JVM Class Structure * @return string The version information */ string read_JVMClass (local JVMClass &j) { // JVM Version (as stored in the class file) local string s; SPrintf (s, "JVM class v%d.%d", j.major_version, j.minor_version); // Java Runtime Version. From the JVM Spec for class files local string jre_v = ""; local int ma=1; // JRE Major (Guess at 1.) local int mi=0; // JRE Minor (Guess at .0) switch(j.major_version) { case 45: if (j.minor_version > 3) mi = 1; break; case 46: mi = 2; break; case 47: mi = 3; break; case 48: mi = 4; break; case 49: mi = 5; break; case 50: mi = 6; break; default: // Unknown: it's either newer or older than the // JVM Spec 2nd, Edition, that I used ma = 0; mi = 0; } if (ma || mi) { SPrintf(jre_v, " (Java %d.%d)", ma, mi); s += jre_v; } return s; } // ***************************************** // MAIN - Allocate data here... // ***************************************** struct JVMClass jc;