Refactored CpInfo to be more nested

So I can only refer to a single variant
This commit is contained in:
nora 2021-08-21 16:50:20 +02:00
parent 3546a5b268
commit 860346a910
5 changed files with 418 additions and 231 deletions

View file

@ -2,7 +2,15 @@ use crate::parse::{ClassFile, ParseErr};
mod execute; mod execute;
mod parse; mod parse;
mod ui;
pub fn parse_class_file(file: &[u8]) -> Result<ClassFile, ParseErr> { pub fn parse_class_file(file: &[u8]) -> Result<ClassFile, ParseErr> {
parse::parse_class_file(file) parse::parse_class_file(file)
} }
pub fn display_class<W>(w: W, class: &ClassFile) -> std::io::Result<()>
where
W: std::io::Write,
{
ui::display_class(w, class)
}

View file

@ -1,10 +1,25 @@
use coldsquare::parse_class_file; use coldsquare::{display_class, parse_class_file};
fn main() { fn main() {
let file = "Test.class"; let file = std::env::args().nth(1).unwrap_or_else(|| {
let file = std::fs::read(file).unwrap(); eprintln!("No file provided");
std::process::exit(1);
});
let file = std::fs::read(file).unwrap_or_else(|_| {
eprintln!("Could not read file");
std::process::exit(1);
});
let class_file = parse_class_file(&file).unwrap(); let class_file = match parse_class_file(&file) {
Ok(file) => file,
Err(err) => {
eprintln!("{}", err);
return;
}
};
let stdout = std::io::stdout();
println!("{:?}", class_file); if let Err(why) = display_class(stdout.lock(), &class_file) {
eprintln!("{}", why);
}
} }

View file

