btparser/cparser/tests/CLASSTemplate.bt

254 lines
8.0 KiB
Plaintext
Raw Normal View History

//-------------------------------------------------------------------------
//--- 010 Editor v2.1 Binary Template
//
// File: CLASSTemplate.bt
// Author: Kevin O. Grover <kevin@kevingrover.net>
// Purpose: A template for parsing Java Class (JVM) Files
// Version: 1.1 2014-08-13
// History:
// 2007-02-26 kog Original Version
// 2014-08-13 kog Updated for Java 7/8 Version number (and future)
//
// This template was written to the "The Java Virtual Machine
// Specification", Second Edition, by Tim Lindholm, Frank Yellin.
// It was later updated to include the provisio in that spec (and future
// specs).
//
// The details used to write this Template came mainly from Chapter 4:
// "The <code>class</code> File Format".
//
// You can get the document from the Oracle Java Pages or Wikipedia:
// http://docs.oracle.com/javase/specs/
// http://docs.oracle.com/javase/specs/jvms/se7/jvms7.pdf
// http://docs.oracle.com/javase/specs/jvms/se8/jvms8.pdf
// http://en.wikipedia.org/wiki/Class_file
//-------------------------------------------------------------------------
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 <u2> 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 <read=read_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 <u1> 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 <read=read_cp_info, optimize=false>;
/**
* 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 <optimize=false>;
typedef struct {
AF access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
} field_info <optimize=false>;
typedef struct {
AF access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
} method_info <optimize=false>;
// MAIN Structure
typedef struct {
u4 magic <format=hex>;
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 <read=read_JVMClass, optimize=false>;
/**
* 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 int major = 1;
local int minor = 0;
if (j.major_version == 45) {
if (j.minor_version >= 3) minor = 1;
} else {
if (j.major_version >= 46) {
minor = j.major_version - 44;
} else {
// Unknown: it's either newer or older than expected
major = 0;
minor = 0;
Warning("Unexpected JVM major version number.");
}
}
if (major || minor) {
local string jre_v;
SPrintf(jre_v, " (Java %d.%d)", major, minor);
s += jre_v;
} else {
s += " (Unknown Java Version)";
}
return s;
}
// *****************************************
// MAIN - Allocate data here...
// *****************************************
struct JVMClass jc;