From 724b2f3eaac5e78f2e60a16ba28b552ccd085277 Mon Sep 17 00:00:00 2001 From: Sander Hautvast Date: Wed, 20 Sep 2023 13:24:07 +0200 Subject: [PATCH] added get_names for methods --- src/lib.rs | 24 ++++++++---- src/types.rs | 33 ++++++++++++++--- tests/class_tests.rs | 87 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+), 12 deletions(-) create mode 100644 tests/class_tests.rs diff --git a/src/lib.rs b/src/lib.rs index e23400b..f18b005 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ pub mod types; +use std::rc::Rc; use crate::types::{CpEntry, Class, Field, Attribute, Method}; pub fn get_class(bytecode: Vec) -> Option { @@ -12,6 +13,8 @@ pub fn get_class(bytecode: Vec) -> Option { constant_pool.push(read_constant_pool_entry(&mut index, &bytecode)); } + let constant_pool = Rc::new(constant_pool); + let access_flags = get_u16(&bytecode, index); let this_class = get_u16(&bytecode, index + 2); let super_class = get_u16(&bytecode, index + 4); @@ -35,7 +38,7 @@ pub fn get_class(bytecode: Vec) -> Option { index += 2; let mut methods = vec![]; for _ in 0..methods_count { - methods.push(read_method(&mut index, &bytecode)); + methods.push(read_method(constant_pool.clone(), &mut index, &bytecode)); } let attributes_count = get_u16(&bytecode, index); @@ -61,7 +64,7 @@ pub fn get_class(bytecode: Vec) -> Option { fn check_magic(bytecode: &Vec) { if &bytecode[0..4] != [0xCA, 0xFE, 0xBA, 0xBE] { - panic!(); //must never happen + panic!("Invalid class file"); } } @@ -97,12 +100,12 @@ fn read_constant_pool_entry(index: &mut usize, bytecode: &Vec) -> CpEntry { 7 => { let name_index = get_u16(bytecode, *index + 1); *index += 3; - CpEntry::Class(name_index) + CpEntry::ClassRef(name_index) } 8 => { let string_index = get_u16(bytecode, *index + 1); *index += 3; - CpEntry::String(string_index) + CpEntry::StringRef(string_index) } 9 => { let class_index = get_u16(bytecode, *index + 1); @@ -127,7 +130,13 @@ fn read_constant_pool_entry(index: &mut usize, bytecode: &Vec) -> CpEntry { let descriptor_index = get_u16(bytecode, *index + 3); *index += 5; CpEntry::NameAndType(name_index, descriptor_index) - } + }, + // 15 MethodHandle, + // 16 MethodType, + // 17 Dynamic, + // 18 InvokeDynamic, + // 19 Module, + // 20 Package, _ => panic!() } } @@ -151,9 +160,9 @@ fn read_field(index: &mut usize, bytecode: &Vec) -> Field { } } -fn read_method(index: &mut usize, bytecode: &Vec) -> Method { +fn read_method(constant_pool: Rc>, index: &mut usize, bytecode: &Vec) -> Method { let access_flags = get_u16(bytecode, *index); - let name_index = get_u16(bytecode, *index + 2); + let name_index = get_u16(bytecode, *index + 2) as usize; let descriptor_index = get_u16(bytecode, *index + 4); let attributes_count = get_u16(bytecode, *index + 6); *index += 8; @@ -162,6 +171,7 @@ fn read_method(index: &mut usize, bytecode: &Vec) -> Method { attributes.push(read_attribute(bytecode, index)); } Method { + constant_pool, access_flags, name_index, descriptor_index, diff --git a/src/types.rs b/src/types.rs index d2c46d6..1332a93 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,9 +1,12 @@ +use std::rc::Rc; +use crate::types::CpEntry::*; + #[derive(Debug)] //TODO create factory function pub struct Class { pub minor_version: u16, pub major_version: u16, - pub constant_pool: Vec, + pub constant_pool: Rc>, pub access_flags: u16, pub this_class: u16, pub super_class: u16, @@ -13,6 +16,16 @@ pub struct Class { pub attributes: Vec, } +impl<'a> Class { + pub fn get_version(&self) -> (u16, u16) { + (self.major_version, self.minor_version) + } + + pub fn get_methods(&self) -> &Vec { + &self.methods + } +} + #[derive(Debug)] pub enum CpEntry { @@ -21,8 +34,8 @@ pub enum CpEntry { Float(f32), Long(i64), Double(f64), - Class(u16), - String(u16), + ClassRef(u16), + StringRef(u16), Fieldref(u16, u16), MethodRef(u16, u16), InterfaceMethodref(u16, u16), @@ -45,10 +58,20 @@ pub struct Attribute { } #[derive(Debug)] -pub struct Method{ +pub struct Method { + pub constant_pool: Rc>, pub access_flags: u16, - pub name_index: u16, + pub name_index: usize, pub descriptor_index: u16, pub attributes_count: u16, pub attributes: Vec, +} + +impl Method { + pub fn name(&self) -> &str { + if let Utf8(s) = &self.constant_pool[self.name_index - 1] { + return &s; + } + panic!() // name must be utf8 + } } \ No newline at end of file diff --git a/tests/class_tests.rs b/tests/class_tests.rs new file mode 100644 index 0000000..312f387 --- /dev/null +++ b/tests/class_tests.rs @@ -0,0 +1,87 @@ +use std::rc::Rc; +use classfile_reader::types::{Attribute, Class, Field, Method}; +use classfile_reader::types::CpEntry::*; + +#[test] +fn get_version() { + assert_eq!((55, 0), get_class().get_version()); +} + +#[test] +fn get_methods() { + for m in get_class().get_methods() { + println!("{}", m.name()); + } +} + +fn get_class() -> Class { + let cp = Rc::new(vec![MethodRef(2, 3), + ClassRef(4), + NameAndType(5, 6), + Utf8("java/lang/Object".to_owned()), + Utf8("".to_owned()), + Utf8("()V".to_owned()), + Fieldref(8, 9), + ClassRef(10), + NameAndType(11, 12), + Utf8("com/github/shautvast/reflective/MetaField".to_owned()), + Utf8("name".to_owned()), + Utf8("Ljava/lang/String;".to_owned()), + Fieldref(8, 14), + NameAndType(15, 16), + Utf8("modifiers".to_owned()), + Utf8("I".to_owned()), + Utf8("(Ljava/lang/String;I)V".to_owned()), + Utf8("Code".to_owned()), + Utf8("LineNumberTable".to_owned()), + Utf8("LocalVariableTable".to_owned()), + Utf8("this".to_owned()), + Utf8("Lcom/github/shautvast/reflective/MetaField;".to_owned()), + Utf8("getName".to_owned()), + Utf8("()Ljava/lang/String;".to_owned()), + Utf8("getModifiers".to_owned()), + Utf8("()I".to_owned()), + Utf8("SourceFile".to_owned()), + Utf8("MetaField.java".to_owned())]); + + Class { + minor_version: 0, + major_version: 55, + constant_pool: cp.clone(), + interfaces: vec![], + super_class: 2, + access_flags: 33, + this_class: 8, + methods: vec![ + Method { + constant_pool: cp.clone(), + access_flags: 1, + name_index: 5, + descriptor_index: 17, + attributes_count: 1, + attributes: vec![Attribute { + attribute_name_index: 18, + info: vec![0, 2, 0, 3, 0, 0, 0, 15, 42, 183, 0, 1, 42, 43, 181, 0, 7, 42, 28, + 181, 0, 13, 177, 0, 0, 0, 2, 0, 19, 0, 0, 0, + 18, 0, 4, 0, 0, 0, 8, 0, 4, 0, 9, 0, 9, 0, 10, 0, 14, 0, 11, 0, 20, 0, 0, + 0, 32, 0, 3, 0, 0, 0, 15, 0, 21, 0, 22, 0, 0, 0, 0, 0, 15, 0, 11, + 0, 12, 0, 1, 0, 0, 0, 15, 0, 15, 0, 16, 0, 2], + }], + }, + Method { + constant_pool: cp, + access_flags: 1, + name_index: 23, + descriptor_index: 24, + attributes_count: 1, + attributes: vec![Attribute { + attribute_name_index: 18, + info: vec![0, 1, 0, 1, 0, 0, 0, 5, 42, 180, 0, 7, 176, 0, 0, 0, 2, 0, 19, 0, 0, 0, 6, 0, + 1, 0, 0, 0, 14, 0, 20, 0, 0, 0, 12, 0, 1, 0, 0, 0, 5, 0, 21, 0, 22, 0, 0], + }], + }], + fields: vec![Field { access_flags: 18, name_index: 11, descriptor_index: 12, attributes_count: 0, attributes: vec![] }, + Field { access_flags: 18, name_index: 15, descriptor_index: 16, attributes_count: 0, attributes: vec![] }], + attributes: vec![Attribute { attribute_name_index: 27, info: vec![0, 28] }], + } +} \ No newline at end of file