@ -3,10 +3,19 @@ mod model;
mod test; mod test;
pub use model::*; pub use model::*;
use std::fmt::{Display, Formatter};
#[derive(Debug)] #[derive(Debug)]
pub struct ParseErr(String); pub struct ParseErr(String);
impl Display for ParseErr {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Could not parse class file: {}", self.0)
}
}
impl std::error::Error for ParseErr {}
pub type Result<T> = std::result::Result<T, ParseErr>; pub type Result<T> = std::result::Result<T, ParseErr>;
#[derive(Clone)] #[derive(Clone)]
@ -35,6 +44,10 @@ impl<'a> Data<'a> {
Ok(((self.u1()? as u2) << 8) | self.u1()? as u2) Ok(((self.u1()? as u2) << 8) | self.u1()? as u2)
} }
fn cp(&mut self) -> Result<FromPool> {
Ok(self.u2()?.into())
}
fn u4(&mut self) -> Result<u4> { fn u4(&mut self) -> Result<u4> {
Ok(((self.u2()? as u4) << 16) | self.u2()? as u4) Ok(((self.u2()? as u4) << 16) | self.u2()? as u4)
} }
@ -100,6 +113,12 @@ macro_rules! parse_primitive {
parse_primitive!(u1, u2, u4); parse_primitive!(u1, u2, u4);
impl Parse for FromPool {
fn parse(data: &mut Data) -> Result<Self> {
Ok(data.u2()?.into())
}
}
impl Parse for ClassFile { impl Parse for ClassFile {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data) -> Result<Self> {
let magic = data.u4()?; let magic = data.u4()?;
@ -109,8 +128,8 @@ impl Parse for ClassFile {
let constant_pool_count = data.u2()?; let constant_pool_count = data.u2()?;
let constant_pool = parse_vec(data, constant_pool_count - 1)?; // the minus one is important let constant_pool = parse_vec(data, constant_pool_count - 1)?; // the minus one is important
let access_flags = data.u2()?; let access_flags = data.u2()?;
let this_class = data.u2()?; let this_class = data.cp()?;
let super_class = data.u2()?; let super_class = data.cp()?;
let interfaces_count = data.u2()?; let interfaces_count = data.u2()?;
let interfaces = parse_vec(data, interfaces_count)?; let interfaces = parse_vec(data, interfaces_count)?;
let fields_count = data.u2()?; let fields_count = data.u2()?;
@ -148,71 +167,96 @@ impl Parse for CpInfo {
let tag = data.u1()?; let tag = data.u1()?;
Ok(match tag { Ok(match tag {
7 => Self::Class { 7 => Self {
tag, tag,
name_index: data.u2()?, inner: CpInfoInner::Class(cp_info::Class {
name_index: data.cp()?,
}),
}, },
9 => Self::Fieldref { 9 => Self {
tag, tag,
class_index: data.u2()?, inner: CpInfoInner::Fieldref(cp_info::Fieldref {
name_and_type_index: data.u2()?, class_index: data.cp()?,
name_and_type_index: data.cp()?,
}),
}, },
10 => Self::MethodRef { 10 => Self {
tag, tag,
class_index: data.u2()?, inner: CpInfoInner::MethodRef(cp_info::MethodRef {
name_and_type_index: data.u2()?, class_index: data.cp()?,
name_and_type_index: data.cp()?,
}),
}, },
11 => Self::InterfaceMethodref { 11 => Self {
tag, tag,
class_index: data.u2()?, inner: CpInfoInner::InterfaceMethodref(cp_info::InterfaceMethodref {
name_and_type_index: data.u2()?, class_index: data.cp()?,
name_and_type_index: data.cp()?,
}),
}, },
8 => Self::String { 8 => Self {
tag, tag,
string_index: data.u2()?, inner: CpInfoInner::String(cp_info::String {
string_index: data.cp()?,
}),
}, },
3 => Self::Integer { 3 => Self {
tag, tag,
bytes: data.u4()?, inner: CpInfoInner::Integer(cp_info::Integer { bytes: data.u4()? }),
}, },
4 => Self::Float { 4 => Self {
tag, tag,
bytes: data.u4()?, inner: CpInfoInner::Float(cp_info::Float { bytes: data.u4()? }),
}, },
5 => Self::Long { 5 => Self {
tag, tag,
high_bytes: data.u4()?, inner: CpInfoInner::Long(cp_info::Long {
low_bytes: data.u4()?, high_bytes: data.u4()?,
low_bytes: data.u4()?,
}),
}, },
6 => Self::Double { 6 => Self {
tag, tag,
high_bytes: data.u4()?, inner: CpInfoInner::Double(cp_info::Double {
low_bytes: data.u4()?, high_bytes: data.u4()?,
low_bytes: data.u4()?,
}),
}, },
12 => Self::NameAndType { 12 => Self {
tag, tag,
name_index: data.u2()?, inner: CpInfoInner::NameAndType(cp_info::NameAndType {
descriptor_index: data.u2()?, name_index: data.cp()?,
descriptor_index: data.cp()?,
}),
}, },
1 => Self::Utf8 { 1 => Self {
tag, tag,
length: data.u2()?, inner: CpInfoInner::Utf8(cp_info::Utf8 {
bytes: String::from_utf8(parse_vec(data, data.last_u2()?)?) length: data.u2()?,
.map_err(|err| ParseErr(format!("Invalid utf8 in CpInfo::Utf8: {}", err)))?, bytes: String::from_utf8(parse_vec(data, data.last_u2()?)?).map_err(|err| {
ParseErr(format!("Invalid utf8 in CpInfo::Utf8: {}", err))
})?,
}),
}, },
15 => Self::MethodHandle { 15 => Self {
tag, tag,
reference_kind: data.u1()?, inner: CpInfoInner::MethodHandle(cp_info::MethodHandle {
reference_index: data.u2()?, reference_kind: data.u1()?,
reference_index: data.cp()?,
}),
}, },
16 => Self::MethodType { 16 => Self {
tag, tag,
descriptor_index: data.u2()?, inner: CpInfoInner::MethodType(cp_info::MethodType {
descriptor_index: data.cp()?,
}),
}, },
18 => Self::InvokeDynamic { 18 => Self {
tag, tag,
bootstrap_method_attr_index: data.u2()?, inner: CpInfoInner::InvokeDynamic(cp_info::InvokeDynamic {
name_and_type_index: data.u2()?, bootstrap_method_attr_index: data.u2()?,
name_and_type_index: data.cp()?,
}),
}, },
_ => Err(ParseErr(format!("Invalid CPInfo tag: {}", tag)))?, _ => Err(ParseErr(format!("Invalid CPInfo tag: {}", tag)))?,
}) })
@ -223,8 +267,8 @@ impl Parse for FieldInfo {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data) -> Result<Self> {
Ok(Self { Ok(Self {
access_flags: data.u2()?, access_flags: data.u2()?,
name_index: data.u2()?, name_index: data.cp()?,
descriptor_index: data.u2()?, descriptor_index: data.cp()?,
attributes_count: data.u2()?, attributes_count: data.u2()?,
attributes: parse_vec(data, data.last_u2()?)?, attributes: parse_vec(data, data.last_u2()?)?,
}) })
@ -235,8 +279,8 @@ impl Parse for MethodInfo {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data) -> Result<Self> {
Ok(Self { Ok(Self {
access_flags: data.u2()?, access_flags: data.u2()?,
name_index: data.u2()?, name_index: data.cp()?,
descriptor_index: data.u2()?, descriptor_index: data.cp()?,
attributes_count: data.u2()?, attributes_count: data.u2()?,
attributes: parse_vec(data, data.last_u2()?)?, attributes: parse_vec(data, data.last_u2()?)?,
}) })
@ -246,7 +290,7 @@ impl Parse for MethodInfo {
impl Parse for AttributeInfo { impl Parse for AttributeInfo {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data) -> Result<Self> {
Ok(Self { Ok(Self {
attribute_name_index: data.u2()?, attribute_name_index: data.cp()?,
attribute_length: data.u4()?, attribute_length: data.u4()?,
inner: AttributeInfoInner::Unknown { inner: AttributeInfoInner::Unknown {
attribute_content: parse_vec(data, data.last_u4()? as usize)?, attribute_content: parse_vec(data, data.last_u4()? as usize)?,
@ -340,9 +384,9 @@ impl Parse for VerificationTypeInfo {
impl Parse for AttributeInnerClass { impl Parse for AttributeInnerClass {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data) -> Result<Self> {
Ok(Self { Ok(Self {
inner_class_info_index: data.u2()?, inner_class_info_index: data.cp()?,
outer_class_info_index: data.u2()?, outer_class_info_index: data.cp()?,
inner_class_name_index: data.u2()?, inner_class_name_index: data.cp()?,
inner_class_access_flags: data.u2()?, inner_class_access_flags: data.u2()?,
}) })
} }
@ -362,8 +406,8 @@ impl Parse for AttributeLocalVariableTable {
Ok(Self { Ok(Self {
start_pc: data.u2()?, start_pc: data.u2()?,
length: data.u2()?, length: data.u2()?,
name_index: data.u2()?, name_index: data.cp()?,
descriptor_or_signature_index: data.u2()?, descriptor_or_signature_index: data.cp()?,
index: data.u2()?, index: data.u2()?,
}) })
} }
@ -372,7 +416,7 @@ impl Parse for AttributeLocalVariableTable {
impl Parse for Annotation { impl Parse for Annotation {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data) -> Result<Self> {
Ok(Self { Ok(Self {
type_index: data.u2()?, type_index: data.cp()?,
num_element_value_pairs: data.u2()?, num_element_value_pairs: data.u2()?,
element_value_pairs: parse_vec(data, data.last_u2()?)?, element_value_pairs: parse_vec(data, data.last_u2()?)?,
}) })
@ -382,7 +426,7 @@ impl Parse for Annotation {
impl Parse for AnnotationElementValuePair { impl Parse for AnnotationElementValuePair {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data) -> Result<Self> {
Ok(Self { Ok(Self {
element_name_index: data.u2()?, element_name_index: data.cp()?,
element_name_name: AnnotationElementValue::parse(data)?, element_name_name: AnnotationElementValue::parse(data)?,
}) })
} }
@ -402,13 +446,13 @@ impl Parse for AnnotationElementValueValue {
let tag = data.last_u1()? as char; let tag = data.last_u1()? as char;
Ok(match tag { Ok(match tag {
'B' | 'C' | 'D' | 'F' | 'I' | 'J' | 'S' | 'Z' | 's' => { 'B' | 'C' | 'D' | 'F' | 'I' | 'J' | 'S' | 'Z' | 's' => {
Self::ConstValueIndex { index: data.u2()? } Self::ConstValueIndex { index: data.cp()? }
} }
'e' => Self::EnumConstValue { 'e' => Self::EnumConstValue {
type_name_index: data.u2()?, type_name_index: data.cp()?,
const_name_index: data.u2()?, const_name_index: data.cp()?,
}, },
'c' => Self::ClassInfoIndex { index: data.u2()? }, 'c' => Self::ClassInfoIndex { index: data.cp()? },
'@' => Self::AnnotationValue { '@' => Self::AnnotationValue {
annotation: Box::new(Annotation::parse(data)?), annotation: Box::new(Annotation::parse(data)?),
}, },
@ -436,7 +480,7 @@ impl Parse for ParameterAnnotation {
impl Parse for BootstrapMethod { impl Parse for BootstrapMethod {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data) -> Result<Self> {
Ok(Self { Ok(Self {
bootstrap_method_ref: data.u2()?, bootstrap_method_ref: data.cp()?,
num_bootstrap_arguments: data.u2()?, num_bootstrap_arguments: data.u2()?,
bootstrap_arguments: parse_vec(data, data.last_u2()?)?, bootstrap_arguments: parse_vec(data, data.last_u2()?)?,
}) })
@ -449,9 +493,33 @@ fn resolve_attributes(class: &mut ClassFile) -> Result<()> {
class class
.attributes .attributes
.iter_mut() .iter_mut()
.map(|attr| AttributeInfo::resolve_attribute(attr, pool)) .map(|attr| attr.resolve_attribute(pool))
.collect::<Result<Vec<()>>>()?; .collect::<Result<Vec<()>>>()?;
class
.methods
.iter_mut()
.map(|method| {
method
.attributes
.iter_mut()
.map(|attr| attr.resolve_attribute(pool))
.collect::<Result<Vec<()>>>()
})
.collect::<Result<Vec<_>>>()?;
class
.fields
.iter_mut()
.map(|method| {
method
.attributes
.iter_mut()
.map(|attr| attr.resolve_attribute(pool))
.collect::<Result<Vec<()>>>()
})
.collect::<Result<Vec<_>>>()?;
Ok(()) Ok(())
} }
@ -461,7 +529,7 @@ impl AttributeInfo {
let attr = std::mem::replace( let attr = std::mem::replace(
self, self,
AttributeInfo { AttributeInfo {
attribute_name_index: 0, attribute_name_index: 0.into(),
attribute_length: 0, attribute_length: 0,
inner: AttributeInfoInner::__Empty, inner: AttributeInfoInner::__Empty,
}, },
@ -475,22 +543,26 @@ impl AttributeInfo {
} => (attribute_name_index, attribute_length, attribute_content), } => (attribute_name_index, attribute_length, attribute_content),
_ => unreachable!("Attribute already resolved"), _ => unreachable!("Attribute already resolved"),
}; };
let info = match pool.get(index as usize - 1) { let info = match pool.get((*index) as usize - 1) {
Some(CpInfo::Utf8 { bytes, .. }) => bytes, Some(CpInfo {
inner: CpInfoInner::Utf8(cp_info::Utf8 { bytes, .. }),
..
}) => bytes,
Some(_) => return Err(ParseErr("Attribute name is not CpInfo::Utf8".to_string())), Some(_) => return Err(ParseErr("Attribute name is not CpInfo::Utf8".to_string())),
_ => return Err(ParseErr("Constant Pool index out of Bounds".to_string())), _ => return Err(ParseErr("Constant Pool index out of Bounds".to_string())),
}; };
let mut data = Data::new(&content); let mut data = Data::new(&content);
self.resolve_attribute_inner(index, len, info, &mut data) self.resolve_attribute_inner(index, len, info, &mut data, pool)
} }
fn resolve_attribute_inner( fn resolve_attribute_inner(
&mut self, &mut self,
attribute_name_index: u16, attribute_name_index: FromPool,
attribute_length: u32, attribute_length: u32,
name: &str, name: &str,
data: &mut Data, data: &mut Data,
pool: &[CpInfo],
) -> Result<()> { ) -> Result<()> {
let _ = std::mem::replace( let _ = std::mem::replace(
self, self,
@ -499,23 +571,37 @@ impl AttributeInfo {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::ConstantValue { inner: AttributeInfoInner::ConstantValue {
constantvalue_index: data.u2()?, constantvalue_index: data.cp()?,
},
},
"Code" => Self {
attribute_name_index,
attribute_length,
inner: AttributeInfoInner::Code {
max_stack: data.u2()?,
max_locals: data.u2()?,
code_length: data.u4()?,
code: parse_vec(data, data.last_u4()? as usize)?,
exception_table_length: data.u2()?,
exception_table: parse_vec(data, data.last_u2()?)?,
attributes_count: data.u2()?,
attributes: parse_vec(data, data.last_u2()?)?,
}, },
}, },
"Code" => {
let mut code = Self {
attribute_name_index,
attribute_length,
inner: AttributeInfoInner::Code {
max_stack: data.u2()?,
max_locals: data.u2()?,
code_length: data.u4()?,
code: parse_vec(data, data.last_u4()? as usize)?,
exception_table_length: data.u2()?,
exception_table: parse_vec(data, data.last_u2()?)?,
attributes_count: data.u2()?,
attributes: parse_vec(data, data.last_u2()?)?,
},
};
if let AttributeInfoInner::Code {
ref mut attributes, ..
} = code.inner
{
attributes
.iter_mut()
.map(|attr| attr.resolve_attribute(pool))
.collect::<Result<Vec<()>>>()?;
} else {
unreachable!()
}
code
}
"StackMapTable" => Self { "StackMapTable" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
@ -544,8 +630,8 @@ impl AttributeInfo {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::EnclosingMethod { inner: AttributeInfoInner::EnclosingMethod {
class_index: data.u2()?, class_index: data.cp()?,
method_index: data.u2()?, method_index: data.cp()?,
}, },
}, },
"Synthetic" => Self { "Synthetic" => Self {
@ -557,14 +643,14 @@ impl AttributeInfo {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::Signature { inner: AttributeInfoInner::Signature {
signature_index: data.u2()?, signature_index: data.cp()?,
}, },
}, },
"SourceFile" => Self { "SourceFile" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::SourceFile { inner: AttributeInfoInner::SourceFile {
sourcefile_index: data.u2()?, sourcefile_index: data.cp()?,
}, },
}, },
"SourceDebugExtension" => Self { "SourceDebugExtension" => Self {

View file

@ -12,6 +12,32 @@ pub type u2 = u16;
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
pub type u4 = u32; pub type u4 = u32;
///
/// An index into the constant pool of the class
#[repr(transparent)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct FromPool(u2);
impl std::ops::Deref for FromPool {
type Target = u2;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<u2> for FromPool {
fn from(n: u2) -> Self {
Self(n)
}
}
impl FromPool {
pub fn get<'a>(&self, pool: &'a [CpInfo]) -> &'a CpInfo {
&pool[self.0 as usize - 1]
}
}
/// ///
/// # Represents a .class file /// # Represents a .class file
/// ///
@ -30,9 +56,9 @@ pub struct ClassFile {
/// Mask of `ClassAccessFlag` used to denote access permissions /// Mask of `ClassAccessFlag` used to denote access permissions
pub access_flags: u2, pub access_flags: u2,
/// A valid index into the `constant_pool` table. The entry must be a `ConstantClassInfo` /// A valid index into the `constant_pool` table. The entry must be a `ConstantClassInfo`
pub this_class: u2, pub this_class: FromPool,
/// Zero or a valid index into the `constant_pool` table /// Zero or a valid index into the `constant_pool` table
pub super_class: u2, pub super_class: FromPool,
/// The number if direct superinterfaces of this class or interface type /// The number if direct superinterfaces of this class or interface type
pub interfaces_count: u2, pub interfaces_count: u2,
/// Each entry must be a valid index into the `constant_pool` table. The entry must be a `ConstantClassInfo` /// Each entry must be a valid index into the `constant_pool` table. The entry must be a `ConstantClassInfo`
@ -55,107 +81,135 @@ pub struct ClassFile {
/// May have indices back to the constant pool, with expected types /// May have indices back to the constant pool, with expected types
/// _index: A valid index into the `constant_pool` table. /// _index: A valid index into the `constant_pool` table.
#[derive(Debug, Clone, Hash, PartialEq, Eq)] #[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum CpInfo { pub struct CpInfo {
Class { pub tag: u1,
tag: u1, // 7 pub inner: CpInfoInner,
/// Entry must be `Utf8` }
name_index: u2,
}, #[derive(Debug, Clone, Hash, PartialEq, Eq)]
Fieldref { pub enum CpInfoInner {
tag: u1, // 9 Class(cp_info::Class),
/// May be a class or interface type Fieldref(cp_info::Fieldref),
class_index: u2, MethodRef(cp_info::MethodRef),
/// Entry must be `NameAndType` InterfaceMethodref(cp_info::InterfaceMethodref),
name_and_type_index: u2, String(cp_info::String),
}, Integer(cp_info::Integer),
MethodRef { Float(cp_info::Float),
tag: u1, // 10
/// Must be a class type
class_index: u2,
/// Entry must be `NameAndType`
name_and_type_index: u2,
},
InterfaceMethodref {
tag: u1, // 11
/// Must be an interface type
class_index: u2,
/// Entry must be `NameAndType`
name_and_type_index: u2,
},
String {
tag: u1, // 8
/// Entry must be `Utf8`
string_index: u2,
},
Integer {
tag: u1, // 3
// Big endian
bytes: u4,
},
Float {
tag: u1, // 4
/// IEEE 754 floating-point single format, big endian
bytes: u4,
},
/// 8 byte constants take up two spaces in the constant pool /// 8 byte constants take up two spaces in the constant pool
Long { Long(cp_info::Long),
tag: u1, // 5
/// Big endian
high_bytes: u4,
/// Big endian
low_bytes: u4,
},
/// 8 byte constants take up two spaces in the constant pool /// 8 byte constants take up two spaces in the constant pool
Double { Double(cp_info::Double),
tag: u1, // 6
/// IEEE 754 floating-point double format, big endian
high_bytes: u4,
/// IEEE 754 floating-point double format, big endian
low_bytes: u4,
},
/// Any field or method, without the class it belongs to /// Any field or method, without the class it belongs to
NameAndType { NameAndType(cp_info::NameAndType),
tag: u1, // 12 Utf8(cp_info::Utf8),
MethodHandle(cp_info::MethodHandle),
MethodType(cp_info::MethodType),
InvokeDynamic(cp_info::InvokeDynamic),
}
pub mod cp_info {
use super::*;
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Class {
/// Entry must be `Utf8` /// Entry must be `Utf8`
name_index: u2, pub name_index: FromPool,
}
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Fieldref {
/// May be a class or interface type
pub class_index: FromPool,
/// Entry must be `NameAndType`
pub name_and_type_index: FromPool,
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct MethodRef {
/// Must be a class type
pub class_index: FromPool,
/// Entry must be `NameAndType`
pub name_and_type_index: FromPool,
}
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct InterfaceMethodref {
/// Must be an interface type
pub class_index: FromPool,
/// Entry must be `NameAndType`
pub name_and_type_index: FromPool,
}
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct String {
/// Entry must be `Utf8` /// Entry must be `Utf8`
descriptor_index: u2, pub string_index: FromPool,
}, }
Utf8 { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
tag: u1, // 1 pub struct Integer {
// Big endian
pub bytes: u4,
}
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Float {
/// IEEE 754 floating-point single format, big endian
pub bytes: u4,
}
/// 8 byte constants take up two spaces in the constant pool
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Long {
/// Big endian
pub high_bytes: u4,
/// Big endian
pub low_bytes: u4,
}
/// 8 byte constants take up two spaces in the constant pool
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Double {
/// IEEE 754 floating-point double format, big endian
pub high_bytes: u4,
/// IEEE 754 floating-point double format, big endian
pub low_bytes: u4,
}
/// Any field or method, without the class it belongs to
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct NameAndType {
/// Entry must be `Utf8`
pub name_index: FromPool,
/// Entry must be `Utf8`
pub descriptor_index: FromPool,
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Utf8 {
/// The length of the String. Not null-terminated. /// The length of the String. Not null-terminated.
length: u2, pub length: u2,
/// Contains modified UTF-8 /// Contains modified UTF-8
bytes: String, pub bytes: std::string::String,
}, }
MethodHandle { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
tag: u1, // 15 pub struct MethodHandle {
/// The kind of method handle (0-9) /// The kind of method handle (0-9)
reference_kind: u1, pub reference_kind: u1,
/// If the kind is 1-4, the entry must be `FieldRef`. If the kind is 5-8, the entry must be `MethodRef` /// If the kind is 1-4, the entry must be `FieldRef`. If the kind is 5-8, the entry must be `MethodRef`
/// If the kind is 9, the entry must be `InterfaceMethodRef` /// If the kind is 9, the entry must be `InterfaceMethodRef`
reference_index: u2, pub reference_index: FromPool,
}, }
MethodType { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
tag: u1, // 16 pub struct MethodType {
/// Entry must be `Utf8` /// Entry must be `Utf8`
descriptor_index: u2, pub descriptor_index: FromPool,
}, }
InvokeDynamic { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
tag: u1, // 18 pub struct InvokeDynamic {
/// Must be a valid index into the `bootstrap_methods` array of the bootstrap method table of this class fiel /// Must be a valid index into the `bootstrap_methods` array of the bootstrap method table of this class field
bootstrap_method_attr_index: u2, pub bootstrap_method_attr_index: u2,
/// Entry must `NameAndType` /// Entry must `NameAndType`
name_and_type_index: u2, pub name_and_type_index: FromPool,
}, }
} }
/// Information about a field /// Information about a field
#[derive(Debug, Clone, Hash, PartialEq, Eq)] #[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct FieldInfo { pub struct FieldInfo {
pub access_flags: u2, pub access_flags: u2,
pub name_index: u2, pub name_index: FromPool,
pub descriptor_index: u2, pub descriptor_index: FromPool,
pub attributes_count: u2, pub attributes_count: u2,
pub attributes: Vec<AttributeInfo>, pub attributes: Vec<AttributeInfo>,
} }
@ -166,9 +220,9 @@ pub struct MethodInfo {
/// Mask of `MethodAccessFlag` used to denote access permissions /// Mask of `MethodAccessFlag` used to denote access permissions
pub access_flags: u2, pub access_flags: u2,
/// Index to the `constant_pool` of the method name, must be `Utf8` /// Index to the `constant_pool` of the method name, must be `Utf8`
pub name_index: u2, pub name_index: FromPool,
/// Index to the `constant_pool` of the method descriptor, must be `Utf8` /// Index to the `constant_pool` of the method descriptor, must be `Utf8`
pub descriptor_index: u2, pub descriptor_index: FromPool,
/// The amount of attributes for this method /// The amount of attributes for this method
pub attributes_count: u2, pub attributes_count: u2,
/// The attributes for this method /// The attributes for this method
@ -183,7 +237,7 @@ pub struct MethodInfo {
/// _index: Index to the `constant_pool` table of any type /// _index: Index to the `constant_pool` table of any type
#[derive(Debug, Clone, Hash, PartialEq, Eq)] #[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct AttributeInfo { pub struct AttributeInfo {
pub attribute_name_index: u2, pub attribute_name_index: FromPool,
pub attribute_length: u4, pub attribute_length: u4,
/// The attribute value /// The attribute value
pub inner: AttributeInfoInner, pub inner: AttributeInfoInner,
@ -200,7 +254,7 @@ pub enum AttributeInfoInner {
/// Only on fields, the constant value of that field /// Only on fields, the constant value of that field
ConstantValue { ConstantValue {
/// Must be of type `Long`/`Float`/`Double`/`Integer`/`String` /// Must be of type `Long`/`Float`/`Double`/`Integer`/`String`
constantvalue_index: u2, constantvalue_index: FromPool,
}, },
/// Only on methods, contains JVM instructions and auxiliary information for a single method /// Only on methods, contains JVM instructions and auxiliary information for a single method
Code { Code {
@ -240,9 +294,9 @@ pub enum AttributeInfoInner {
/// Only on a `ClassFile`, required if it is local or anonymous /// Only on a `ClassFile`, required if it is local or anonymous
EnclosingMethod { EnclosingMethod {
/// Must be a `Class` constant, the innermost enclosing class /// Must be a `Class` constant, the innermost enclosing class
class_index: u2, class_index: FromPool,
/// Must be zero or `NameAndType` /// Must be zero or `NameAndType`
method_index: u2, method_index: FromPool,
}, },
/// Can be on `ClassFile`, `FieldInfo`,or `MethodInfo`. /// Can be on `ClassFile`, `FieldInfo`,or `MethodInfo`.
/// Every generated class has to have this attribute or the `Synthetic` Accessor modifier /// Every generated class has to have this attribute or the `Synthetic` Accessor modifier
@ -250,12 +304,12 @@ pub enum AttributeInfoInner {
/// Can be on `ClassFile`, `FieldInfo`,or `MethodInfo`. Records generic signature information /// Can be on `ClassFile`, `FieldInfo`,or `MethodInfo`. Records generic signature information
Signature { Signature {
/// Must be `Utf8`, and a Class/Method/Field signature /// Must be `Utf8`, and a Class/Method/Field signature
signature_index: u2, signature_index: FromPool,
}, },
/// Only on a `ClassFile` /// Only on a `ClassFile`
SourceFile { SourceFile {
/// Must be `Utf8`, the name of the source filed /// Must be `Utf8`, the name of the source filed
sourcefile_index: u2, sourcefile_index: FromPool,
}, },
/// Only on a `ClassFile` /// Only on a `ClassFile`
SourceDebugExtension { SourceDebugExtension {
@ -414,11 +468,11 @@ pub enum VerificationTypeInfo {
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub struct AttributeInnerClass { pub struct AttributeInnerClass {
/// Must be a `Class` /// Must be a `Class`
pub inner_class_info_index: u2, pub inner_class_info_index: FromPool,
/// Must be 0 or a `Class` /// Must be 0 or a `Class`
pub outer_class_info_index: u2, pub outer_class_info_index: FromPool,
/// Must be 0 or `Utf8` /// Must be 0 or `Utf8`
pub inner_class_name_index: u2, pub inner_class_name_index: FromPool,
/// Must be a mask of `InnerClassAccessFlags` /// Must be a mask of `InnerClassAccessFlags`
pub inner_class_access_flags: u2, pub inner_class_access_flags: u2,
} }
@ -440,9 +494,9 @@ pub struct AttributeLocalVariableTable {
/// The local variable must have a value between `start_pc` and `start_pc + length` /// The local variable must have a value between `start_pc` and `start_pc + length`
pub length: u2, pub length: u2,
/// Must be `Utf8` /// Must be `Utf8`
pub name_index: u2, pub name_index: FromPool,
/// Must be `Utf8`, field descriptor or field signature encoding the type /// Must be `Utf8`, field descriptor or field signature encoding the type
pub descriptor_or_signature_index: u2, pub descriptor_or_signature_index: FromPool,
/// The variable must be at `index` in the local variable array /// The variable must be at `index` in the local variable array
pub index: u2, pub index: u2,
} }
@ -451,7 +505,7 @@ pub struct AttributeLocalVariableTable {
#[derive(Debug, Clone, Hash, PartialEq, Eq)] #[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Annotation { pub struct Annotation {
/// Must be `Utf8` /// Must be `Utf8`
pub type_index: u2, pub type_index: FromPool,
pub num_element_value_pairs: u2, pub num_element_value_pairs: u2,
pub element_value_pairs: Vec<AnnotationElementValuePair>, pub element_value_pairs: Vec<AnnotationElementValuePair>,
} }
@ -462,7 +516,7 @@ pub struct Annotation {
#[derive(Debug, Clone, Hash, PartialEq, Eq)] #[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct AnnotationElementValuePair { pub struct AnnotationElementValuePair {
/// Must be `Utf8` /// Must be `Utf8`
pub element_name_index: u2, pub element_name_index: FromPool,
pub element_name_name: AnnotationElementValue, pub element_name_name: AnnotationElementValue,
} }
@ -480,19 +534,19 @@ pub enum AnnotationElementValueValue {
/// If the tag is B, C, D, F, I, J, S, Z, or s. /// If the tag is B, C, D, F, I, J, S, Z, or s.
ConstValueIndex { ConstValueIndex {
/// Must be the matching constant pool entry /// Must be the matching constant pool entry
index: u2, index: FromPool,
}, },
/// If the tag is e /// If the tag is e
EnumConstValue { EnumConstValue {
/// Must be `Utf8` /// Must be `Utf8`
type_name_index: u2, type_name_index: FromPool,
/// Must be `Utf8` /// Must be `Utf8`
const_name_index: u2, const_name_index: FromPool,
}, },
/// If the tag is c /// If the tag is c
ClassInfoIndex { ClassInfoIndex {
/// Must be `Utf8`, for example Ljava/lang/Object; for Object /// Must be `Utf8`, for example Ljava/lang/Object; for Object
index: u2, index: FromPool,
}, },
/// If the tag is @ /// If the tag is @
AnnotationValue { AnnotationValue {
@ -517,10 +571,10 @@ pub struct ParameterAnnotation {
#[derive(Debug, Clone, Hash, PartialEq, Eq)] #[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct BootstrapMethod { pub struct BootstrapMethod {
/// Must be a `MethodHandle` /// Must be a `MethodHandle`
pub bootstrap_method_ref: u2, pub bootstrap_method_ref: FromPool,
pub num_bootstrap_arguments: u2, pub num_bootstrap_arguments: u2,
/// Each argument is a cpool entry. The constants must be `String, Class, Integer, Long, Float, Double, MethodHandle, or MethodType` /// Each argument is a cpool entry. The constants must be `String, Class, Integer, Long, Float, Double, MethodHandle, or MethodType`
pub bootstrap_arguments: Vec<u2>, pub bootstrap_arguments: Vec<FromPool>,
} }
/////// Access Flags /////// Access Flags

View file

@ -47,77 +47,101 @@ fn parse_empty_class() {
assert_eq!( assert_eq!(
parsed.constant_pool, parsed.constant_pool,
vec![ vec![
CpInfo::MethodRef { CpInfo {
tag: 0x0a, tag: 0x0a,
class_index: 2, inner: CpInfoInner::MethodRef(cp_info::MethodRef {
name_and_type_index: 3 class_index: 2.into(),
name_and_type_index: 3.into(),
})
}, },
CpInfo::Class { CpInfo {
tag: 7, tag: 7,
name_index: 4 inner: CpInfoInner::Class(cp_info::Class {
name_index: 4.into(),
})
}, },
CpInfo::NameAndType { CpInfo {
tag: 0xc, tag: 0xc,
name_index: 5, inner: CpInfoInner::NameAndType(cp_info::NameAndType {
descriptor_index: 6 name_index: 5.into(),
descriptor_index: 6.into(),
})
}, },
CpInfo::Utf8 { CpInfo {
tag: 1, tag: 1,
length: 0x10, inner: CpInfoInner::Utf8(cp_info::Utf8 {
bytes: "java/lang/Object".to_string() length: 0x10,
bytes: "java/lang/Object".to_string()
})
}, },
CpInfo::Utf8 { CpInfo {
tag: 1, tag: 1,
length: 6, inner: CpInfoInner::Utf8(cp_info::Utf8 {
bytes: "<init>".to_string() length: 6,
bytes: "<init>".to_string()
})
}, },
CpInfo::Utf8 { CpInfo {
tag: 1, tag: 1,
length: 3, inner: CpInfoInner::Utf8(cp_info::Utf8 {
bytes: "()V".to_string() length: 3,
bytes: "()V".to_string()
})
}, },
CpInfo::Class { CpInfo {
tag: 7, tag: 7,
name_index: 8 inner: CpInfoInner::Class(cp_info::Class {
name_index: 8.into(),
})
}, },
CpInfo::Utf8 { CpInfo {
tag: 1, tag: 1,
length: 4, inner: CpInfoInner::Utf8(cp_info::Utf8 {
bytes: "Test".to_string() length: 4,
bytes: "Test".to_string()
})
}, },
CpInfo::Utf8 { CpInfo {
tag: 1, tag: 1,
length: 4, inner: CpInfoInner::Utf8(cp_info::Utf8 {
bytes: "Code".to_string() length: 4,
bytes: "Code".to_string()
})
}, },
CpInfo::Utf8 { CpInfo {
tag: 1, tag: 1,
length: 15, inner: CpInfoInner::Utf8(cp_info::Utf8 {
bytes: "LineNumberTable".to_string() length: 15,
bytes: "LineNumberTable".to_string()
})
}, },
CpInfo::Utf8 { CpInfo {
tag: 1, tag: 1,
length: 10, inner: CpInfoInner::Utf8(cp_info::Utf8 {
bytes: "SourceFile".to_string() length: 10,
bytes: "SourceFile".to_string()
})
}, },
CpInfo::Utf8 { CpInfo {
tag: 1, tag: 1,
length: 9, inner: CpInfoInner::Utf8(cp_info::Utf8 {
bytes: "Test.java".to_string() length: 9,
bytes: "Test.java".to_string()
})
} }
] ]
); );
assert_eq!(parsed.access_flags, 0x0021); assert_eq!(parsed.access_flags, 0x0021);
assert_eq!(parsed.this_class, 7); assert_eq!(parsed.this_class, 7.into());
assert_eq!(parsed.super_class, 2); assert_eq!(parsed.super_class, 2.into());
assert_eq!(parsed.interfaces_count, 0); assert_eq!(parsed.interfaces_count, 0);
assert_eq!(parsed.interfaces, vec![]); assert_eq!(parsed.interfaces, vec![]);
assert_eq!(parsed.fields_count, 0); assert_eq!(parsed.fields_count, 0);
assert_eq!(parsed.fields, vec![]); assert_eq!(parsed.fields, vec![]);
assert_eq!(parsed.method_count, 1); assert_eq!(parsed.method_count, 1);
assert_eq!(parsed.methods[0].access_flags, 1); assert_eq!(parsed.methods[0].access_flags, 1);
assert_eq!(parsed.methods[0].name_index, 5); assert_eq!(parsed.methods[0].name_index, 5.into());
assert_eq!(parsed.methods[0].descriptor_index, 6); assert_eq!(parsed.methods[0].descriptor_index, 6.into());
assert_eq!(parsed.methods[0].attributes_count, 1); assert_eq!(parsed.methods[0].attributes_count, 1);
//assert_eq!(parsed.methods[0].attributes[0].attribute_name_index, 9); //assert_eq!(parsed.methods[0].attributes[0].attribute_name_index, 9);
//assert_eq!(parsed.methods[0].attributes[0].attribute_length, 0x1d); //assert_eq!(parsed.methods[0].attributes[0].attribute_length, 0x1d);