diff --git a/src/execute/mod.rs b/src/execute/mod.rs new file mode 100644 index 0000000..e3ce5fc --- /dev/null +++ b/src/execute/mod.rs @@ -0,0 +1 @@ +mod model; \ No newline at end of file diff --git a/src/model.rs b/src/execute/model.rs similarity index 82% rename from src/model.rs rename to src/execute/model.rs index e8b6dd9..5a5990e 100644 --- a/src/model.rs +++ b/src/execute/model.rs @@ -1,5 +1,5 @@ pub struct OperandStack { - vec: Vec, + vec: Vec, } impl OperandStack { @@ -9,11 +9,11 @@ impl OperandStack { } } - pub fn pop(&mut self) -> i32 { + pub fn pop(&mut self) -> u32 { self.vec.pop().unwrap() } - pub fn push(&mut self, n: i32) { + pub fn push(&mut self, n: u32) { self.vec.push(n); } @@ -24,7 +24,7 @@ impl OperandStack { } pub struct LocalVariables { - vec: Vec + vec: Vec } impl LocalVariables { @@ -34,19 +34,19 @@ impl LocalVariables { } } - pub fn store(&mut self, address: u16, value: i32) { + pub fn store(&mut self, address: u8, value: u32) { self.vec.insert(address as usize, value); } - pub fn store2(&mut self, address: u16, value1: i32, value2: i32) { + pub fn store2(&mut self, address: u8, value1: u32, value2: u32) { self.vec.insert(address as usize, value1); self.vec.insert(address as usize + 1, value2); } - pub fn load(&self, address: u16) -> i32 { + pub fn load(&self, address: u8) -> u32 { self.vec[address as usize] } - pub fn load2(&self, address: u16) -> (i32, i32) { + pub fn load2(&self, address: u8) -> (u32, u32) { (self.vec[address as usize], self.vec[address as usize + 1]) } diff --git a/src/lib.rs b/src/lib.rs index ee2d47a..14367f3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1,2 @@ -mod model; +mod parse; +mod execute; \ No newline at end of file diff --git a/src/parse/mod.rs b/src/parse/mod.rs new file mode 100644 index 0000000..c880278 --- /dev/null +++ b/src/parse/mod.rs @@ -0,0 +1,3 @@ +mod model; + +pub fn parse_class_file(data: &[u8]) {} diff --git a/src/parse/model.rs b/src/parse/model.rs new file mode 100644 index 0000000..4531509 --- /dev/null +++ b/src/parse/model.rs @@ -0,0 +1,344 @@ +//! +//! The models for a .class file +//! +//! [The .class specs](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html) + +// The types used in the specs +#[allow(non_camel_case_types)] +type u1 = u8; +#[allow(non_camel_case_types)] +type u2 = u16; +#[allow(non_camel_case_types)] +type u4 = u32; + +/// +/// # Represents a .class file +/// +pub struct ClassFile { + /// Magic number identifying the format (= 0xCAFEBABE) + magic: u4, + /// The version of the class file (.X) + minor_version: u2, + /// The version of the class file (X.) + major_version: u2, + /// Number of entries in the constant pool + 1 + constant_pool_count: u2, + /// The constant pool. Indexed from 1 to constant_pool_count - 1 + constant_pool: Vec, + /// Mask of `ClassAccessFlag` used to denote access permissions + access_flags: u2, + /// A valid index into the `constant_pool` table. The entry must be a `ConstantClassInfo` + this_class: u2, + /// Zero or a valid index into the `constant_pool` table + super_class: u2, + /// The number if direct superinterfaces of this class or interface type + interfaces_count: u2, + /// Each entry must be a valid index into the `constant_pool` table. The entry must be a `ConstantClassInfo` + interfaces: Vec, + /// The number of fields in the `fields` table + fields_count: u2, + /// All fields of the class. Contains only fields of the class itself + fields: Vec, + /// The number of methods in `methods` + method_count: u2, + /// All methods of the class. If it's neither Native nor Abstract, the implementation has to be provided too + methods: Vec, + /// The number of attributes in `attributes` + attributes_count: u2, + /// All attributes of the class + attributes: Vec, +} + +/// Access Flags of a class +#[repr(u16)] +enum ClassAccessFlag { + /// Declared public; may be accessed from outside its package. + Public = 0x0001, + /// Declared final; no subclasses allowed. + Final = 0x0010, + /// Treat superclass methods specially when invoked by the invokespecial instruction. + Super = 0x0020, + /// Is an interface, not a class. + Interface = 0x0200, + /// Declared abstract; must not be instantiated. + Abstract = 0x0400, + /// Declared synthetic; not present in the source code. + Synthetic = 0x1000, + /// Declared as an annotation type. + Annotation = 0x2000, + /// Declared as an enum type. + Enum = 0x4000, +} + +/// Access Flags of a method +#[repr(u16)] +enum MethodAccessFlag { + // Declared public; may be accessed from outside its package. + PUBLIC = 0x0001, + // Declared private; accessible only within the defining class. + PRIVATE = 0x0002, + // Declared protected; may be accessed within subclasses. + PROTECTED = 0x0004, + // Declared static. + STATIC = 0x0008, + // Declared final; must not be overridden. + FINAL = 0x0010, + // Declared synchronized; invocation is wrapped by a monitor use. + SYNCHRONIZED = 0x0020, + // A bridge method, generated by the compiler. + BRIDGE = 0x0040, + // Declared with variable number of arguments. + VARARGS = 0x0080, + // Declared native; implemented in a language other than Java. + NATIVE = 0x0100, + // Declared abstract; no implementation is provided. + ABSTRACT = 0x0400, + // Declared strictfp; floating-point mode is FP-strict. + STRICT = 0x0800, + // Declared synthetic; not present in the source code. + SYNTHETIC = 0x1000, +} + +/// A constant from the constant pool +/// May have indices back to the constant pool, with expected types +/// _index: A valid index into the `constant_pool` table. +enum CpInfo { + Class { + tag: u1, // 7 + /// Entry must be `Utf8` + name_index: u2, + }, + Fieldref { + tag: u1, // 9 + /// May be a class or interface type + class_index: u2, + /// Entry must be `NameAndType` + name_and_type_index: u2, + }, + Methodref { + tag: u1, // 10 + /// Must be a class type + class_index: u2, + /// Entry must be `NameAndType` + name_and_type_index: u2, + }, + InterfaceMethodref { + tag: u1, // 11 + /// Must be an interface type + class_index: u2, + /// Entry must be `NameAndType` + name_and_type_index: u2, + }, + String { + tag: u1, // 8 + /// Entry must be `Utf8` + string_index: u2, + }, + Integer { + tag: u1, // 3 + // Big endian + bytes: u4, + }, + Float { + tag: u1, // 4 + /// IEEE 754 floating-point single format, big endian + bytes: u4, + }, + /// 8 byte constants take up two spaces in the constant pool + Long { + tag: u1, // 5 + /// Big endian + high_bytes: u4, + /// Big endian + low_bytes: u4, + }, + /// 8 byte constants take up two spaces in the constant pool + Double { + tag: u1, // 6 + /// IEEE 754 floating-point double format, big endian + high_bytes: u4, + /// IEEE 754 floating-point double format, big endian + low_bytes: u4, + }, + /// Any field or method, without the class it belongs to + NameAndType { + tag: u1, // 12 + /// Entry must be `Utf8` + name_index: u2, + /// Entry must be `Utf8` + descriptor_index: u2, + }, + Utf8 { + tag: u1, // 1 + /// The length of the String. Not null-terminated. + length: u2, + /// Contains modified UTF-8 + bytes: Vec, + }, + MethodHandle { + tag: u1, // 15 + /// The kind of method handle (0-9) + reference_kind: u1, + /// If the kind is 1-4, the entry must be `FieldRef`. If the kind is 5-8, the entry must be `MethodRef` + /// If the kind is 9, the entry must be `InterfaceMethodRef` + reference_index: u2, + }, + MethodType { + tag: u1, // 16 + /// Entry must be `Utf8` + descriptor_index: u2, + }, + InvokeDynamic { + tag: u1, + /// Must be a valid index into the `bootstrap_methods` array of the bootstrap method table of this class fiel + bootstrap_method_attr_index: u2, + /// Entry must `NameAndType` + name_and_type_index: u2, + }, +} + +/// Information about a method +struct MethodInfo { + /// Mask of `MethodAccessFlag` used to denote access permissions + access_flags: u2, + /// Index to the `constant_pool` of the method name, must be `Utf8` + name_index: u2, + /// Index to the `constant_pool` of the method descriptor, must be `Utf8` + descriptor_index: u2, + /// The amount of attributes for this method + attributes_count: u2, + /// The attributes for this method + attributes: Vec, +} + +/// Information about an attribute +/// +/// `attribute_name_index`: Index to the `constant_pool`, must be `Utf8` +/// `attribute_length`: The length of the subsequent bytes, does not include the first 6 +/// +/// _index: Index to the `constant_pool` table of any type +enum AttributeInfo { + /// Only on fields, the constant value of that field + ConstantValue { + attribute_name_index: u2, // "ConstantValue" + attribute_length: u4, + /// Must be of type `Long`/`Float`/`Double`/`Integer`/`String` + constantvalue_index: u2, + }, + /// Only on methods, contains JVM instructions and auxiliary information for a single method + Code { + attribute_name_index: u2, + attribute_length: u4, + /// The maximum depth of the operand stack for this method + max_stack: u2, + /// The number of the local variables array, including the parameters + max_locals: u2, + /// The length of the JVM bytecode in bytes + code_length: u4, + /// The JVM bytecode of this method + code: Vec, + /// The number of entries in the exception table + exception_table_length: u2, + /// The exception handlers for this method + exception_table: Vec, + attributes_count: u2, + /// The attributes of the code + attributes: Vec, + }, + /// Only on the `Code` attribute, used for verification + /// May be implicit on version >= 50.0, with no entries + StackMapTable { + attribute_name_index: u2, + attribute_length: u4, + number_of_entries: u2, + entries: Vec, + }, + Exceptions { + attribute_name_index: u2, + attribute_length: u4, + }, + InnerClasses { + attribute_name_index: u2, + attribute_length: u4, + }, + EnclosingMethod { + attribute_name_index: u2, + attribute_length: u4, + }, + Synthetic { + attribute_name_index: u2, + attribute_length: u4, + }, + Signature { + attribute_name_index: u2, + attribute_length: u4, + }, + SourceFile { + attribute_name_index: u2, + attribute_length: u4, + }, + SourceDebugExtension { + attribute_name_index: u2, + attribute_length: u4, + }, + LineNumberTable { + attribute_name_index: u2, + attribute_length: u4, + }, + LocalVariableTable { + attribute_name_index: u2, + attribute_length: u4, + }, + LocalVariableTypeTable { + attribute_name_index: u2, + attribute_length: u4, + }, + Deprecated { + attribute_name_index: u2, + attribute_length: u4, + }, + RuntimeVisibleAnnotations { + attribute_name_index: u2, + attribute_length: u4, + }, + RuntimeInvisibleAnnotations { + attribute_name_index: u2, + attribute_length: u4, + }, + RuntimeVisibleParameterAnnotations { + attribute_name_index: u2, + attribute_length: u4, + }, + RuntimeInvisibleParameterAnnotations { + attribute_name_index: u2, + attribute_length: u4, + }, + AnnotationDefault { + attribute_name_index: u2, + attribute_length: u4, + }, + BootstrapMethods { + attribute_name_index: u2, + attribute_length: u4, + }, +} + +/// An exception handler in the JVM bytecode array +struct AttributeCodeException { + /// The ranges in the code in which the handler is active. Must be a valid index into the code array. + /// The `start_pc` is inclusive + start_pc: u2, + /// The ranges in the code in which the handler is active. Must be a valid index into the code array or the length. + /// The `end_pc` is exclusive + end_pc: u2, + /// The start of the exception handler, must be a valid index into the code array at an opcode instruction + handler_pc: u2, + /// If the catch type is nonzero, it must be a valid index into the `constant_pool`, must be a `Class` + /// Zero means it catches all Exceptions, this is usually for `finally` + catch_type: u2, +} + +type StackMapFrame = u8; + +/// Information about a field +type FieldInfo = u8;