├── .gitignore ├── Cargo.toml ├── README.md ├── classfile ├── Cargo.toml └── src │ ├── attr │ ├── info │ │ ├── classfile │ │ │ ├── inner_classes.rs │ │ │ └── mod.rs │ │ ├── code │ │ │ ├── line_number.rs │ │ │ ├── local_variable.rs │ │ │ ├── mod.rs │ │ │ └── stack_map │ │ │ │ ├── frame.rs │ │ │ │ └── mod.rs │ │ ├── field.rs │ │ ├── macros.rs │ │ ├── method │ │ │ ├── code.rs │ │ │ ├── exception.rs │ │ │ └── mod.rs │ │ ├── misc │ │ │ ├── annotations.rs │ │ │ ├── mod.rs │ │ │ └── signature.rs │ │ └── mod.rs │ └── mod.rs │ ├── constant │ ├── error.rs │ └── mod.rs │ ├── error.rs │ ├── field.rs │ ├── lib.rs │ ├── method.rs │ ├── utils │ ├── io.rs │ ├── macros.rs │ ├── mod.rs │ ├── print.rs │ └── vec.rs │ └── version.rs └── src ├── bin └── rjvm.rs ├── classpath └── mod.rs └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # Rust files 2 | target 3 | Cargo.lock 4 | 5 | # Java files 6 | *.class 7 | 8 | # IDE / Editor files 9 | *.sublime-* 10 | 11 | # Misc files 12 | .* 13 | !.gitignore 14 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["classfile"] 3 | 4 | [package] 5 | name = "jvm" 6 | version = "0.1.0" 7 | authors = ["KokaKiwi "] 8 | 9 | [dependencies] 10 | clap = { version = "*", features = ["unstable"] } 11 | env_logger = "*" 12 | error-chain = "*" 13 | jvm-classfile = { path = "classfile" } 14 | log = "*" 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | rust-jvm 2 | ======== 3 | 4 | A basic experiment about implementing the JVM (Java SE 8) in Rust (http://www.rust-lang.org), maybe inspired by 5 | [jvm.go](https://github.com/zxh0/jvm.go) 6 | 7 | Current status: `WIP` 8 | 9 | Documentation: http://kokakiwi.github.io/rust-jvm/jvm/index.html 10 | 11 | JVM specification documentation: https://docs.oracle.com/javase/specs/jvms/se8/html/ 12 | 13 | Currently, the library can only parse almost all the Java .class file and print it. 14 | 15 | The `rjvm` executable only take a class name, parse it and print it. 16 | 17 | TO-DO List 18 | ---------- 19 | 20 | - [ ] Read `*.class` files 21 | - [ ] Read attributes 22 | - [ ] Read `BootstrapMethods` attribute 23 | - [ ] Read `RuntimeVisibleParameterAnnotations` attribute 24 | - [ ] Read `RuntimeInvisibleParameterAnnotations` attribute 25 | - [ ] Read `AnnotationDefault` attribute 26 | - [ ] Read `MethodParameters` attribute 27 | - [ ] Read `LocalVariableTypeTable` attribute 28 | - [ ] Read `RuntimeInvisibleAnnotations` attribute 29 | - [ ] Read `RuntimeVisibleTypeAnnotations` attribute 30 | - [ ] Read `RuntimeInvisibleTypeAnnotations` attribute 31 | - [ ] Read `StackMapTable` attribute 32 | - [ ] Read `StackMapFrame` struct 33 | - [ ] Read `VerificationTypeInfo` struct 34 | - [ ] Implement classpath structs 35 | -------------------------------------------------------------------------------- /classfile/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "jvm-classfile" 3 | version = "0.1.0" 4 | authors = ["KokaKiwi "] 5 | description = "Java class files reader" 6 | 7 | [dependencies] 8 | bitflags = "1.0" 9 | byteorder = "1.0" 10 | error-chain = "*" 11 | -------------------------------------------------------------------------------- /classfile/src/attr/info/classfile/inner_classes.rs: -------------------------------------------------------------------------------- 1 | use constant::{ConstantPool, ConstantClassInfo}; 2 | use error::*; 3 | 4 | #[derive(Debug)] 5 | pub struct InnerClassesAttrInfo { 6 | pub classes: Vec, 7 | } 8 | 9 | impl_read! { 10 | InnerClassesAttrInfo(reader, _constant_pool: &ConstantPool) -> Result = { 11 | let classes_count = try!(reader.read_u16::()) as usize; 12 | let mut classes = Vec::with_capacity(classes_count); 13 | for _ in 0..classes_count { 14 | let class = try!(Class::read(reader)); 15 | classes.push(class); 16 | } 17 | 18 | Ok(InnerClassesAttrInfo { 19 | classes: classes, 20 | }) 21 | } 22 | } 23 | 24 | impl_print! { 25 | InnerClassesAttrInfo(self, printer, constant_pool: &ConstantPool) { 26 | for class in self.classes.iter() { 27 | try!(printer.write_indent()); 28 | try!(writeln!(printer, "Class:")); 29 | 30 | try!(class.print(&mut printer.sub_indent(1), constant_pool)); 31 | } 32 | } 33 | } 34 | 35 | #[derive(Debug)] 36 | pub struct Class { 37 | inner_class_info_index: usize, 38 | outer_class_info_index: usize, 39 | inner_name_index: usize, 40 | pub inner_class_access_flags: flags::AccessFlags, 41 | } 42 | 43 | impl Class { 44 | pub fn inner_class_info<'a>(&self, constant_pool: &'a ConstantPool) -> Option<&'a ConstantClassInfo> { 45 | constant_pool.get_class_info(self.inner_class_info_index) 46 | } 47 | 48 | pub fn outer_class_info<'a>(&self, constant_pool: &'a ConstantPool) -> Option<&'a ConstantClassInfo> { 49 | if self.outer_class_info_index != 0 { 50 | constant_pool.get_class_info(self.outer_class_info_index) 51 | } else { 52 | None 53 | } 54 | } 55 | 56 | pub fn inner_name<'a>(&self, constant_pool: &'a ConstantPool) -> Option<&'a str> { 57 | if self.inner_name_index != 0 { 58 | constant_pool.get_str(self.inner_name_index) 59 | } else { 60 | None 61 | } 62 | } 63 | } 64 | 65 | impl_read! { 66 | Class(reader) -> Result = { 67 | let inner_class_info_index = try!(reader.read_u16::()) as usize; 68 | let outer_class_info_index = try!(reader.read_u16::()) as usize; 69 | let inner_name_index = try!(reader.read_u16::()) as usize; 70 | let inner_class_access_flags = try!(reader.read_u16::()); 71 | let inner_class_access_flags = match flags::AccessFlags::from_bits(inner_class_access_flags) { 72 | Some(flags) => flags, 73 | None => bail!(ErrorKind::BadAccessFlags(inner_class_access_flags)), 74 | }; 75 | 76 | Ok(Class { 77 | inner_class_info_index: inner_class_info_index, 78 | outer_class_info_index: outer_class_info_index, 79 | inner_name_index: inner_name_index, 80 | inner_class_access_flags: inner_class_access_flags, 81 | }) 82 | } 83 | } 84 | 85 | impl_print! { 86 | Class(self, printer, constant_pool: &ConstantPool) { 87 | let inner_class_info = self.inner_class_info(constant_pool).expect("Invalid index"); 88 | 89 | try!(printer.write_indent()); 90 | try!(write!(printer, "Inner class: ")); 91 | try!(inner_class_info.print(printer, constant_pool)); 92 | try!(writeln!(printer, "")); 93 | 94 | try!(printer.write_indent()); 95 | try!(writeln!(printer, "Access flags: {:?}", self.inner_class_access_flags)); 96 | 97 | if let Some(outer_class_info) = self.outer_class_info(constant_pool) { 98 | try!(printer.write_indent()); 99 | try!(write!(printer, "Outer class: ")); 100 | try!(outer_class_info.print(printer, constant_pool)); 101 | try!(writeln!(printer, "")); 102 | } 103 | 104 | if let Some(inner_name) = self.inner_name(constant_pool) { 105 | try!(printer.write_indent()); 106 | try!(writeln!(printer, "Inner name: {}", inner_name)); 107 | } 108 | } 109 | } 110 | 111 | pub mod flags { 112 | bitflags! { 113 | pub struct AccessFlags: u16 { 114 | #[doc = "Marked or implicitly public in source."] 115 | const ACC_PUBLIC = 0x0001; 116 | #[doc = "Marked private in source."] 117 | const ACC_PRIVATE = 0x0002; 118 | #[doc = "Marked protected in source."] 119 | const ACC_PROTECTED = 0x0004; 120 | #[doc = "Marked or implicitly static in source."] 121 | const ACC_STATIC = 0x0008; 122 | #[doc = "Marked final in source."] 123 | const ACC_FINAL = 0x0010; 124 | #[doc = "Was an interface in source."] 125 | const ACC_INTERFACE = 0x0200; 126 | #[doc = "Marked or implicitly abstract in source."] 127 | const ACC_ABSTRACT = 0x0400; 128 | #[doc = "Declared synthetic; not present in the source code."] 129 | const ACC_SYNTHETIC = 0x1000; 130 | #[doc = "Declared as an annotation type."] 131 | const ACC_ANNOTATION = 0x2000; 132 | #[doc = "Declared as an enum type."] 133 | const ACC_ENUM = 0x4000; 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /classfile/src/attr/info/classfile/mod.rs: -------------------------------------------------------------------------------- 1 | use constant::{ConstantPool, ConstantPoolEntry, ConstantClassInfo, ConstantNameAndTypeInfo}; 2 | use error::Result; 3 | pub use self::inner_classes::InnerClassesAttrInfo; 4 | 5 | pub mod inner_classes; 6 | 7 | #[derive(Debug)] 8 | pub struct SourceFileAttrInfo { 9 | sourcefile_index: usize, 10 | } 11 | 12 | impl SourceFileAttrInfo { 13 | pub fn sourcefile<'a>(&self, constant_pool: &'a ConstantPool) -> Option<&'a str> { 14 | constant_pool.get_str(self.sourcefile_index) 15 | } 16 | } 17 | 18 | impl_read! { 19 | SourceFileAttrInfo(reader, _constant_pool: &ConstantPool) -> Result = { 20 | let sourcefile_index = try!(reader.read_u16::()) as usize; 21 | 22 | Ok(SourceFileAttrInfo { 23 | sourcefile_index: sourcefile_index, 24 | }) 25 | } 26 | } 27 | 28 | impl_print! { 29 | SourceFileAttrInfo(self, printer, constant_pool: &ConstantPool) { 30 | let sourcefile = self.sourcefile(constant_pool).expect("Invalid index"); 31 | 32 | try!(printer.write_indent()); 33 | try!(writeln!(printer, "Source file: {}", sourcefile)); 34 | } 35 | } 36 | 37 | #[derive(Debug)] 38 | pub struct EnclosingMethodAttrInfo { 39 | class_index: usize, 40 | method_index: usize, 41 | } 42 | 43 | impl EnclosingMethodAttrInfo { 44 | pub fn class<'a>(&self, constant_pool: &'a ConstantPool) -> Option<&'a ConstantClassInfo> { 45 | constant_pool.get_class_info(self.class_index) 46 | } 47 | 48 | pub fn method<'a>(&self, constant_pool: &'a ConstantPool) -> Option<&'a ConstantNameAndTypeInfo> { 49 | if self.method_index != 0 { 50 | constant_pool.get(self.method_index).and_then(|entry| match entry { 51 | &ConstantPoolEntry::NameAndType(ref info) => Some(info), 52 | _ => None, 53 | }) 54 | } else { 55 | None 56 | } 57 | } 58 | } 59 | 60 | impl_read! { 61 | EnclosingMethodAttrInfo(reader, _constant_pool: &ConstantPool) -> Result = { 62 | let class_index = try!(reader.read_u16::()) as usize; 63 | let method_index = try!(reader.read_u16::()) as usize; 64 | 65 | Ok(EnclosingMethodAttrInfo { 66 | class_index: class_index, 67 | method_index: method_index, 68 | }) 69 | } 70 | } 71 | 72 | impl_print! { 73 | EnclosingMethodAttrInfo(self, printer, constant_pool: &ConstantPool) { 74 | let class = self.class(constant_pool).expect("Invalid class index"); 75 | 76 | try!(printer.write_indent()); 77 | try!(class.print(printer, constant_pool)); 78 | try!(writeln!(printer, "")); 79 | 80 | if let Some(method) = self.method(constant_pool) { 81 | try!(printer.write_indent()); 82 | try!(method.print(printer, constant_pool)); 83 | try!(writeln!(printer, "")); 84 | } 85 | } 86 | } 87 | 88 | #[derive(Debug)] 89 | pub struct SourceDebugExtensionAttrInfo { 90 | pub data: String, 91 | } 92 | 93 | impl_read! { 94 | SourceDebugExtensionAttrInfo(reader, _constant_pool: &ConstantPool) -> Result = { 95 | let mut data = String::new(); 96 | try!(reader.read_to_string(&mut data)); 97 | 98 | Ok(SourceDebugExtensionAttrInfo { 99 | data: data, 100 | }) 101 | } 102 | } 103 | 104 | impl_print! { 105 | SourceDebugExtensionAttrInfo(self, printer, _constant_pool: &ConstantPool) { 106 | try!(printer.write_indent()); 107 | try!(writeln!(printer, "{}", self.data)); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /classfile/src/attr/info/code/line_number.rs: -------------------------------------------------------------------------------- 1 | use constant::ConstantPool; 2 | use error::Result; 3 | use std::slice::Iter; 4 | 5 | #[derive(Debug)] 6 | pub struct LineNumberTableAttrInfo { 7 | entries: Vec, 8 | } 9 | 10 | impl LineNumberTableAttrInfo { 11 | pub fn entries<'a>(&'a self) -> Iter<'a, LineNumber> { 12 | self.entries.iter() 13 | } 14 | } 15 | 16 | impl_read! { 17 | LineNumberTableAttrInfo(reader, _constant_pool: &ConstantPool) -> Result = { 18 | // Read entries 19 | let entries_count = try!(reader.read_u16::()) as usize; 20 | let mut entries = Vec::with_capacity(entries_count); 21 | for _ in 0..entries_count { 22 | let entry = try!(LineNumber::read(reader)); 23 | entries.push(entry); 24 | } 25 | 26 | Ok(LineNumberTableAttrInfo { 27 | entries: entries, 28 | }) 29 | } 30 | } 31 | 32 | impl_print! { 33 | LineNumberTableAttrInfo(self, printer) { 34 | for entry in self.entries() { 35 | try!(printer.write_indent()); 36 | try!(entry.print(printer)); 37 | try!(writeln!(printer, "")); 38 | } 39 | } 40 | } 41 | 42 | #[derive(Debug)] 43 | pub struct LineNumber { 44 | pub start_pc: usize, 45 | pub line_number: usize, 46 | } 47 | 48 | impl_read! { 49 | LineNumber(reader) -> Result = { 50 | let start_pc = try!(reader.read_u16::()) as usize; 51 | let line_number = try!(reader.read_u16::()) as usize; 52 | 53 | Ok(LineNumber { 54 | start_pc: start_pc, 55 | line_number: line_number, 56 | }) 57 | } 58 | } 59 | 60 | impl_print! { 61 | LineNumber(self, printer) { 62 | try!(write!(printer, "{:#x} = Line {}", self.start_pc, self.line_number)); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /classfile/src/attr/info/code/local_variable.rs: -------------------------------------------------------------------------------- 1 | use constant::ConstantPool; 2 | use error::Result; 3 | use std::slice::Iter; 4 | 5 | #[derive(Debug)] 6 | pub struct LocalVariableTableAttrInfo { 7 | entries: Vec, 8 | } 9 | 10 | impl LocalVariableTableAttrInfo { 11 | pub fn entries<'a>(&'a self) -> Iter<'a, LocalVariable> { 12 | self.entries.iter() 13 | } 14 | } 15 | 16 | impl_read! { 17 | LocalVariableTableAttrInfo(reader, _constant_pool: &ConstantPool) -> Result = { 18 | let entries_count = try!(reader.read_u16::()) as usize; 19 | let mut entries = Vec::with_capacity(entries_count); 20 | for _ in 0..entries_count { 21 | let entry = try!(LocalVariable::read(reader)); 22 | entries.push(entry); 23 | } 24 | 25 | Ok(LocalVariableTableAttrInfo { 26 | entries: entries, 27 | }) 28 | } 29 | } 30 | 31 | impl_print! { 32 | LocalVariableTableAttrInfo(self, printer, constant_pool: &ConstantPool) { 33 | for entry in self.entries() { 34 | try!(entry.print(printer, constant_pool)); 35 | } 36 | } 37 | } 38 | 39 | #[derive(Debug)] 40 | pub struct LocalVariable { 41 | pub start_pc: usize, 42 | pub length: usize, 43 | name_index: usize, 44 | desc_index: usize, 45 | pub index: usize, 46 | } 47 | 48 | impl LocalVariable { 49 | pub fn name<'a>(&self, constant_pool: &'a ConstantPool) -> Option<&'a str> { 50 | constant_pool.get_str(self.name_index) 51 | } 52 | 53 | pub fn desc<'a>(&self, constant_pool: &'a ConstantPool) -> Option<&'a str> { 54 | constant_pool.get_str(self.desc_index) 55 | } 56 | } 57 | 58 | impl_read! { 59 | LocalVariable(reader) -> Result = { 60 | let start_pc = try!(reader.read_u16::()) as usize; 61 | let length = try!(reader.read_u16::()) as usize; 62 | let name_index = try!(reader.read_u16::()) as usize; 63 | let desc_index = try!(reader.read_u16::()) as usize; 64 | let index = try!(reader.read_u16::()) as usize; 65 | 66 | Ok(LocalVariable { 67 | start_pc: start_pc, 68 | length: length, 69 | name_index: name_index, 70 | desc_index: desc_index, 71 | index: index, 72 | }) 73 | } 74 | } 75 | 76 | impl_print! { 77 | LocalVariable(self, printer, constant_pool: &ConstantPool) { 78 | let name = self.name(constant_pool).expect("Invalid name index"); 79 | let desc = self.desc(constant_pool).expect("Invalid desc index"); 80 | 81 | let start = self.start_pc; 82 | let end = start + self.length; 83 | 84 | try!(printer.write_indent()); 85 | try!(writeln!(printer, "Local variable `{}` [{}] @ {:#x}:", name, desc, self.index)); 86 | 87 | { 88 | let mut printer = printer.sub_indent(1); 89 | 90 | try!(printer.write_indent()); 91 | try!(writeln!(printer, "Location: [{:#x}:{:#x}]", start, end)); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /classfile/src/attr/info/code/mod.rs: -------------------------------------------------------------------------------- 1 | pub use self::line_number::LineNumberTableAttrInfo; 2 | pub use self::local_variable::LocalVariableTableAttrInfo; 3 | pub use self::stack_map::StackMapTableAttrInfo; 4 | 5 | pub mod line_number; 6 | pub mod local_variable; 7 | pub mod stack_map; 8 | -------------------------------------------------------------------------------- /classfile/src/attr/info/code/stack_map/frame.rs: -------------------------------------------------------------------------------- 1 | use error::Result; 2 | 3 | #[derive(Debug)] 4 | pub struct StackMapFrame { 5 | tag: u8, 6 | pub info: StackMapFrameInfo, 7 | } 8 | 9 | impl StackMapFrame { 10 | pub fn offset_delta(&self) -> usize { 11 | match self.info { 12 | StackMapFrameInfo::SameFrame => self.tag as usize, 13 | StackMapFrameInfo::SameLocalsOneStackItemFrame(..) => self.tag as usize - 64, 14 | StackMapFrameInfo::SameLocalsOneStackItemFrameExtended(ref info) => info.offset_delta as usize, 15 | StackMapFrameInfo::ChopFrame(ref info) => info.offset_delta as usize, 16 | StackMapFrameInfo::SameFrameExtended(ref info) => info.offset_delta as usize, 17 | StackMapFrameInfo::AppendFrame(ref info) => info.offset_delta as usize, 18 | StackMapFrameInfo::FullFrame(ref info) => info.offset_delta as usize, 19 | } 20 | } 21 | 22 | pub fn offset(&self, frames: &[StackMapFrame]) -> usize { 23 | match frames.split_last() { 24 | Some((ref last, frames)) => last.offset(frames) + self.offset_delta() + 1, 25 | None => self.offset_delta(), 26 | } 27 | } 28 | } 29 | 30 | impl_read! { 31 | StackMapFrame(reader) -> Result = { 32 | let tag = try!(reader.read_u8()); 33 | let info = try!(StackMapFrameInfo::read(reader, tag)); 34 | 35 | Ok(StackMapFrame { 36 | tag: tag, 37 | info: info, 38 | }) 39 | } 40 | } 41 | 42 | impl_print! { 43 | StackMapFrame(self, printer, frames: &[StackMapFrame]) { 44 | try!(printer.write_indent()); 45 | try!(writeln!(printer, "{} ({:#x}):", self.info.name(), self.offset(frames))); 46 | 47 | try!(self.info.print(&mut printer.sub_indent(1), self, frames)); 48 | } 49 | } 50 | 51 | #[derive(Debug)] 52 | pub enum StackMapFrameInfo { 53 | SameFrame, 54 | SameLocalsOneStackItemFrame(SameLocalsOneStackItemFrameInfo), 55 | SameLocalsOneStackItemFrameExtended(SameLocalsOneStackItemFrameExtendedInfo), 56 | ChopFrame(ChopFrameInfo), 57 | SameFrameExtended(SameFrameExtendedInfo), 58 | AppendFrame(AppendFrameInfo), 59 | FullFrame(FullFrameInfo), 60 | } 61 | 62 | impl StackMapFrameInfo { 63 | fn name(&self) -> &'static str { 64 | match *self { 65 | StackMapFrameInfo::SameFrame => "SameFrame", 66 | StackMapFrameInfo::SameLocalsOneStackItemFrame(..) => "SameLocalsOneStackItemFrame", 67 | StackMapFrameInfo::SameLocalsOneStackItemFrameExtended(..) => "SameLocalsOneStackItemFrameExtended", 68 | StackMapFrameInfo::ChopFrame(..) => "ChopFrame", 69 | StackMapFrameInfo::SameFrameExtended(..) => "SameFrameExtended", 70 | StackMapFrameInfo::AppendFrame(..) => "AppendFrame", 71 | StackMapFrameInfo::FullFrame(..) => "FullFrame", 72 | } 73 | } 74 | } 75 | 76 | impl_read! { 77 | StackMapFrameInfo(reader, tag: u8) -> Result = { 78 | use error::Error; 79 | 80 | let info = match tag { 81 | 0...63 => StackMapFrameInfo::SameFrame, 82 | 64...127 => StackMapFrameInfo::SameLocalsOneStackItemFrame( 83 | try!(SameLocalsOneStackItemFrameInfo::read(reader, tag)) 84 | ), 85 | 128...246 => panic!("Reserved tag"), 86 | 247 => StackMapFrameInfo::SameLocalsOneStackItemFrameExtended( 87 | try!(SameLocalsOneStackItemFrameExtendedInfo::read(reader, tag)) 88 | ), 89 | 248...250 => StackMapFrameInfo::ChopFrame(try!(ChopFrameInfo::read(reader, tag))), 90 | 251 => StackMapFrameInfo::SameFrameExtended( 91 | try!(SameFrameExtendedInfo::read(reader, tag)) 92 | ), 93 | 252...254 => StackMapFrameInfo::AppendFrame(try!(AppendFrameInfo::read(reader, tag))), 94 | 255 => StackMapFrameInfo::FullFrame(try!(FullFrameInfo::read(reader, tag))), 95 | _ => unreachable!(), 96 | }; 97 | 98 | Ok(info) 99 | } 100 | } 101 | 102 | impl_print! { 103 | StackMapFrameInfo(self, printer, _frame: &StackMapFrame, _frames: &[StackMapFrame]) { 104 | try!(printer.write_indent()); 105 | try!(writeln!(printer, "[ data ]")); 106 | } 107 | } 108 | 109 | #[derive(Debug)] 110 | pub struct SameLocalsOneStackItemFrameInfo { 111 | type_info: (), // TODO: Create VerificationTypeInfo type 112 | } 113 | 114 | impl_read! { 115 | SameLocalsOneStackItemFrameInfo(_reader, _tag: u8) -> Result = { 116 | Ok(SameLocalsOneStackItemFrameInfo { 117 | type_info: (), 118 | }) 119 | } 120 | } 121 | 122 | #[derive(Debug)] 123 | pub struct SameLocalsOneStackItemFrameExtendedInfo { 124 | offset_delta: u16, 125 | type_info: (), // TODO: Create VerificationTypeInfo type 126 | } 127 | 128 | impl_read! { 129 | SameLocalsOneStackItemFrameExtendedInfo(reader, _tag: u8) -> Result = { 130 | let offset_delta = try!(reader.read_u16::()); 131 | 132 | Ok(SameLocalsOneStackItemFrameExtendedInfo { 133 | offset_delta: offset_delta, 134 | type_info: (), 135 | }) 136 | } 137 | } 138 | 139 | #[derive(Debug)] 140 | pub struct ChopFrameInfo { 141 | offset_delta: u16, 142 | } 143 | 144 | impl_read! { 145 | ChopFrameInfo(reader, _tag: u8) -> Result = { 146 | let offset_delta = try!(reader.read_u16::()); 147 | 148 | Ok(ChopFrameInfo { 149 | offset_delta: offset_delta, 150 | }) 151 | } 152 | } 153 | 154 | #[derive(Debug)] 155 | pub struct SameFrameExtendedInfo { 156 | offset_delta: u16, 157 | } 158 | 159 | impl_read! { 160 | SameFrameExtendedInfo(reader, _tag: u8) -> Result = { 161 | let offset_delta = try!(reader.read_u16::()); 162 | 163 | Ok(SameFrameExtendedInfo { 164 | offset_delta: offset_delta, 165 | }) 166 | } 167 | } 168 | 169 | #[derive(Debug)] 170 | pub struct AppendFrameInfo { 171 | offset_delta: u16, 172 | locals: Vec<()>, 173 | } 174 | 175 | impl_read! { 176 | AppendFrameInfo(reader, _tag: u8) -> Result = { 177 | let offset_delta = try!(reader.read_u16::()); 178 | 179 | Ok(AppendFrameInfo { 180 | offset_delta: offset_delta, 181 | locals: Vec::new(), 182 | }) 183 | } 184 | } 185 | 186 | #[derive(Debug)] 187 | pub struct FullFrameInfo { 188 | offset_delta: u16, 189 | locals: Vec<()>, 190 | stack: Vec<()>, 191 | } 192 | 193 | impl_read! { 194 | FullFrameInfo(reader, _tag: u8) -> Result = { 195 | let offset_delta = try!(reader.read_u16::()); 196 | 197 | Ok(FullFrameInfo { 198 | offset_delta: offset_delta, 199 | locals: Vec::new(), 200 | stack: Vec::new(), 201 | }) 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /classfile/src/attr/info/code/stack_map/mod.rs: -------------------------------------------------------------------------------- 1 | use constant::ConstantPool; 2 | use error::Result; 3 | use self::frame::StackMapFrame; 4 | 5 | pub mod frame; 6 | 7 | #[derive(Debug)] 8 | pub struct StackMapTableAttrInfo { 9 | entries: Vec, 10 | } 11 | 12 | impl_read! { 13 | StackMapTableAttrInfo(reader, _constant_pool: &ConstantPool) -> Result = { 14 | let entries_count = try!(reader.read_u16::()) as usize; 15 | let mut entries = Vec::with_capacity(entries_count); 16 | for _ in 0..entries_count { 17 | let entry = try!(StackMapFrame::read(reader)); 18 | entries.push(entry); 19 | } 20 | 21 | Ok(StackMapTableAttrInfo { 22 | entries: entries, 23 | }) 24 | } 25 | } 26 | 27 | impl_print! { 28 | StackMapTableAttrInfo(self, printer, _constant_pool: &ConstantPool) { 29 | for (i, entry) in self.entries.iter().enumerate() { 30 | try!(entry.print(printer, &self.entries[0..i])); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /classfile/src/attr/info/field.rs: -------------------------------------------------------------------------------- 1 | use constant::{ConstantPool, ConstantPoolEntry}; 2 | use error::Result; 3 | use byteorder::{ReadBytesExt, BigEndian}; 4 | use std::io::Read; 5 | 6 | #[derive(Debug)] 7 | pub struct ConstantValueAttrInfo { 8 | value_index: usize, 9 | } 10 | 11 | impl ConstantValueAttrInfo { 12 | pub fn read(reader: &mut R, _pool: &ConstantPool) -> Result { 13 | let value_index = try!(reader.read_u16::()) as usize; 14 | 15 | Ok(ConstantValueAttrInfo { 16 | value_index: value_index, 17 | }) 18 | } 19 | 20 | pub fn value<'a>(&self, pool: &'a ConstantPool) -> Option<&'a ConstantPoolEntry> { 21 | pool.get(self.value_index) 22 | } 23 | } 24 | 25 | impl_print! { 26 | ConstantValueAttrInfo(self, printer, constant_pool: &ConstantPool) { 27 | let value = self.value(constant_pool).expect("Invalid value index"); 28 | 29 | try!(printer.write_indent()); 30 | try!(value.print(printer, constant_pool)); 31 | try!(writeln!(printer, "")); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /classfile/src/attr/info/macros.rs: -------------------------------------------------------------------------------- 1 | 2 | macro_rules! empty_attr_info { 3 | ($name:ident) => { 4 | #[derive(Debug)] 5 | pub struct $name; 6 | 7 | impl $name { 8 | pub fn read(_reader: &mut R, _constant_pool: &$crate::constant::ConstantPool) -> $crate::error::Result<$name> { 9 | Ok($name) 10 | } 11 | } 12 | 13 | impl_print! { 14 | $name(self, _printer) {} 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /classfile/src/attr/info/method/code.rs: -------------------------------------------------------------------------------- 1 | use attr::Attr; 2 | use constant::{ConstantPool, ConstantClassInfo}; 3 | use error::Result; 4 | 5 | #[derive(Debug)] 6 | pub struct CodeAttrInfo { 7 | pub max_stack: usize, 8 | pub max_locals: usize, 9 | pub code: Vec, 10 | pub exception_handlers: Vec, 11 | pub attrs: Vec, 12 | } 13 | 14 | impl_read! { 15 | CodeAttrInfo(reader, constant_pool: &ConstantPool) -> Result = { 16 | use utils::io::ReadExt; 17 | 18 | // Read indexes 19 | let max_stack = try!(reader.read_u16::()) as usize; 20 | let max_locals = try!(reader.read_u16::()) as usize; 21 | 22 | // Read code 23 | let code_size = try!(reader.read_u32::()) as usize; 24 | let code = try!(reader.read_vec(code_size)); 25 | 26 | // Read exception table 27 | let exception_handlers_count = try!(reader.read_u16::()) as usize; 28 | let mut exception_handlers = Vec::with_capacity(exception_handlers_count); 29 | for _ in 0..exception_handlers_count { 30 | let exception_handler = try!(ExceptionHandler::read(reader)); 31 | exception_handlers.push(exception_handler); 32 | } 33 | 34 | // Read attributes 35 | let attrs_count = try!(reader.read_u16::()) as usize; 36 | let mut attrs = Vec::with_capacity(attrs_count); 37 | for _ in 0..attrs_count { 38 | let attr = try!(Attr::read(reader, constant_pool)); 39 | attrs.push(attr); 40 | } 41 | 42 | Ok(CodeAttrInfo { 43 | max_stack: max_stack, 44 | max_locals: max_locals, 45 | code: code, 46 | exception_handlers: exception_handlers, 47 | attrs: attrs, 48 | }) 49 | } 50 | } 51 | 52 | impl_print! { 53 | CodeAttrInfo(self, printer, constant_pool: &ConstantPool) { 54 | try!(printer.write_indent()); 55 | try!(writeln!(printer, "Max stack: {}", self.max_stack)); 56 | 57 | try!(printer.write_indent()); 58 | try!(writeln!(printer, "Max locals: {}", self.max_locals)); 59 | 60 | try!(printer.write_indent()); 61 | try!(writeln!(printer, "Code: [ {} bytes ]", self.code.len())); 62 | 63 | try!(printer.write_indent()); 64 | try!(writeln!(printer, "Exception handlers:")); 65 | for handler in self.exception_handlers.iter() { 66 | try!(handler.print(&mut printer.sub_indent(1), constant_pool)); 67 | } 68 | 69 | try!(printer.write_indent()); 70 | try!(writeln!(printer, "Attrs:")); 71 | for attr in self.attrs.iter() { 72 | try!(attr.print(&mut printer.sub_indent(1).by_ref(), constant_pool)); 73 | } 74 | } 75 | } 76 | 77 | #[derive(Debug)] 78 | pub struct ExceptionHandler { 79 | pub start_pc: usize, 80 | pub end_pc: usize, 81 | pub handler_pc: usize, 82 | catch_type: usize, 83 | } 84 | 85 | impl ExceptionHandler { 86 | pub fn catch_type<'a>(&self, pool: &'a ConstantPool) -> Option<&'a ConstantClassInfo> { 87 | if self.catch_type != 0 { 88 | pool.get_class_info(self.catch_type) 89 | } else { 90 | None 91 | } 92 | } 93 | } 94 | 95 | impl_read! { 96 | ExceptionHandler(reader) -> Result = { 97 | let start_pc = try!(reader.read_u16::()) as usize; 98 | let end_pc = try!(reader.read_u16::()) as usize; 99 | let handler_pc = try!(reader.read_u16::()) as usize; 100 | let catch_type = try!(reader.read_u16::()) as usize; 101 | 102 | Ok(ExceptionHandler { 103 | start_pc: start_pc, 104 | end_pc: end_pc, 105 | handler_pc: handler_pc, 106 | catch_type: catch_type, 107 | }) 108 | } 109 | } 110 | 111 | impl_print! { 112 | ExceptionHandler(self, printer, constant_pool: &ConstantPool) { 113 | try!(printer.write_indent()); 114 | try!(write!(printer, "Exception handler [{:#x}:{:#x}] @ {:#x}", self.start_pc, self.end_pc, self.handler_pc)); 115 | 116 | if let Some(catch_type) = self.catch_type(constant_pool) { 117 | try!(write!(printer, " -> ")); 118 | try!(catch_type.print(printer, constant_pool)); 119 | } 120 | 121 | try!(writeln!(printer, "")); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /classfile/src/attr/info/method/exception.rs: -------------------------------------------------------------------------------- 1 | use constant::{ConstantPool, ConstantClassInfo}; 2 | use error::Result; 3 | 4 | #[derive(Debug)] 5 | pub struct ExceptionsAttrInfo { 6 | table: Vec, 7 | } 8 | 9 | impl ExceptionsAttrInfo { 10 | pub fn table<'a, 'b>(&'a self, pool: &'b ConstantPool) -> ExceptionsTable<'a, 'b> { 11 | ExceptionsTable::new(self, pool) 12 | } 13 | } 14 | 15 | impl_read! { 16 | ExceptionsAttrInfo(reader, _constant_pool: &ConstantPool) -> Result = { 17 | let table_size = try!(reader.read_u16::()) as usize; 18 | let mut table = Vec::with_capacity(table_size); 19 | for _ in 0..table_size { 20 | let index = try!(reader.read_u16::()) as usize; 21 | table.push(index); 22 | } 23 | 24 | Ok(ExceptionsAttrInfo { 25 | table: table, 26 | }) 27 | } 28 | } 29 | 30 | impl_print! { 31 | ExceptionsAttrInfo(self, printer, constant_pool: &ConstantPool) { 32 | for class in self.table(constant_pool).filter_map(|class| class) { 33 | try!(printer.write_indent()); 34 | try!(class.print(printer, constant_pool)); 35 | try!(writeln!(printer, "")); 36 | } 37 | } 38 | } 39 | 40 | pub struct ExceptionsTable<'a, 'b> { 41 | iter: ::std::slice::Iter<'a, usize>, 42 | constant_pool: &'b ConstantPool, 43 | } 44 | 45 | impl<'a, 'b> ExceptionsTable<'a, 'b> { 46 | fn new(info: &'a ExceptionsAttrInfo, constant_pool: &'b ConstantPool) -> Self { 47 | ExceptionsTable { 48 | iter: info.table.iter(), 49 | constant_pool: constant_pool, 50 | } 51 | } 52 | } 53 | 54 | impl<'a, 'b> Iterator for ExceptionsTable<'a, 'b> { 55 | type Item = Option<&'b ConstantClassInfo>; 56 | 57 | fn next(&mut self) -> Option { 58 | self.iter.next().map(|&index| self.constant_pool.get_class_info(index)) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /classfile/src/attr/info/method/mod.rs: -------------------------------------------------------------------------------- 1 | pub use self::code::CodeAttrInfo; 2 | pub use self::exception::ExceptionsAttrInfo; 3 | 4 | pub mod code; 5 | pub mod exception; 6 | -------------------------------------------------------------------------------- /classfile/src/attr/info/misc/annotations.rs: -------------------------------------------------------------------------------- 1 | use constant::{ConstantPool, ConstantPoolEntry}; 2 | use error::*; 3 | use std::slice::Iter; 4 | 5 | #[derive(Debug)] 6 | pub struct RuntimeVisibleAnnotationsAttrInfo { 7 | annotations: Vec, 8 | } 9 | 10 | impl RuntimeVisibleAnnotationsAttrInfo { 11 | pub fn annotations<'a>(&'a self) -> Iter<'a, Annotation> { 12 | self.annotations.iter() 13 | } 14 | } 15 | 16 | impl_read! { 17 | RuntimeVisibleAnnotationsAttrInfo(reader, _constant_pool: &ConstantPool) -> Result = { 18 | let annotations_count = try!(reader.read_u16::()) as usize; 19 | let mut annotations = Vec::with_capacity(annotations_count); 20 | for _ in 0..annotations_count { 21 | let annotation = try!(Annotation::read(reader)); 22 | annotations.push(annotation); 23 | } 24 | 25 | Ok(RuntimeVisibleAnnotationsAttrInfo { 26 | annotations: annotations, 27 | }) 28 | } 29 | } 30 | 31 | impl_print! { 32 | RuntimeVisibleAnnotationsAttrInfo(self, printer, constant_pool: &ConstantPool) { 33 | for annotation in self.annotations() { 34 | try!(printer.write_indent()); 35 | try!(annotation.print(printer, constant_pool)); 36 | } 37 | } 38 | } 39 | 40 | #[derive(Debug)] 41 | pub struct Annotation { 42 | type_index: usize, 43 | element_values: Vec, 44 | } 45 | 46 | impl Annotation { 47 | pub fn ty<'a>(&self, constant_pool: &'a ConstantPool) -> Option<&'a str> { 48 | constant_pool.get_str(self.type_index) 49 | } 50 | 51 | pub fn element_values<'a>(&'a self) -> Iter<'a, NamedElementValue> { 52 | self.element_values.iter() 53 | } 54 | } 55 | 56 | impl_read! { 57 | Annotation(reader) -> Result = { 58 | let type_index = try!(reader.read_u16::()) as usize; 59 | 60 | // Read element values 61 | let element_values_count = try!(reader.read_u16::()) as usize; 62 | let mut element_values = Vec::with_capacity(element_values_count); 63 | for _ in 0..element_values_count { 64 | let element_value = try!(NamedElementValue::read(reader)); 65 | element_values.push(element_value); 66 | } 67 | 68 | Ok(Annotation { 69 | type_index: type_index, 70 | element_values: element_values, 71 | }) 72 | } 73 | } 74 | 75 | impl_print! { 76 | Annotation(self, printer, constant_pool: &ConstantPool) { 77 | let ty = self.ty(constant_pool).expect("Invalid type index"); 78 | 79 | try!(writeln!(printer, "Annotation [{}]:", ty)); 80 | 81 | for element_value in self.element_values() { 82 | try!(element_value.print(&mut printer.sub_indent(1), constant_pool)); 83 | } 84 | } 85 | } 86 | 87 | #[derive(Debug)] 88 | pub struct NamedElementValue { 89 | name_index: usize, 90 | pub value: ElementValue, 91 | } 92 | 93 | impl NamedElementValue { 94 | pub fn name<'a>(&self, constant_pool: &'a ConstantPool) -> Option<&'a str> { 95 | constant_pool.get_str(self.name_index) 96 | } 97 | } 98 | 99 | impl_read! { 100 | NamedElementValue(reader) -> Result = { 101 | let name_index = try!(reader.read_u16::()) as usize; 102 | let value = try!(ElementValue::read(reader)); 103 | 104 | Ok(NamedElementValue { 105 | name_index: name_index, 106 | value: value, 107 | }) 108 | } 109 | } 110 | 111 | impl_print! { 112 | NamedElementValue(self, printer, constant_pool: &ConstantPool) { 113 | let name = self.name(constant_pool).expect("Invalid name index"); 114 | 115 | try!(printer.write_indent()); 116 | try!(write!(printer, "{}: ", name)); 117 | try!(self.value.print(printer, constant_pool)); 118 | } 119 | } 120 | 121 | #[derive(Debug)] 122 | pub enum ElementValue { 123 | ConstValue(ConstValueInfo), 124 | EnumConstValue(EnumConstValueInfo), 125 | Class(ClassInfo), 126 | Annotation(Annotation), 127 | Array(Vec), 128 | } 129 | 130 | impl_read! { 131 | ElementValue(reader) -> Result = { 132 | let tag = try!(reader.read_u8()); 133 | 134 | let value = match tag { 135 | b'B' | b'C' | b'D' | b'F' | b'I' | b'J' | b'S' | b'Z' | b's' 136 | => ElementValue::ConstValue(try!(ConstValueInfo::read(reader))), 137 | b'e' 138 | => ElementValue::EnumConstValue(try!(EnumConstValueInfo::read(reader))), 139 | b'c' 140 | => ElementValue::Class(try!(ClassInfo::read(reader))), 141 | b'@' 142 | => ElementValue::Annotation(try!(Annotation::read(reader))), 143 | b'[' 144 | => { 145 | let values_count = try!(reader.read_u16::()) as usize; 146 | let mut values = Vec::with_capacity(values_count); 147 | for _ in 0..values_count { 148 | let value = try!(ElementValue::read(reader)); 149 | values.push(value); 150 | } 151 | 152 | ElementValue::Array(values) 153 | } 154 | _ => bail!(ErrorKind::BadTagValue(tag)), 155 | }; 156 | 157 | Ok(value) 158 | } 159 | } 160 | 161 | impl_print! { 162 | ElementValue(self, printer, constant_pool: &ConstantPool) { 163 | match *self { 164 | ElementValue::ConstValue(ref info) => try!(info.print(printer, constant_pool)), 165 | ElementValue::EnumConstValue(ref info) => try!(info.print(printer, constant_pool)), 166 | ElementValue::Class(ref info) => try!(info.print(printer, constant_pool)), 167 | ElementValue::Annotation(ref annotation) => try!(annotation.print(&mut printer.by_ref(), constant_pool)), 168 | ElementValue::Array(ref values) => { 169 | try!(writeln!(printer, "Array:")); 170 | 171 | let mut printer = printer.sub_indent(1); 172 | for value in values.iter() { 173 | try!(printer.write_indent()); 174 | try!(value.print(&mut printer.sub_indent(1).by_ref(), constant_pool)); 175 | } 176 | } 177 | } 178 | } 179 | } 180 | 181 | #[derive(Debug)] 182 | pub struct ConstValueInfo { 183 | index: usize, 184 | } 185 | 186 | impl ConstValueInfo { 187 | pub fn value<'a>(&self, constant_pool: &'a ConstantPool) -> Option<&'a ConstantPoolEntry> { 188 | constant_pool.get(self.index) 189 | } 190 | } 191 | 192 | impl_read! { 193 | ConstValueInfo(reader) -> Result = { 194 | let index = try!(reader.read_u16::()) as usize; 195 | 196 | Ok(ConstValueInfo { 197 | index: index, 198 | }) 199 | } 200 | } 201 | 202 | impl_print! { 203 | ConstValueInfo(self, printer, constant_pool: &ConstantPool) { 204 | let value = self.value(constant_pool).expect("Invalid value index"); 205 | 206 | try!(write!(printer, "Constant value: ")); 207 | try!(value.print(printer, constant_pool)); 208 | try!(writeln!(printer, "")); 209 | } 210 | } 211 | 212 | #[derive(Debug)] 213 | pub struct EnumConstValueInfo { 214 | type_name_index: usize, 215 | const_name_index: usize, 216 | } 217 | 218 | impl EnumConstValueInfo { 219 | pub fn type_name<'a>(&self, constant_pool: &'a ConstantPool) -> Option<&'a str> { 220 | constant_pool.get_str(self.type_name_index) 221 | } 222 | 223 | pub fn const_name<'a>(&self, constant_pool: &'a ConstantPool) -> Option<&'a str> { 224 | constant_pool.get_str(self.const_name_index) 225 | } 226 | } 227 | 228 | impl_read! { 229 | EnumConstValueInfo(reader) -> Result = { 230 | let type_name_index = try!(reader.read_u16::()) as usize; 231 | let const_name_index = try!(reader.read_u16::()) as usize; 232 | 233 | Ok(EnumConstValueInfo { 234 | type_name_index: type_name_index, 235 | const_name_index: const_name_index, 236 | }) 237 | } 238 | } 239 | 240 | impl_print! { 241 | EnumConstValueInfo(self, printer, constant_pool: &ConstantPool) { 242 | let type_name = self.type_name(constant_pool).expect("Invalid name index"); 243 | let const_name = self.const_name(constant_pool).expect("Invalid name index"); 244 | 245 | try!(writeln!(printer, "Enum constant value: {} [{}]", const_name, type_name)); 246 | } 247 | } 248 | 249 | #[derive(Debug)] 250 | pub struct ClassInfo { 251 | index: usize, 252 | } 253 | 254 | impl ClassInfo { 255 | pub fn class<'a>(&self, constant_pool: &'a ConstantPool) -> Option<&'a str> { 256 | constant_pool.get_str(self.index) 257 | } 258 | } 259 | 260 | impl_read! { 261 | ClassInfo(reader) -> Result = { 262 | let index = try!(reader.read_u16::()) as usize; 263 | 264 | Ok(ClassInfo { 265 | index: index, 266 | }) 267 | } 268 | } 269 | 270 | impl_print! { 271 | ClassInfo(self, printer, constant_pool: &ConstantPool) { 272 | let class = self.class(constant_pool).expect("Invalid class index"); 273 | 274 | try!(writeln!(printer, "Class: {}", class)); 275 | } 276 | } 277 | -------------------------------------------------------------------------------- /classfile/src/attr/info/misc/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod annotations; 2 | pub mod signature; 3 | 4 | pub use self::annotations::RuntimeVisibleAnnotationsAttrInfo; 5 | pub use self::signature::SignatureAttrInfo; 6 | 7 | empty_attr_info!(SyntheticAttrInfo); 8 | empty_attr_info!(DeprecatedAttrInfo); 9 | -------------------------------------------------------------------------------- /classfile/src/attr/info/misc/signature.rs: -------------------------------------------------------------------------------- 1 | use constant::ConstantPool; 2 | use error::Result; 3 | 4 | #[derive(Debug)] 5 | pub struct SignatureAttrInfo { 6 | index: usize, 7 | } 8 | 9 | impl SignatureAttrInfo { 10 | pub fn value<'a>(&self, constant_pool: &'a ConstantPool) -> Option<&'a str> { 11 | constant_pool.get_str(self.index) 12 | } 13 | } 14 | 15 | impl_read! { 16 | SignatureAttrInfo(reader, _constant_pool: &ConstantPool) -> Result = { 17 | let index = try!(reader.read_u16::()) as usize; 18 | 19 | Ok(SignatureAttrInfo { 20 | index: index, 21 | }) 22 | } 23 | } 24 | 25 | impl_print! { 26 | SignatureAttrInfo(self, printer, constant_pool: &ConstantPool) { 27 | let value = self.value(constant_pool).expect("Invalid signature index"); 28 | 29 | try!(printer.write_indent()); 30 | try!(writeln!(printer, "{:?}", value)); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /classfile/src/attr/info/mod.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] mod macros; 2 | pub mod classfile; 3 | pub mod code; 4 | pub mod field; 5 | pub mod method; 6 | pub mod misc; 7 | 8 | use error::Result; 9 | use constant::ConstantPool; 10 | 11 | #[derive(Debug)] 12 | pub enum AttrInfo { 13 | // Class file 14 | SourceFile(classfile::SourceFileAttrInfo), 15 | InnerClasses(classfile::InnerClassesAttrInfo), 16 | EnclosingMethod(classfile::EnclosingMethodAttrInfo), 17 | SourceDebugExtension(classfile::SourceDebugExtensionAttrInfo), 18 | // BootstrapMethods 19 | 20 | // Field 21 | ConstantValue(field::ConstantValueAttrInfo), 22 | 23 | // Method 24 | Code(method::CodeAttrInfo), 25 | Exceptions(method::ExceptionsAttrInfo), 26 | // RuntimeVisibleParameterAnnotations 27 | // RuntimeInvisibleParameterAnnotations 28 | // AnnotationDefault 29 | // MethodParameters 30 | 31 | // Code 32 | LineNumberTable(code::LineNumberTableAttrInfo), 33 | LocalVariableTable(code::LocalVariableTableAttrInfo), 34 | // LocalVariableTypeTable 35 | StackMapTable(code::StackMapTableAttrInfo), 36 | 37 | // Misc 38 | Syncthetic(misc::SyntheticAttrInfo), 39 | Deprecated(misc::DeprecatedAttrInfo), 40 | Signature(misc::SignatureAttrInfo), 41 | RuntimeVisibleAnnotations(misc::RuntimeVisibleAnnotationsAttrInfo), 42 | // RuntimeInvisibleAnnotations 43 | // RuntimeVisibleTypeAnnotations 44 | // RuntimeInvisibleTypeAnnotations 45 | 46 | // Unknown 47 | Unknown(Vec), 48 | } 49 | 50 | macro_rules! read_by_name { 51 | ($name_expr:expr, $reader:expr, $pool:expr => 52 | $($name:ident => $read:path),* 53 | ) => { 54 | match $name_expr { 55 | $(stringify!($name) => return $read(&mut $reader, $pool).map(AttrInfo::$name),)* 56 | _ => {} 57 | } 58 | }; 59 | ($name_expr:expr, $reader:expr, $pool:expr => 60 | $($name:ident => $read:path),+, 61 | ) => ( 62 | read_by_name!($name_expr, $reader, $pool => 63 | $($name => $read),+ 64 | ) 65 | ); 66 | } 67 | 68 | impl_read! { 69 | AttrInfo(reader, name: &str, pool: &ConstantPool) -> Result = { 70 | use utils::io::ReadExt; 71 | 72 | let size = try!(reader.read_u32::()) as usize; 73 | let data = try!(reader.read_vec(size)); 74 | 75 | { 76 | use std::io::Cursor; 77 | 78 | let mut reader: Cursor<&[u8]> = Cursor::new(&data); 79 | 80 | read_by_name!(name, reader, pool => 81 | // Class file 82 | InnerClasses => classfile::InnerClassesAttrInfo::read, 83 | SourceFile => classfile::SourceFileAttrInfo::read, 84 | EnclosingMethod => classfile::EnclosingMethodAttrInfo::read, 85 | SourceDebugExtension => classfile::SourceDebugExtensionAttrInfo::read, 86 | 87 | // Field 88 | ConstantValue => field::ConstantValueAttrInfo::read, 89 | 90 | // Method 91 | Code => method::CodeAttrInfo::read, 92 | Exceptions => method::ExceptionsAttrInfo::read, 93 | 94 | // Code 95 | StackMapTable => code::StackMapTableAttrInfo::read, 96 | LineNumberTable => code::LineNumberTableAttrInfo::read, 97 | LocalVariableTable => code::LocalVariableTableAttrInfo::read, 98 | 99 | // Misc 100 | Syncthetic => misc::SyntheticAttrInfo::read, 101 | Deprecated => misc::DeprecatedAttrInfo::read, 102 | RuntimeVisibleAnnotations => misc::RuntimeVisibleAnnotationsAttrInfo::read, 103 | Signature => misc::SignatureAttrInfo::read, 104 | ); 105 | } 106 | 107 | Ok(AttrInfo::Unknown(data)) 108 | } 109 | } 110 | 111 | impl_print! { 112 | AttrInfo(self, printer, constant_pool: &ConstantPool) { 113 | match *self { 114 | // Class files 115 | AttrInfo::SourceFile(ref info) => try!(info.print(printer, constant_pool)), 116 | AttrInfo::InnerClasses(ref info) => try!(info.print(printer, constant_pool)), 117 | AttrInfo::EnclosingMethod(ref info) => try!(info.print(printer, constant_pool)), 118 | AttrInfo::SourceDebugExtension(ref info) => try!(info.print(printer, constant_pool)), 119 | 120 | // Field 121 | AttrInfo::ConstantValue(ref info) => try!(info.print(printer, constant_pool)), 122 | 123 | // Method 124 | AttrInfo::Code(ref info) => try!(info.print(printer, constant_pool)), 125 | AttrInfo::Exceptions(ref info) => try!(info.print(printer, constant_pool)), 126 | 127 | // Code 128 | AttrInfo::StackMapTable(ref info) => try!(info.print(printer, constant_pool)), 129 | AttrInfo::LineNumberTable(ref info) => try!(info.print(printer)), 130 | AttrInfo::LocalVariableTable(ref info) => try!(info.print(printer, constant_pool)), 131 | 132 | // Misc 133 | AttrInfo::Syncthetic(ref info) => try!(info.print(printer)), 134 | AttrInfo::Deprecated(ref info) => try!(info.print(printer)), 135 | AttrInfo::RuntimeVisibleAnnotations(ref info) => try!(info.print(printer, constant_pool)), 136 | AttrInfo::Signature(ref info) => try!(info.print(printer, constant_pool)), 137 | 138 | // Unknown 139 | AttrInfo::Unknown(ref data) => { 140 | try!(printer.write_indent()); 141 | try!(writeln!(printer, "Unknown [ {} bytes ]", data.len())) 142 | } 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /classfile/src/attr/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod info; 2 | 3 | use error::*; 4 | use self::info::AttrInfo; 5 | use super::constant::ConstantPool; 6 | 7 | #[derive(Debug)] 8 | pub struct Attr { 9 | name_index: usize, 10 | pub info: AttrInfo, 11 | } 12 | 13 | impl Attr { 14 | pub fn name<'a>(&self, pool: &'a ConstantPool) -> Option<&'a str> { 15 | pool.get_str(self.name_index) 16 | } 17 | } 18 | 19 | impl_read! { 20 | Attr(reader, pool: &ConstantPool) -> Result = { 21 | // Read name index 22 | let name_index = try!(reader.read_u16::()) as usize; 23 | let name = match pool.get_str(name_index) { 24 | Some(name) => name, 25 | None => bail!(ErrorKind::BadAttrName(name_index)), 26 | }; 27 | 28 | // Read attr info 29 | let info = try!(AttrInfo::read(reader, name, pool)); 30 | 31 | Ok(Attr { 32 | name_index: name_index, 33 | info: info, 34 | }) 35 | } 36 | } 37 | 38 | impl_print! { 39 | Attr(self, printer, constant_pool: &ConstantPool) { 40 | let name = self.name(constant_pool).expect("Invalid name index"); 41 | 42 | try!(printer.write_indent()); 43 | try!(writeln!(printer, "Attr `{}`:", name)); 44 | 45 | try!(self.info.print(&mut printer.sub_indent(1), constant_pool)); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /classfile/src/constant/error.rs: -------------------------------------------------------------------------------- 1 | use std::convert::From; 2 | use std::string::FromUtf8Error; 3 | 4 | error_chain! { 5 | foreign_links { 6 | Io(::std::io::Error); 7 | Utf8(FromUtf8Error); 8 | } 9 | 10 | errors { 11 | BadTagValue(value: u8) { 12 | description("Bad tag value") 13 | display("Bad tag value: {:x}", value) 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /classfile/src/constant/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod error; 2 | 3 | use byteorder::{ReadBytesExt, BigEndian}; 4 | use self::error::*; 5 | use std::io::Read; 6 | 7 | // #[allow(dead_code)] 8 | mod tag { 9 | pub const CONSTANT_UTF8: u8 = 1; 10 | pub const CONSTANT_INTEGER: u8 = 3; 11 | pub const CONSTANT_FLOAT: u8 = 4; 12 | pub const CONSTANT_LONG: u8 = 5; 13 | pub const CONSTANT_DOUBLE: u8 = 6; 14 | pub const CONSTANT_CLASS: u8 = 7; 15 | pub const CONSTANT_STRING: u8 = 8; 16 | pub const CONSTANT_FIELDREF: u8 = 9; 17 | pub const CONSTANT_METHODREF: u8 = 10; 18 | pub const CONSTANT_INTERFACEMETHODREF: u8 = 11; 19 | pub const CONSTANT_NAMEANDTYPE: u8 = 12; 20 | pub const CONSTANT_METHODHANDLE: u8 = 15; 21 | pub const CONSTANT_METHODTYPE: u8 = 16; 22 | pub const CONSTANT_INVOKEDYNAMIC: u8 = 18; 23 | } 24 | 25 | #[derive(Debug)] 26 | pub struct ConstantPool { 27 | entries: Vec>, 28 | } 29 | 30 | impl ConstantPool { 31 | pub fn read(reader: &mut R) -> Result { 32 | let entries_count = try!(reader.read_u16::()) as usize; 33 | let mut entries = Vec::with_capacity(entries_count - 1); 34 | 35 | let mut index = 1; 36 | while index < entries_count { 37 | let constant_pool_entry = try!(ConstantPoolEntry::read(reader)); 38 | 39 | let long_entry = match constant_pool_entry { 40 | ConstantPoolEntry::Long(_) | ConstantPoolEntry::Double(_) => true, 41 | _ => false, 42 | }; 43 | 44 | entries.push(Some(constant_pool_entry)); 45 | index += 1; 46 | 47 | if long_entry { 48 | index += 1; 49 | entries.push(None); 50 | } 51 | } 52 | 53 | Ok(ConstantPool { 54 | entries: entries, 55 | }) 56 | } 57 | 58 | pub fn get(&self, index: usize) -> Option<&ConstantPoolEntry> { 59 | // Indexes starts at 1 in Java classfiles... 60 | self.entries.get(index - 1).and_then(|entry| entry.as_ref()) 61 | } 62 | 63 | pub fn get_str(&self, index: usize) -> Option<&str> { 64 | self.get(index).and_then(|entry| match entry { 65 | &ConstantPoolEntry::Utf8(ref info) => Some(info.value()), 66 | _ => None, 67 | }) 68 | } 69 | 70 | pub fn get_class_info(&self, index: usize) -> Option<&ConstantClassInfo> { 71 | self.get(index).and_then(|entry| match entry { 72 | &ConstantPoolEntry::Class(ref info) => Some(info), 73 | _ => None, 74 | }) 75 | } 76 | } 77 | 78 | impl_print! { 79 | ConstantPool(self, printer) { 80 | for entry in self.entries.iter() { 81 | if let &Some(ref entry) = entry { 82 | try!(printer.write_indent()); 83 | try!(entry.print(printer, self)); 84 | try!(writeln!(printer, "")); 85 | } 86 | } 87 | } 88 | } 89 | 90 | #[derive(Debug)] 91 | pub enum ConstantPoolEntry { 92 | Class(ConstantClassInfo), 93 | FieldRef(ConstantFieldRefInfo), 94 | MethodRef(ConstantMethodRefInfo), 95 | InterfaceMethodRef(ConstantInterfaceMethodRefInfo), 96 | String(ConstantStringInfo), 97 | Integer(ConstantIntegerInfo), 98 | Float(ConstantFloatInfo), 99 | Long(ConstantLongInfo), 100 | Double(ConstantDoubleInfo), 101 | NameAndType(ConstantNameAndTypeInfo), 102 | Utf8(ConstantUtf8Info), 103 | MethodHandle(ConstantMethodHandleInfo), 104 | MethodType(ConstantMethodTypeInfo), 105 | InvokedDynamic(ConstantInvokedDynamicInfo), 106 | } 107 | 108 | impl ConstantPoolEntry { 109 | pub fn read(reader: &mut R) -> Result { 110 | let tag = try!(reader.read_u8()); 111 | 112 | match tag { 113 | tag::CONSTANT_CLASS => ConstantClassInfo::read(reader).map(ConstantPoolEntry::Class), 114 | tag::CONSTANT_FIELDREF => ConstantFieldRefInfo::read(reader).map(ConstantPoolEntry::FieldRef), 115 | tag::CONSTANT_METHODREF => ConstantMethodRefInfo::read(reader).map(ConstantPoolEntry::MethodRef), 116 | tag::CONSTANT_INTERFACEMETHODREF => ConstantInterfaceMethodRefInfo::read(reader).map(ConstantPoolEntry::InterfaceMethodRef), 117 | tag::CONSTANT_STRING => ConstantStringInfo::read(reader).map(ConstantPoolEntry::String), 118 | tag::CONSTANT_INTEGER => ConstantIntegerInfo::read(reader).map(ConstantPoolEntry::Integer), 119 | tag::CONSTANT_FLOAT => ConstantFloatInfo::read(reader).map(ConstantPoolEntry::Float), 120 | tag::CONSTANT_LONG => ConstantLongInfo::read(reader).map(ConstantPoolEntry::Long), 121 | tag::CONSTANT_DOUBLE => ConstantDoubleInfo::read(reader).map(ConstantPoolEntry::Double), 122 | tag::CONSTANT_NAMEANDTYPE => ConstantNameAndTypeInfo::read(reader).map(ConstantPoolEntry::NameAndType), 123 | tag::CONSTANT_UTF8 => ConstantUtf8Info::read(reader).map(ConstantPoolEntry::Utf8), 124 | tag::CONSTANT_METHODHANDLE => ConstantMethodHandleInfo::read(reader).map(ConstantPoolEntry::MethodHandle), 125 | tag::CONSTANT_METHODTYPE => ConstantMethodTypeInfo::read(reader).map(ConstantPoolEntry::MethodType), 126 | tag::CONSTANT_INVOKEDYNAMIC => ConstantInvokedDynamicInfo::read(reader).map(ConstantPoolEntry::InvokedDynamic), 127 | _ => Err(ErrorKind::BadTagValue(tag).into()), 128 | } 129 | } 130 | } 131 | 132 | impl_print! { 133 | ConstantPoolEntry(self, printer, constant_pool: &ConstantPool) { 134 | match *self { 135 | ConstantPoolEntry::Class(ref info) => try!(info.print(printer, constant_pool)), 136 | ConstantPoolEntry::FieldRef(ref info) => try!(info.print(printer, constant_pool)), 137 | ConstantPoolEntry::MethodRef(ref info) => try!(info.print(printer, constant_pool)), 138 | ConstantPoolEntry::InterfaceMethodRef(ref info) => try!(info.print(printer, constant_pool)), 139 | ConstantPoolEntry::String(ref info) => try!(info.print(printer, constant_pool)), 140 | ConstantPoolEntry::Integer(ref info) => try!(info.print(printer, constant_pool)), 141 | ConstantPoolEntry::Float(ref info) => try!(info.print(printer, constant_pool)), 142 | ConstantPoolEntry::Long(ref info) => try!(info.print(printer, constant_pool)), 143 | ConstantPoolEntry::Double(ref info) => try!(info.print(printer, constant_pool)), 144 | ConstantPoolEntry::NameAndType(ref info) => try!(info.print(printer, constant_pool)), 145 | ConstantPoolEntry::Utf8(ref info) => try!(info.print(printer, constant_pool)), 146 | ConstantPoolEntry::MethodHandle(ref info) => try!(info.print(printer, constant_pool)), 147 | ConstantPoolEntry::MethodType(ref info) => try!(info.print(printer, constant_pool)), 148 | ConstantPoolEntry::InvokedDynamic(ref info) => try!(info.print(printer, constant_pool)), 149 | } 150 | } 151 | } 152 | 153 | #[derive(Debug)] 154 | pub struct ConstantClassInfo { 155 | name_index: usize, 156 | } 157 | 158 | impl ConstantClassInfo { 159 | pub fn read(reader: &mut R) -> Result { 160 | // Read name index 161 | let name_index = try!(reader.read_u16::()); 162 | 163 | Ok(ConstantClassInfo { 164 | name_index: name_index as usize, 165 | }) 166 | } 167 | 168 | pub fn name<'a>(&self, pool: &'a ConstantPool) -> Option<&'a str> { 169 | pool.get_str(self.name_index) 170 | } 171 | } 172 | 173 | impl_print! { 174 | ConstantClassInfo(self, printer, constant_pool: &ConstantPool) { 175 | let name = self.name(constant_pool).expect("Invalid name index."); 176 | 177 | try!(write!(printer, "Class `{}`", name)); 178 | } 179 | } 180 | 181 | #[derive(Debug)] 182 | pub struct ConstantFieldRefInfo { 183 | class_index: usize, 184 | name_and_type_index: usize, 185 | } 186 | 187 | impl ConstantFieldRefInfo { 188 | pub fn read(reader: &mut R) -> Result { 189 | // Read indexes 190 | let class_index = try!(reader.read_u16::()); 191 | let name_and_type_index = try!(reader.read_u16::()); 192 | 193 | Ok(ConstantFieldRefInfo { 194 | class_index: class_index as usize, 195 | name_and_type_index: name_and_type_index as usize, 196 | }) 197 | } 198 | 199 | pub fn class<'a>(&self, pool: &'a ConstantPool) -> Option<&'a ConstantClassInfo> { 200 | pool.get_class_info(self.class_index) 201 | } 202 | 203 | pub fn name_and_type<'a>(&self, pool: &'a ConstantPool) -> Option<&'a ConstantNameAndTypeInfo> { 204 | pool.get(self.name_and_type_index).and_then(|entry| match *entry { 205 | ConstantPoolEntry::NameAndType(ref info) => Some(info), 206 | _ => None, 207 | }) 208 | } 209 | } 210 | 211 | impl_print! { 212 | ConstantFieldRefInfo(self, printer, constant_pool: &ConstantPool) { 213 | try!(writeln!(printer, "FieldRef:")); 214 | 215 | let class = self.class(constant_pool).expect("Invalid class index."); 216 | let name_and_type = self.name_and_type(constant_pool).expect("Invalid Name And Type index."); 217 | 218 | { 219 | let mut printer = printer.sub_indent(1); 220 | 221 | try!(printer.write_indent()); 222 | try!(class.print(&mut printer, constant_pool)); 223 | try!(writeln!(printer, "")); 224 | 225 | try!(printer.write_indent()); 226 | try!(name_and_type.print(&mut printer, constant_pool)); 227 | } 228 | } 229 | } 230 | 231 | #[derive(Debug)] 232 | pub struct ConstantMethodRefInfo { 233 | class_index: usize, 234 | name_and_type_index: usize, 235 | } 236 | 237 | impl ConstantMethodRefInfo { 238 | pub fn read(reader: &mut R) -> Result { 239 | // Read indexes 240 | let class_index = try!(reader.read_u16::()); 241 | let name_and_type_index = try!(reader.read_u16::()); 242 | 243 | Ok(ConstantMethodRefInfo { 244 | class_index: class_index as usize, 245 | name_and_type_index: name_and_type_index as usize, 246 | }) 247 | } 248 | 249 | pub fn class<'a>(&self, pool: &'a ConstantPool) -> Option<&'a ConstantClassInfo> { 250 | pool.get_class_info(self.class_index) 251 | } 252 | 253 | pub fn name_and_type<'a>(&self, pool: &'a ConstantPool) -> Option<&'a ConstantNameAndTypeInfo> { 254 | pool.get(self.name_and_type_index).and_then(|entry| match *entry { 255 | ConstantPoolEntry::NameAndType(ref info) => Some(info), 256 | _ => None, 257 | }) 258 | } 259 | } 260 | 261 | impl_print! { 262 | ConstantMethodRefInfo(self, printer, constant_pool: &ConstantPool) { 263 | let class = self.class(constant_pool).expect("Invalid class index"); 264 | let name_and_type = self.name_and_type(constant_pool).expect("Invalid name and type index."); 265 | 266 | try!(writeln!(printer, "MethodRef:")); 267 | 268 | { 269 | let mut printer = printer.sub_indent(1); 270 | 271 | try!(printer.write_indent()); 272 | try!(class.print(&mut printer, constant_pool)); 273 | try!(writeln!(printer, "")); 274 | 275 | try!(printer.write_indent()); 276 | try!(name_and_type.print(&mut printer, constant_pool)); 277 | } 278 | } 279 | } 280 | 281 | #[derive(Debug)] 282 | pub struct ConstantInterfaceMethodRefInfo { 283 | class_index: usize, 284 | name_and_type_index: usize, 285 | } 286 | 287 | impl ConstantInterfaceMethodRefInfo { 288 | pub fn read(reader: &mut R) -> Result { 289 | // Read indexes 290 | let class_index = try!(reader.read_u16::()); 291 | let name_and_type_index = try!(reader.read_u16::()); 292 | 293 | Ok(ConstantInterfaceMethodRefInfo { 294 | class_index: class_index as usize, 295 | name_and_type_index: name_and_type_index as usize, 296 | }) 297 | } 298 | 299 | pub fn class<'a>(&self, pool: &'a ConstantPool) -> Option<&'a ConstantClassInfo> { 300 | pool.get_class_info(self.class_index) 301 | } 302 | 303 | pub fn name_and_type<'a>(&self, pool: &'a ConstantPool) -> Option<&'a ConstantNameAndTypeInfo> { 304 | pool.get(self.name_and_type_index).and_then(|entry| match *entry { 305 | ConstantPoolEntry::NameAndType(ref info) => Some(info), 306 | _ => None, 307 | }) 308 | } 309 | } 310 | 311 | impl_print! { 312 | ConstantInterfaceMethodRefInfo(self, printer, constant_pool: &ConstantPool) { 313 | let class = self.class(constant_pool).expect("Invalid class index"); 314 | let name_and_type = self.name_and_type(constant_pool).expect("Invalid name and type index."); 315 | 316 | try!(writeln!(printer, "InterfaceMethodRef:")); 317 | 318 | { 319 | let mut printer = printer.sub_indent(1); 320 | 321 | try!(printer.write_indent()); 322 | try!(class.print(&mut printer, constant_pool)); 323 | try!(writeln!(printer, "")); 324 | 325 | try!(printer.write_indent()); 326 | try!(name_and_type.print(&mut printer, constant_pool)); 327 | } 328 | } 329 | } 330 | 331 | #[derive(Debug)] 332 | pub struct ConstantStringInfo { 333 | string_index: usize, 334 | } 335 | 336 | impl ConstantStringInfo { 337 | pub fn read(reader: &mut R) -> Result { 338 | let string_index = try!(reader.read_u16::()); 339 | 340 | Ok(ConstantStringInfo { 341 | string_index: string_index as usize, 342 | }) 343 | } 344 | 345 | pub fn value<'a>(&self, pool: &'a ConstantPool) -> Option<&'a str> { 346 | pool.get_str(self.string_index) 347 | } 348 | } 349 | 350 | impl_print! { 351 | ConstantStringInfo(self, printer, constant_pool: &ConstantPool) { 352 | let value = self.value(constant_pool).expect("Invalid string index."); 353 | 354 | try!(write!(printer, "String \"{}\"", value)); 355 | } 356 | } 357 | 358 | #[derive(Debug)] 359 | pub struct ConstantIntegerInfo { 360 | value: i32, 361 | } 362 | 363 | impl ConstantIntegerInfo { 364 | pub fn read(reader: &mut R) -> Result { 365 | let value = try!(reader.read_i32::()); 366 | 367 | Ok(ConstantIntegerInfo { 368 | value: value, 369 | }) 370 | } 371 | 372 | pub fn value(&self) -> i32 { 373 | self.value 374 | } 375 | } 376 | 377 | impl_print! { 378 | ConstantIntegerInfo(self, printer, _constant_pool: &ConstantPool) { 379 | try!(write!(printer, "{}", self.value)); 380 | } 381 | } 382 | 383 | #[derive(Debug)] 384 | pub struct ConstantFloatInfo { 385 | value: f32, 386 | } 387 | 388 | impl ConstantFloatInfo { 389 | pub fn read(reader: &mut R) -> Result { 390 | let value = try!(reader.read_f32::()); 391 | 392 | Ok(ConstantFloatInfo { 393 | value: value, 394 | }) 395 | } 396 | 397 | pub fn value(&self) -> f32 { 398 | self.value 399 | } 400 | } 401 | 402 | impl_print! { 403 | ConstantFloatInfo(self, printer, _constant_pool: &ConstantPool) { 404 | try!(write!(printer, "Float {}", self.value)); 405 | } 406 | } 407 | 408 | #[derive(Debug)] 409 | pub struct ConstantLongInfo { 410 | value: i64, 411 | } 412 | 413 | impl ConstantLongInfo { 414 | pub fn read(reader: &mut R) -> Result { 415 | let value = try!(reader.read_i64::()); 416 | 417 | Ok(ConstantLongInfo { 418 | value: value, 419 | }) 420 | } 421 | 422 | pub fn value(&self) -> i64 { 423 | self.value 424 | } 425 | } 426 | 427 | impl_print! { 428 | ConstantLongInfo(self, printer, _constant_pool: &ConstantPool) { 429 | try!(write!(printer, "Long {}", self.value)); 430 | } 431 | } 432 | 433 | #[derive(Debug)] 434 | pub struct ConstantDoubleInfo { 435 | value: f64, 436 | } 437 | 438 | impl ConstantDoubleInfo { 439 | pub fn read(reader: &mut R) -> Result { 440 | let value = try!(reader.read_f64::()); 441 | 442 | Ok(ConstantDoubleInfo { 443 | value: value, 444 | }) 445 | } 446 | 447 | pub fn value(&self) -> f64 { 448 | self.value 449 | } 450 | } 451 | 452 | impl_print! { 453 | ConstantDoubleInfo(self, printer, _constant_pool: &ConstantPool) { 454 | try!(write!(printer, "Double {}", self.value)); 455 | } 456 | } 457 | 458 | #[derive(Debug)] 459 | pub struct ConstantNameAndTypeInfo { 460 | name_index: usize, 461 | desc_index: usize, 462 | } 463 | 464 | impl ConstantNameAndTypeInfo { 465 | pub fn read(reader: &mut R) -> Result { 466 | // Read indexes 467 | let name_index = try!(reader.read_u16::()); 468 | let desc_index = try!(reader.read_u16::()); 469 | 470 | Ok(ConstantNameAndTypeInfo { 471 | name_index: name_index as usize, 472 | desc_index: desc_index as usize, 473 | }) 474 | } 475 | 476 | pub fn name<'a>(&self, pool: &'a ConstantPool) -> Option<&'a str> { 477 | pool.get_str(self.name_index) 478 | } 479 | 480 | pub fn desc<'a>(&self, pool: &'a ConstantPool) -> Option<&'a str> { 481 | pool.get_str(self.desc_index) 482 | } 483 | } 484 | 485 | impl_print! { 486 | ConstantNameAndTypeInfo(self, printer, constant_pool: &ConstantPool) { 487 | let name = self.name(constant_pool).expect("Invalid name index."); 488 | let desc = self.desc(constant_pool).expect("Invalid descriptor index."); 489 | 490 | try!(write!(printer, "NameAndType `{}` [{}]", name, desc)); 491 | } 492 | } 493 | 494 | #[derive(Debug)] 495 | pub struct ConstantUtf8Info { 496 | value: String, 497 | } 498 | 499 | impl ConstantUtf8Info { 500 | pub fn read(reader: &mut R) -> Result { 501 | use utils::io::ReadExt; 502 | 503 | let length = try!(reader.read_u16::()) as usize; 504 | let data = try!(reader.read_vec(length)); 505 | let value = String::from_utf8_lossy(&data).into_owned(); 506 | 507 | Ok(ConstantUtf8Info { 508 | value: value, 509 | }) 510 | } 511 | 512 | pub fn value(&self) -> &str { 513 | &self.value 514 | } 515 | } 516 | 517 | impl_print! { 518 | ConstantUtf8Info(self, printer, _constant_pool: &ConstantPool) { 519 | try!(write!(printer, "Utf8 {:?}", self.value)); 520 | } 521 | } 522 | 523 | #[derive(Debug)] 524 | pub struct ConstantMethodHandleInfo { 525 | ref_kind: u8, // TODO: Change this to an enum. 526 | ref_index: usize, 527 | } 528 | 529 | impl ConstantMethodHandleInfo { 530 | pub fn read(reader: &mut R) -> Result { 531 | let ref_kind = try!(reader.read_u8()); 532 | let ref_index = try!(reader.read_u16::()); 533 | 534 | Ok(ConstantMethodHandleInfo { 535 | ref_kind: ref_kind, 536 | ref_index: ref_index as usize, 537 | }) 538 | } 539 | 540 | pub fn ref_kind(&self) -> u8 { 541 | self.ref_kind 542 | } 543 | 544 | pub fn ref_entry<'a>(&self, pool: &'a ConstantPool) -> Option<&'a ConstantPoolEntry> { 545 | pool.get(self.ref_index) 546 | } 547 | } 548 | 549 | impl_print! { 550 | ConstantMethodHandleInfo(self, printer, constant_pool: &ConstantPool) { 551 | let ref_entry = self.ref_entry(constant_pool).expect("Invalid ref index."); 552 | 553 | try!(writeln!(printer, "MethodRef [{}]", self.ref_kind)); 554 | 555 | { 556 | let mut printer = printer.sub_indent(1); 557 | 558 | try!(printer.write_indent()); 559 | try!(ref_entry.print(&mut printer.by_ref(), constant_pool)); 560 | } 561 | } 562 | } 563 | 564 | #[derive(Debug)] 565 | pub struct ConstantMethodTypeInfo { 566 | desc_index: usize, 567 | } 568 | 569 | impl ConstantMethodTypeInfo { 570 | pub fn read(reader: &mut R) -> Result { 571 | let desc_index = try!(reader.read_u16::()); 572 | 573 | Ok(ConstantMethodTypeInfo { 574 | desc_index: desc_index as usize, 575 | }) 576 | } 577 | 578 | pub fn desc<'a>(&self, pool: &'a ConstantPool) -> Option<&'a str> { 579 | pool.get_str(self.desc_index) 580 | } 581 | } 582 | 583 | impl_print! { 584 | ConstantMethodTypeInfo(self, printer, constant_pool: &ConstantPool) { 585 | let desc = self.desc(constant_pool).expect("Invalid desc index."); 586 | 587 | try!(write!(printer, "MethodType `{}`", desc)); 588 | } 589 | } 590 | 591 | #[derive(Debug)] 592 | pub struct ConstantInvokedDynamicInfo { 593 | bootstrap_method_attr_index: usize, 594 | name_and_type_index: usize, 595 | } 596 | 597 | impl ConstantInvokedDynamicInfo { 598 | pub fn read(reader: &mut R) -> Result { 599 | let bootstrap_method_attr_index = try!(reader.read_u16::()); 600 | let name_and_type_index = try!(reader.read_u16::()); 601 | 602 | Ok(ConstantInvokedDynamicInfo { 603 | bootstrap_method_attr_index: bootstrap_method_attr_index as usize, 604 | name_and_type_index: name_and_type_index as usize, 605 | }) 606 | } 607 | 608 | pub fn bootstrap_method_attr<'a>(&self, pool: &'a ConstantPool) -> Option<&'a ConstantPoolEntry> { 609 | pool.get(self.bootstrap_method_attr_index) 610 | } 611 | 612 | pub fn name_and_type<'a>(&self, pool: &'a ConstantPool) -> Option<&'a ConstantNameAndTypeInfo> { 613 | pool.get(self.name_and_type_index).and_then(|entry| match *entry { 614 | ConstantPoolEntry::NameAndType(ref info) => Some(info), 615 | _ => None, 616 | }) 617 | } 618 | } 619 | 620 | impl_print! { 621 | ConstantInvokedDynamicInfo(self, printer, constant_pool: &ConstantPool) { 622 | let bootstrap_method_attr = self.bootstrap_method_attr(constant_pool).expect("Invalid index."); 623 | let name_and_type = self.name_and_type(constant_pool).expect("Invalid index."); 624 | 625 | try!(writeln!(printer, "InvokedDynamic:")); 626 | 627 | { 628 | let mut printer = printer.sub_indent(1); 629 | 630 | try!(printer.write_indent()); 631 | try!(bootstrap_method_attr.print(&mut printer.by_ref(), constant_pool)); 632 | try!(writeln!(printer, "")); 633 | 634 | try!(printer.write_indent()); 635 | try!(name_and_type.print(&mut printer, constant_pool)); 636 | } 637 | } 638 | } 639 | -------------------------------------------------------------------------------- /classfile/src/error.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use super::constant; 3 | 4 | error_chain! { 5 | links { 6 | ConstantPool(constant::error::Error, constant::error::ErrorKind); 7 | } 8 | 9 | foreign_links { 10 | Io(io::Error); 11 | } 12 | 13 | errors { 14 | BadAccessFlags(flags: u16) { 15 | description("Bad access flags") 16 | display("Bad access flags: {:#x}", flags) 17 | } 18 | BadAttrName(value: usize) { 19 | description("Bad attribute name") 20 | } 21 | BadMagicValue(value: u32) { 22 | description("Bad magic value") 23 | display("Bad magic value: {:#x}", value) 24 | } 25 | BadTagValue(value: u8) { 26 | description("Bad tag value") 27 | display("Bad tag value: {:#x} `{}`", value, *value as char) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /classfile/src/field.rs: -------------------------------------------------------------------------------- 1 | use attr::Attr; 2 | use byteorder::{ReadBytesExt, BigEndian}; 3 | use constant::ConstantPool; 4 | use error::*; 5 | use std::io::Read; 6 | 7 | #[derive(Debug)] 8 | pub struct FieldInfo { 9 | pub access_flags: flags::AccessFlags, 10 | name_index: usize, 11 | desc_index: usize, 12 | pub attrs: Vec, 13 | } 14 | 15 | impl FieldInfo { 16 | pub fn read(reader: &mut R, cp: &ConstantPool) -> Result { 17 | // Read access flags 18 | let access_flags = try!(reader.read_u16::()); 19 | let access_flags = match flags::AccessFlags::from_bits(access_flags) { 20 | Some(flags) => flags, 21 | None => bail!(ErrorKind::BadAccessFlags(access_flags)), 22 | }; 23 | 24 | // Read indexes 25 | let name_index = try!(reader.read_u16::()) as usize; 26 | let desc_index = try!(reader.read_u16::()) as usize; 27 | 28 | // Read attributes 29 | let attrs_count = try!(reader.read_u16::()) as usize; 30 | let mut attrs = Vec::with_capacity(attrs_count); 31 | for _ in 0..attrs_count { 32 | let attr = try!(Attr::read(reader, cp)); 33 | attrs.push(attr); 34 | } 35 | 36 | Ok(FieldInfo { 37 | access_flags: access_flags, 38 | name_index: name_index, 39 | desc_index: desc_index, 40 | attrs: attrs, 41 | }) 42 | } 43 | 44 | pub fn name<'a>(&self, pool: &'a ConstantPool) -> Option<&'a str> { 45 | pool.get_str(self.name_index) 46 | } 47 | 48 | pub fn desc<'a>(&self, pool: &'a ConstantPool) -> Option<&'a str> { 49 | pool.get_str(self.desc_index) 50 | } 51 | } 52 | 53 | impl_print! { 54 | FieldInfo(self, printer, constant_pool: &ConstantPool) { 55 | let name = self.name(constant_pool).expect("Invalid name index"); 56 | let desc = self.desc(constant_pool).expect("Invalid desc index"); 57 | 58 | try!(printer.write_indent()); 59 | try!(writeln!(printer, "Field `{}` [{}]:", name, desc)); 60 | 61 | { 62 | let mut printer = printer.sub_indent(1); 63 | 64 | try!(printer.write_indent()); 65 | try!(writeln!(printer, "Access flags: {:?}", self.access_flags)); 66 | 67 | try!(printer.write_indent()); 68 | try!(writeln!(printer, "Attrs:")); 69 | for attr in self.attrs.iter() { 70 | try!(attr.print(&mut printer.sub_indent(1), constant_pool)); 71 | } 72 | } 73 | } 74 | } 75 | 76 | pub mod flags { 77 | bitflags! { 78 | pub struct AccessFlags: u16 { 79 | #[doc = "Declared public; may be accessed from outside its package."] 80 | const ACC_PUBLIC = 0x0001; 81 | #[doc = "Declared private; usable only within the defining class."] 82 | const ACC_PRIVATE = 0x0002; 83 | #[doc = "Declared protected; may be accessed within subclasses."] 84 | const ACC_PROTECTED = 0x0004; 85 | #[doc = "Declared static."] 86 | const ACC_STATIC = 0x0008; 87 | #[doc = "Declared final; never directly assigned to after object construction (JLS §17.5)."] 88 | const ACC_FINAL = 0x0010; 89 | #[doc = "Declared volatile; cannot be cached."] 90 | const ACC_VOLATILE = 0x0040; 91 | #[doc = "Declared transient; not written or read by a persistent object manager."] 92 | const ACC_TRANSIENT = 0x0080; 93 | #[doc = "Declared synthetic; not present in the source code."] 94 | const ACC_SYNTHETIC = 0x1000; 95 | #[doc = "Declared as an element of an enum."] 96 | const ACC_ENUM = 0x4000; 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /classfile/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate bitflags; 2 | extern crate byteorder; 3 | #[macro_use] extern crate error_chain; 4 | 5 | #[macro_use] mod utils; 6 | pub mod attr; 7 | pub mod constant; 8 | pub mod error; 9 | pub mod field; 10 | pub mod method; 11 | pub mod version; 12 | 13 | use attr::Attr; 14 | use byteorder::{ReadBytesExt, BigEndian}; 15 | use constant::ConstantPool; 16 | use error::*; 17 | use field::FieldInfo; 18 | use method::MethodInfo; 19 | use version::Version; 20 | use std::io; 21 | use utils::print::Printer; 22 | 23 | const MAGIC_VALUE: u32 = 0xCAFEBABE; 24 | 25 | #[derive(Debug)] 26 | pub struct Classfile { 27 | pub version: Version, 28 | pub constant_pool: ConstantPool, 29 | pub access_flags: flags::AccessFlags, 30 | this_class: usize, 31 | super_class: usize, 32 | interfaces: Vec, 33 | pub fields: Vec, 34 | pub methods: Vec, 35 | pub attrs: Vec, 36 | } 37 | 38 | impl Classfile { 39 | pub fn read(reader: &mut R) -> Result { 40 | // Read magic value 41 | let magic = try!(reader.read_u32::()); 42 | if magic != MAGIC_VALUE { 43 | bail!(ErrorKind::BadMagicValue(magic)); 44 | } 45 | 46 | // Read version 47 | let minor = try!(reader.read_u16::()); 48 | let major = try!(reader.read_u16::()); 49 | 50 | // Read constant pool 51 | let constant_pool = try!(ConstantPool::read(reader)); 52 | 53 | // Read access flags 54 | let access_flags = try!(reader.read_u16::()); 55 | let access_flags = match flags::AccessFlags::from_bits(access_flags) { 56 | Some(flags) => flags, 57 | None => bail!(ErrorKind::BadAccessFlags(access_flags)), 58 | }; 59 | 60 | // Read indexes 61 | let this_class = try!(reader.read_u16::()) as usize; 62 | let super_class = try!(reader.read_u16::()) as usize; 63 | 64 | // Read interfaces 65 | let interfaces_count = try!(reader.read_u16::()) as usize; 66 | let mut interfaces = Vec::with_capacity(interfaces_count); 67 | for _ in 0..interfaces_count { 68 | let interface_index = try!(reader.read_u16::()) as usize; 69 | interfaces.push(interface_index); 70 | } 71 | 72 | // Read fields 73 | let fields_count = try!(reader.read_u16::()) as usize; 74 | let mut fields = Vec::with_capacity(fields_count); 75 | for _ in 0..fields_count { 76 | let field = try!(FieldInfo::read(reader, &constant_pool)); 77 | fields.push(field); 78 | } 79 | 80 | // Read methods 81 | let methods_count = try!(reader.read_u16::()) as usize; 82 | let mut methods = Vec::with_capacity(methods_count); 83 | for _ in 0..methods_count { 84 | let method = try!(MethodInfo::read(reader, &constant_pool)); 85 | methods.push(method); 86 | } 87 | 88 | // Read attributes 89 | let attrs_count = try!(reader.read_u16::()) as usize; 90 | let mut attrs = Vec::with_capacity(attrs_count); 91 | for _ in 0..attrs_count { 92 | let attr = try!(Attr::read(reader, &constant_pool)); 93 | attrs.push(attr); 94 | } 95 | 96 | Ok(Classfile { 97 | version: Version::new(major, minor), 98 | constant_pool: constant_pool, 99 | access_flags: access_flags, 100 | this_class: this_class, 101 | super_class: super_class, 102 | interfaces: interfaces, 103 | fields: fields, 104 | methods: methods, 105 | attrs: attrs, 106 | }) 107 | } 108 | 109 | pub fn this_class(&self) -> Option<&constant::ConstantClassInfo> { 110 | self.constant_pool.get_class_info(self.this_class) 111 | } 112 | 113 | pub fn super_class(&self) -> Option<&constant::ConstantClassInfo> { 114 | self.constant_pool.get_class_info(self.super_class) 115 | } 116 | 117 | pub fn interfaces<'a>(&'a self) -> Interfaces<'a> { 118 | Interfaces::new(self) 119 | } 120 | 121 | pub fn dump(&self) { 122 | let mut printer = Printer::default(); 123 | self.print(&mut printer).unwrap(); 124 | } 125 | } 126 | 127 | impl_print! { 128 | Classfile(self, printer) { 129 | try!(printer.write_indent()); 130 | try!(writeln!(printer, "Version: {}", self.version)); 131 | 132 | try!(printer.write_indent()); 133 | try!(writeln!(printer, "Access flags: {:?}", self.access_flags)); 134 | 135 | let this_class = self.this_class().expect("Invalid class index"); 136 | try!(printer.write_indent()); 137 | try!(write!(printer, "This class: ")); 138 | try!(this_class.print(printer, &self.constant_pool)); 139 | try!(writeln!(printer, "")); 140 | 141 | let super_class = self.super_class().expect("Invalid class index"); 142 | try!(printer.write_indent()); 143 | try!(write!(printer, "Super class: ")); 144 | try!(super_class.print(printer, &self.constant_pool)); 145 | try!(writeln!(printer, "")); 146 | 147 | try!(printer.write_indent()); 148 | try!(writeln!(printer, "Constants:")); 149 | try!(self.constant_pool.print(&mut printer.sub_indent(1))); 150 | 151 | try!(printer.write_indent()); 152 | try!(writeln!(printer, "Interfaces:")); 153 | for iface in self.interfaces() { 154 | if let Some(iface) = iface { 155 | try!(iface.print(&mut printer.sub_indent(1), &self.constant_pool)); 156 | } 157 | } 158 | 159 | try!(printer.write_indent()); 160 | try!(writeln!(printer, "Fields:")); 161 | for field in self.fields.iter() { 162 | try!(field.print(&mut printer.sub_indent(1), &self.constant_pool)); 163 | } 164 | 165 | try!(printer.write_indent()); 166 | try!(writeln!(printer, "Methods:")); 167 | for method in self.methods.iter() { 168 | try!(method.print(&mut printer.sub_indent(1), &self.constant_pool)); 169 | } 170 | 171 | try!(printer.write_indent()); 172 | try!(writeln!(printer, "Attrs:")); 173 | for attr in self.attrs.iter() { 174 | try!(attr.print(&mut printer.sub_indent(1), &self.constant_pool)); 175 | } 176 | } 177 | } 178 | 179 | pub struct Interfaces<'a> { 180 | iter: ::std::slice::Iter<'a, usize>, 181 | constant_pool: &'a ConstantPool, 182 | } 183 | 184 | impl<'a> Interfaces<'a> { 185 | fn new(cf: &'a Classfile) -> Interfaces<'a> { 186 | Interfaces { 187 | iter: cf.interfaces.iter(), 188 | constant_pool: &cf.constant_pool, 189 | } 190 | } 191 | } 192 | 193 | impl<'a> Iterator for Interfaces<'a> { 194 | type Item = Option<&'a constant::ConstantClassInfo>; 195 | 196 | fn next(&mut self) -> Option { 197 | self.iter.next().map(|&index| self.constant_pool.get_class_info(index)) 198 | } 199 | } 200 | 201 | pub mod flags { 202 | bitflags! { 203 | pub struct AccessFlags: u16 { 204 | #[doc = "Declared public; may be accessed from outside its package."] 205 | const ACC_PUBLIC = 0x0001; 206 | #[doc = "Declared final; no subclasses allowed."] 207 | const ACC_FINAL = 0x0010; 208 | #[doc = "Treat superclass methods specially when invoked by the invokespecial instruction."] 209 | const ACC_SUPER = 0x0020; 210 | #[doc = "Is an interface, not a class."] 211 | const ACC_INTERFACE = 0x0200; 212 | #[doc = "Declared abstract; must not be instantiated."] 213 | const ACC_ABSTRACT = 0x0400; 214 | #[doc = "Declared synthetic; not present in the source code."] 215 | const ACC_SYNTHETIC = 0x1000; 216 | #[doc = "Declared as an annotation type."] 217 | const ACC_ANNOTATION = 0x2000; 218 | #[doc = "Declared as an enum type."] 219 | const ACC_ENUM = 0x4000; 220 | } 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /classfile/src/method.rs: -------------------------------------------------------------------------------- 1 | use byteorder::{ReadBytesExt, BigEndian}; 2 | use error::*; 3 | use std::io::Read; 4 | use super::attr::Attr; 5 | use super::constant::ConstantPool; 6 | 7 | #[derive(Debug)] 8 | pub struct MethodInfo { 9 | pub access_flags: flags::AccessFlags, 10 | name_index: usize, 11 | desc_index: usize, 12 | pub attrs: Vec, 13 | } 14 | 15 | impl MethodInfo { 16 | pub fn read(reader: &mut R, cp: &ConstantPool) -> Result { 17 | // Read access flags 18 | let access_flags = try!(reader.read_u16::()); 19 | let access_flags = match flags::AccessFlags::from_bits(access_flags) { 20 | Some(flags) => flags, 21 | None => bail!(ErrorKind::BadAccessFlags(access_flags)), 22 | }; 23 | 24 | // Read indexes 25 | let name_index = try!(reader.read_u16::()) as usize; 26 | let desc_index = try!(reader.read_u16::()) as usize; 27 | 28 | // Read attributes 29 | let attrs_count = try!(reader.read_u16::()) as usize; 30 | let mut attrs = Vec::with_capacity(attrs_count); 31 | for _ in 0..attrs_count { 32 | let attr = try!(Attr::read(reader, cp)); 33 | attrs.push(attr); 34 | } 35 | 36 | Ok(MethodInfo { 37 | access_flags: access_flags, 38 | name_index: name_index, 39 | desc_index: desc_index, 40 | attrs: attrs, 41 | }) 42 | } 43 | 44 | pub fn name<'a>(&self, pool: &'a ConstantPool) -> Option<&'a str> { 45 | pool.get_str(self.name_index) 46 | } 47 | 48 | pub fn desc<'a>(&self, pool: &'a ConstantPool) -> Option<&'a str> { 49 | pool.get_str(self.desc_index) 50 | } 51 | } 52 | 53 | impl_print! { 54 | MethodInfo(self, printer, constant_pool: &ConstantPool) { 55 | let name = self.name(constant_pool).expect("Invalid name index"); 56 | let desc = self.desc(constant_pool).expect("Invalid desc index"); 57 | 58 | try!(printer.write_indent()); 59 | try!(writeln!(printer, "Method `{}` [{}]:", name, desc)); 60 | 61 | { 62 | let mut printer = printer.sub_indent(1); 63 | 64 | try!(printer.write_indent()); 65 | try!(writeln!(printer, "Access flags: {:?}", self.access_flags)); 66 | 67 | try!(printer.write_indent()); 68 | try!(writeln!(printer, "Attrs:")); 69 | for attr in self.attrs.iter() { 70 | try!(attr.print(&mut printer.sub_indent(1), constant_pool)); 71 | } 72 | } 73 | } 74 | } 75 | 76 | pub mod flags { 77 | bitflags! { 78 | pub struct AccessFlags: u16 { 79 | #[doc = "Declared public; may be accessed from outside its package."] 80 | const ACC_PUBLIC = 0x0001; 81 | #[doc = "Declared private; accessible only within the defining class."] 82 | const ACC_PRIVATE = 0x0002; 83 | #[doc = "Declared protected; may be accessed within subclasses."] 84 | const ACC_PROTECTED = 0x0004; 85 | #[doc = "Declared static."] 86 | const ACC_STATIC = 0x0008; 87 | #[doc = "Declared final; must not be overridden (§5.4.5)."] 88 | const ACC_FINAL = 0x0010; 89 | #[doc = "Declared synchronized; invocation is wrapped by a monitor use."] 90 | const ACC_SYNCHRONIZED = 0x0020; 91 | #[doc = "A bridge method, generated by the compiler."] 92 | const ACC_BRIDGE = 0x0040; 93 | #[doc = "Declared with variable number of arguments."] 94 | const ACC_VARARGS = 0x0080; 95 | #[doc = "Declared native; implemented in a language other than Java."] 96 | const ACC_NATIVE = 0x0100; 97 | #[doc = "Declared abstract; no implementation is provided."] 98 | const ACC_ABSTRACT = 0x0400; 99 | #[doc = "Declared strictfp; floating-point mode is FP-strict."] 100 | const ACC_STRICT = 0x0800; 101 | #[doc = "Declared synthetic; not present in the source code."] 102 | const ACC_SYNTHETIC = 0x1000; 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /classfile/src/utils/io.rs: -------------------------------------------------------------------------------- 1 | use std::io::Read; 2 | use std::io::Result; 3 | use utils::vec; 4 | 5 | pub trait ReadExt: Read { 6 | fn read_vec(&mut self, size: usize) -> Result> { 7 | let mut data = unsafe { vec::uninitialized(size) }; 8 | try!(self.read_exact(&mut data)); 9 | Ok(data) 10 | } 11 | } 12 | 13 | impl ReadExt for T {} 14 | -------------------------------------------------------------------------------- /classfile/src/utils/macros.rs: -------------------------------------------------------------------------------- 1 | // Util macros 2 | 3 | macro_rules! impl_read { 4 | ($name:ident($reader:ident) -> $result:ty = $body:block) => { 5 | impl $name { 6 | #[allow(unused_imports)] 7 | pub fn read($reader: &mut R) -> $result { 8 | use byteorder::{ReadBytesExt, BigEndian}; 9 | $body 10 | } 11 | } 12 | }; 13 | ($name:ident($reader:ident, $($argname:ident: $argty:ty),+) -> $result:ty = $body:block) => { 14 | impl $name { 15 | #[allow(unused_imports)] 16 | pub fn read($reader: &mut R, 17 | $($argname: $argty),+) -> $result 18 | { 19 | use byteorder::{ReadBytesExt, BigEndian}; 20 | $body 21 | } 22 | } 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /classfile/src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] pub mod macros; 2 | pub mod io; 3 | pub mod vec; 4 | #[macro_use] pub mod print; 5 | -------------------------------------------------------------------------------- /classfile/src/utils/print.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | use std::default::Default; 3 | use std::fmt; 4 | use std::io; 5 | 6 | pub struct Printer { 7 | writer: W, 8 | pub indent_count: usize, 9 | pub indent_str: &'static str, 10 | } 11 | 12 | impl Printer { 13 | pub fn new(writer: W) -> Printer { 14 | Printer { 15 | writer: writer, 16 | indent_count: 0, 17 | indent_str: " ", 18 | } 19 | } 20 | 21 | pub fn by_ref(&mut self) -> Printer<&mut io::Write> { 22 | Printer { 23 | writer: &mut self.writer as &mut io::Write, 24 | indent_count: self.indent_count, 25 | indent_str: self.indent_str, 26 | } 27 | } 28 | 29 | pub fn sub(&mut self) -> Printer<&mut W> { 30 | Printer { 31 | writer: self.writer.by_ref(), 32 | indent_count: self.indent_count, 33 | indent_str: self.indent_str, 34 | } 35 | } 36 | 37 | pub fn sub_indent(&mut self, amount: isize) -> Printer<&mut W> { 38 | let mut sub = self.sub(); 39 | sub.with_indent(amount); 40 | sub 41 | } 42 | 43 | pub fn with_indent(&mut self, amount: isize) -> &mut Self { 44 | self.indent_count = (self.indent_count as isize + amount) as usize; 45 | self 46 | } 47 | 48 | pub fn write_indent(&mut self) -> io::Result<()> { 49 | for _ in 0..self.indent_count { 50 | try!(write!(self.writer, "{}", self.indent_str)); 51 | } 52 | Ok(()) 53 | } 54 | } 55 | 56 | impl io::Write for Printer { 57 | fn write(&mut self, buf: &[u8]) -> io::Result { 58 | self.writer.write(buf) 59 | } 60 | 61 | fn flush(&mut self) -> io::Result<()> { 62 | self.writer.flush() 63 | } 64 | 65 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { 66 | self.writer.write_all(buf) 67 | } 68 | 69 | fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> { 70 | self.writer.write_fmt(fmt) 71 | } 72 | } 73 | 74 | impl Default for Printer { 75 | fn default() -> Printer { 76 | Printer::new(io::stdout()) 77 | } 78 | } 79 | 80 | macro_rules! impl_print { 81 | ($name:ident($selfname:ident, $printer:ident) $block:block) => { 82 | impl $name { 83 | #[allow(unused_imports)] 84 | pub fn print(&$selfname, 85 | $printer: &mut $crate::utils::print::Printer) 86 | -> ::std::io::Result<()> 87 | { 88 | use ::std::io::prelude::*; 89 | $block 90 | Ok(()) 91 | } 92 | } 93 | }; 94 | ($name:ident($selfname:ident, $printer:ident, $($argname:ident: $argty:ty),+) $block:block) => { 95 | impl $name { 96 | #[allow(unused_imports)] 97 | pub fn print(&$selfname, 98 | $printer: &mut $crate::utils::print::Printer, 99 | $($argname: $argty),+) 100 | -> ::std::io::Result<()> 101 | { 102 | use ::std::io::prelude::*; 103 | $block 104 | Ok(()) 105 | } 106 | } 107 | }; 108 | } 109 | -------------------------------------------------------------------------------- /classfile/src/utils/vec.rs: -------------------------------------------------------------------------------- 1 | 2 | pub unsafe fn uninitialized(size: usize) -> Vec { 3 | let mut data = Vec::with_capacity(size); 4 | data.set_len(size); 5 | data 6 | } 7 | -------------------------------------------------------------------------------- /classfile/src/version.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | #[derive(Debug)] 4 | pub struct Version { 5 | pub major: u16, 6 | pub minor: u16, 7 | } 8 | 9 | impl Version { 10 | pub fn new(major: u16, minor: u16) -> Version { 11 | Version { 12 | major: major, 13 | minor: minor, 14 | } 15 | } 16 | } 17 | 18 | impl fmt::Display for Version { 19 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 20 | write!(f, "{}.{}", self.major, self.minor) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/bin/rjvm.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate clap; 2 | extern crate env_logger; 3 | extern crate jvm; 4 | 5 | use jvm::classfile::Classfile; 6 | use std::fs::File; 7 | use std::path::Path; 8 | 9 | fn main() { 10 | env_logger::init(); 11 | 12 | let matches = clap::App::new("rjvm") 13 | .author(crate_authors!()) 14 | .version(crate_version!()) 15 | .arg(clap::Arg::with_name("CLASSPATH") 16 | .short("c").long("classpath") 17 | .takes_value(true)) 18 | .arg(clap::Arg::with_name("CLASS") 19 | .required(true)) 20 | .get_matches(); 21 | 22 | let class = matches.value_of("CLASS").unwrap(); 23 | 24 | let path = Path::new(class).with_extension("class"); 25 | println!("Opening: {}", path.display()); 26 | 27 | let cf = { 28 | let mut file = File::open(path).unwrap(); 29 | Classfile::read(&mut file).unwrap() 30 | }; 31 | 32 | cf.dump(); 33 | } 34 | -------------------------------------------------------------------------------- /src/classpath/mod.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KokaKiwi/rust-jvm/f25e6e0946626ca46f770746227fd55e96eeb105/src/classpath/mod.rs -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub extern crate jvm_classfile as classfile; 2 | 3 | pub mod classpath; 4 | --------------------------------------------------------------------------------