fixed cp entry indices

This commit is contained in:
Sander Hautvast 2023-09-26 14:54:42 +02:00
parent 2f739cb4db
commit 6bad19c244
5 changed files with 49 additions and 35 deletions

Binary file not shown.

View file

@ -1,6 +1,8 @@
public class Dummy { public class Dummy {
public static int get(){ private final static double answer = 42.0;
return 42;
public static double get(){
return answer;
} }
} }

View file

@ -11,10 +11,14 @@ pub fn get_class(bytecode: Vec<u8>) -> Option<Class> {
check_magic(&bytecode); check_magic(&bytecode);
let constant_pool_count = read_u16(&bytecode, 8); let constant_pool_count = read_u16(&bytecode, 8);
// println!("cp count: {}", constant_pool_count);
let mut index = 10; let mut index = 10;
let mut constant_pool: Vec<CpEntry> = vec![]; let mut constant_pool: HashMap<usize, CpEntry> = HashMap::with_capacity(constant_pool_count as usize);
for cp_index in 0..constant_pool_count - 1 { let mut cp_index: usize = 1;
constant_pool.push(read_constant_pool_entry((cp_index + 1) as usize, &mut index, &bytecode)); for _ in 1..constant_pool_count - 1
{
constant_pool.insert(cp_index, read_constant_pool_entry(&mut cp_index, &mut index, &bytecode));
cp_index += 1;
} }
let constant_pool = Rc::new(constant_pool); let constant_pool = Rc::new(constant_pool);
@ -78,68 +82,73 @@ fn check_magic(bytecode: &[u8]) {
} }
} }
fn read_constant_pool_entry(cp_index: usize, index: &mut usize, bytecode: &[u8]) -> CpEntry { fn read_constant_pool_entry(cp_index: &mut usize, index: &mut usize, bytecode: &[u8]) -> CpEntry {
let tag = bytecode[*index]; let tag = bytecode[*index];
// println!("#{}: {}", cp_index, tag);
match tag { match tag {
1 => { 1 => {
let len = read_u16(bytecode, *index + 1) as usize; let len = read_u16(bytecode, *index + 1) as usize;
let utf: Vec<u8> = Vec::from(&bytecode[*index + 3..*index + 3 + len]); let utf: Vec<u8> = Vec::from(&bytecode[*index + 3..*index + 3 + len]);
*index += len + 3; *index += len + 3;
CpEntry::Utf8(cp_index, String::from_utf8(utf).unwrap()) CpEntry::Utf8(*cp_index, String::from_utf8(utf).unwrap())
} }
3 => { 3 => {
let value = read_i32(bytecode, *index + 1); let value = read_i32(bytecode, *index + 1);
*index += 5; *index += 5;
CpEntry::Integer(cp_index, value) CpEntry::Integer(*cp_index, value)
} }
4 => { 4 => {
let value = read_f32(bytecode, *index + 1); let value = read_f32(bytecode, *index + 1);
*index += 5; *index += 5;
CpEntry::Float(cp_index, value) CpEntry::Float(*cp_index, value)
} }
5 => { 5 => {
let value = read_i64(bytecode, *index + 1); let value = read_i64(bytecode, *index + 1);
*index += 9; *index += 9;
CpEntry::Long(cp_index, value) let r = CpEntry::Long(*cp_index, value);
*cp_index += 1;
r
} }
6 => { 6 => {
let value = read_f64(bytecode, *index + 1); let value = read_f64(bytecode, *index + 1);
*index += 9; *index += 9;
CpEntry::Double(cp_index, value) let r = CpEntry::Double(*cp_index, value);
*cp_index += 1;
r
} }
7 => { 7 => {
let name_index = read_u16(bytecode, *index + 1); let name_index = read_u16(bytecode, *index + 1);
*index += 3; *index += 3;
CpEntry::ClassRef(cp_index, name_index) CpEntry::ClassRef(*cp_index, name_index)
} }
8 => { 8 => {
let string_index = read_u16(bytecode, *index + 1); let string_index = read_u16(bytecode, *index + 1);
*index += 3; *index += 3;
CpEntry::StringRef(cp_index, string_index) CpEntry::StringRef(*cp_index, string_index)
} }
9 => { 9 => {
let class_index = read_u16(bytecode, *index + 1); let class_index = read_u16(bytecode, *index + 1);
let name_and_type_index = read_u16(bytecode, *index + 3); let name_and_type_index = read_u16(bytecode, *index + 3);
*index += 5; *index += 5;
CpEntry::Fieldref(cp_index, class_index, name_and_type_index) CpEntry::Fieldref(*cp_index, class_index, name_and_type_index)
} }
10 => { 10 => {
let class_index = read_u16(bytecode, *index + 1); let class_index = read_u16(bytecode, *index + 1);
let name_and_type_index = read_u16(bytecode, *index + 3); let name_and_type_index = read_u16(bytecode, *index + 3);
*index += 5; *index += 5;
CpEntry::MethodRef(cp_index, class_index, name_and_type_index) CpEntry::MethodRef(*cp_index, class_index, name_and_type_index)
} }
11 => { 11 => {
let class_index = read_u16(bytecode, *index + 1); let class_index = read_u16(bytecode, *index + 1);
let name_and_type_index = read_u16(bytecode, *index + 3); let name_and_type_index = read_u16(bytecode, *index + 3);
*index += 5; *index += 5;
CpEntry::InterfaceMethodref(cp_index, class_index, name_and_type_index) CpEntry::InterfaceMethodref(*cp_index, class_index, name_and_type_index)
} }
12 => { 12 => {
let name_index = read_u16(bytecode, *index + 1) as usize; let name_index = read_u16(bytecode, *index + 1) as usize;
let descriptor_index = read_u16(bytecode, *index + 3) as usize; let descriptor_index = read_u16(bytecode, *index + 3) as usize;
*index += 5; *index += 5;
CpEntry::NameAndType(cp_index, name_index, descriptor_index) CpEntry::NameAndType(*cp_index, name_index, descriptor_index)
} }
// 15 MethodHandle, // 15 MethodHandle,
// 16 MethodType, // 16 MethodType,
@ -147,11 +156,12 @@ fn read_constant_pool_entry(cp_index: usize, index: &mut usize, bytecode: &[u8])
// 18 InvokeDynamic, // 18 InvokeDynamic,
// 19 Module, // 19 Module,
// 20 Package, // 20 Package,
_ => panic!()
_ => panic!("cp entry type not recognized")
} }
} }
fn read_field(constant_pool: Rc<Vec<CpEntry>>, index: &mut usize, bytecode: &[u8]) -> Field { fn read_field(constant_pool: Rc<HashMap<usize, CpEntry>>, index: &mut usize, bytecode: &[u8]) -> Field {
let access_flags = read_u16(bytecode, *index); let access_flags = read_u16(bytecode, *index);
let name_index = read_u16(bytecode, *index + 2) as usize; let name_index = read_u16(bytecode, *index + 2) as usize;
let descriptor_index = read_u16(bytecode, *index + 4) as usize; let descriptor_index = read_u16(bytecode, *index + 4) as usize;
@ -162,7 +172,7 @@ fn read_field(constant_pool: Rc<Vec<CpEntry>>, index: &mut usize, bytecode: &[u8
if let Some(att) = read_attribute(constant_pool.clone(), bytecode, index) { if let Some(att) = read_attribute(constant_pool.clone(), bytecode, index) {
attributes.insert(att.0, att.1); attributes.insert(att.0, att.1);
} else { } else {
panic!(); // bug/not-implemented panic!("attribute not recognized"); // bug/not-implemented
} }
} }
Field::new( Field::new(
@ -174,7 +184,7 @@ fn read_field(constant_pool: Rc<Vec<CpEntry>>, index: &mut usize, bytecode: &[u8
) )
} }
fn read_method(constant_pool: Rc<Vec<CpEntry>>, index: &mut usize, bytecode: &[u8]) -> Method { fn read_method(constant_pool: Rc<HashMap<usize, CpEntry>>, index: &mut usize, bytecode: &[u8]) -> Method {
let access_flags = read_u16(bytecode, *index); let access_flags = read_u16(bytecode, *index);
let name_index = read_u16(bytecode, *index + 2) as usize; let name_index = read_u16(bytecode, *index + 2) as usize;
let descriptor_index = read_u16(bytecode, *index + 4) as usize; let descriptor_index = read_u16(bytecode, *index + 4) as usize;
@ -197,7 +207,7 @@ fn read_method(constant_pool: Rc<Vec<CpEntry>>, index: &mut usize, bytecode: &[u
) )
} }
fn read_attribute(constant_pool: Rc<Vec<CpEntry>>, bytecode: &[u8], index: &mut usize) -> Option<(String, AttributeType)> { fn read_attribute(constant_pool: Rc<HashMap<usize, CpEntry>>, bytecode: &[u8], index: &mut usize) -> Option<(String, AttributeType)> {
let attribute_name_index = read_u16(bytecode, *index) as usize; let attribute_name_index = read_u16(bytecode, *index) as usize;
*index += 2; *index += 2;
let attribute_length = read_u32(bytecode, *index) as usize; let attribute_length = read_u32(bytecode, *index) as usize;
@ -206,8 +216,8 @@ fn read_attribute(constant_pool: Rc<Vec<CpEntry>>, bytecode: &[u8], index: &mut
*index += attribute_length; *index += attribute_length;
if let CpEntry::Utf8(_, s) = &constant_pool[attribute_name_index - 1] { if let CpEntry::Utf8(_, s) = &constant_pool.get(&attribute_name_index).unwrap() {
// println!("{}", s); // println!("Att [{}]", s);
return match s.as_str() { return match s.as_str() {
"ConstantValue" => { "ConstantValue" => {
assert_eq!(info.len(), 2); assert_eq!(info.len(), 2);
@ -237,6 +247,7 @@ fn read_attribute(constant_pool: Rc<Vec<CpEntry>>, bytecode: &[u8], index: &mut
Some(("Code".into(), AttributeType::Code(MethodCode::new(max_stack, max_locals, code, exception_table, code_attributes)))) Some(("Code".into(), AttributeType::Code(MethodCode::new(max_stack, max_locals, code, exception_table, code_attributes))))
} }
"SourceFile" => Some(("SourceFile".into(), AttributeType::SourceFile)), "SourceFile" => Some(("SourceFile".into(), AttributeType::SourceFile)),
"LineNumberTable" => Some(("SourceFile".into(), AttributeType::LineNumberTable)),
_ => None _ => None
}; };
} }

View file

@ -4,6 +4,7 @@ use std::io::Read;
fn main() { fn main() {
let bytecode = read_class_file("./Dummy.class"); let bytecode = read_class_file("./Dummy.class");
if let Some(class) = classfile_reader::get_class(bytecode){ if let Some(class) = classfile_reader::get_class(bytecode){
println!("{:?}", class);
let ret = class.execute("public static get()I"); let ret = class.execute("public static get()I");
println!("{:?}", ret); println!("{:?}", ret);
} }

View file

@ -7,7 +7,7 @@ use crate::{CpEntry, opcodes};
pub struct Class { pub struct Class {
pub minor_version: u16, pub minor_version: u16,
pub major_version: u16, pub major_version: u16,
pub constant_pool: Rc<Vec<CpEntry>>, pub constant_pool: Rc<HashMap<usize, CpEntry>>,
pub access_flags: u16, pub access_flags: u16,
pub this_class: u16, pub this_class: u16,
pub super_class: u16, pub super_class: u16,
@ -29,7 +29,7 @@ impl Class {
} }
pub struct Method { pub struct Method {
constant_pool: Rc<Vec<CpEntry>>, constant_pool: Rc<HashMap<usize, CpEntry>>,
access_flags: u16, access_flags: u16,
name_index: usize, name_index: usize,
descriptor_index: usize, descriptor_index: usize,
@ -44,7 +44,7 @@ impl fmt::Debug for Method {
} }
impl Method { impl Method {
pub fn new(constant_pool: Rc<Vec<CpEntry>>, pub fn new(constant_pool: Rc<HashMap<usize, CpEntry>>,
access_flags: u16, access_flags: u16,
name_index: usize, name_index: usize,
descriptor_index: usize, descriptor_index: usize,
@ -54,10 +54,10 @@ impl Method {
pub fn name(&self) -> String { pub fn name(&self) -> String {
let mut full_name = get_modifier(self.access_flags); let mut full_name = get_modifier(self.access_flags);
if let CpEntry::Utf8(_, s) = &self.constant_pool[&self.name_index - 1] { if let CpEntry::Utf8(_, s) = &self.constant_pool.get(&self.name_index).unwrap() {
full_name.push_str(s); full_name.push_str(s);
} }
if let CpEntry::Utf8(_, s) = &self.constant_pool[&self.descriptor_index - 1] { if let CpEntry::Utf8(_, s) = &self.constant_pool.get(&self.descriptor_index).unwrap() {
full_name.push_str(s); full_name.push_str(s);
} }
@ -76,10 +76,10 @@ impl Method {
pc += 1; pc += 1;
let c = code.opcodes[pc] as i32; let c = code.opcodes[pc] as i32;
stack.push(Value::I32(c)); stack.push(Value::I32(c));
}, }
&opcodes::ireturn => { &opcodes::ireturn => {
return stack.pop(); return stack.pop();
}, }
//TODO implement all opcodes //TODO implement all opcodes
_ => {} _ => {}
} }
@ -91,7 +91,7 @@ impl Method {
} }
pub struct Field { pub struct Field {
constant_pool: Rc<Vec<CpEntry>>, constant_pool: Rc<HashMap<usize, CpEntry>>,
access_flags: u16, access_flags: u16,
name_index: usize, name_index: usize,
descriptor_index: usize, descriptor_index: usize,
@ -110,7 +110,7 @@ impl fmt::Debug for Field {
} }
impl Field { impl Field {
pub fn new(constant_pool: Rc<Vec<CpEntry>>, pub fn new(constant_pool: Rc<HashMap<usize, CpEntry>>,
access_flags: u16, access_flags: u16,
name_index: usize, name_index: usize,
descriptor_index: usize, descriptor_index: usize,
@ -121,11 +121,11 @@ impl Field {
pub fn name(&self) -> String { pub fn name(&self) -> String {
let mut full_name = get_modifier(self.access_flags); let mut full_name = get_modifier(self.access_flags);
if let CpEntry::Utf8(_, s) = &self.constant_pool[&self.descriptor_index - 1] { if let CpEntry::Utf8(_, s) = &self.constant_pool.get(&self.descriptor_index).unwrap() {
full_name.push_str(s); full_name.push_str(s);
} }
full_name.push(' '); full_name.push(' ');
if let CpEntry::Utf8(_, s) = &self.constant_pool[&self.name_index - 1] { if let CpEntry::Utf8(_, s) = &self.constant_pool.get(&self.name_index).unwrap() {
full_name.push_str(s); full_name.push_str(s);
} }