mirror of
https://github.com/Noratrieb/coldsquare.git
synced 2026-01-14 16:35:10 +01:00
tests and fixes
This commit is contained in:
parent
ef797d6fa2
commit
5d435a208c
10 changed files with 345 additions and 135 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -3,5 +3,4 @@
|
||||||
|
|
||||||
/target
|
/target
|
||||||
|
|
||||||
*.class
|
testing
|
||||||
*.java
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
mod model;
|
#[allow(dead_code)]
|
||||||
|
mod model;
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,6 @@ use crate::parse::{ClassFile, ParseErr};
|
||||||
mod execute;
|
mod execute;
|
||||||
mod parse;
|
mod parse;
|
||||||
|
|
||||||
pub fn parse_class_file(file: Vec<u8>) -> Result<ClassFile, ParseErr> {
|
pub fn parse_class_file(file: &[u8]) -> Result<ClassFile, ParseErr> {
|
||||||
parse::parse_class_file(file)
|
parse::parse_class_file(file)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ fn main() {
|
||||||
let file = "Test.class";
|
let file = "Test.class";
|
||||||
let file = std::fs::read(file).unwrap();
|
let file = std::fs::read(file).unwrap();
|
||||||
|
|
||||||
let class_file = parse_class_file(file).unwrap();
|
let class_file = parse_class_file(&file).unwrap();
|
||||||
|
|
||||||
println!("{:?}", class_file);
|
println!("{:?}", class_file);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
164
src/parse/mod.rs
164
src/parse/mod.rs
|
|
@ -1,29 +1,26 @@
|
||||||
mod model;
|
mod model;
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test;
|
||||||
|
|
||||||
pub use model::*;
|
pub use model::*;
|
||||||
use std::path::Prefix::Verbatim;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ParseErr(String);
|
pub struct ParseErr(String);
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, ParseErr>;
|
pub type Result<T> = std::result::Result<T, ParseErr>;
|
||||||
|
|
||||||
struct Data {
|
#[derive(Copy, Clone)]
|
||||||
data: Vec<u1>,
|
struct Data<'a> {
|
||||||
|
data: &'a [u1],
|
||||||
pointer: usize,
|
pointer: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_class_file(data: Vec<u1>) -> Result<ClassFile> {
|
pub fn parse_class_file(data: &[u1]) -> Result<ClassFile> {
|
||||||
let mut data = Data { data, pointer: 0 };
|
let data = Data { data, pointer: 0 };
|
||||||
ClassFile::parse(&mut data)
|
ClassFile::parse(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Vec<u8>> for Data {
|
impl<'a> Data<'a> {
|
||||||
fn from(data: Vec<u1>) -> Self {
|
|
||||||
Self { data, pointer: 0 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Data {
|
|
||||||
fn u1(&mut self) -> Result<u1> {
|
fn u1(&mut self) -> Result<u1> {
|
||||||
let item = self.data.get(self.pointer).cloned();
|
let item = self.data.get(self.pointer).cloned();
|
||||||
self.pointer += 1;
|
self.pointer += 1;
|
||||||
|
|
@ -69,65 +66,55 @@ impl Data {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Parse {
|
trait Parse {
|
||||||
fn parse(data: &mut Data) -> Result<Self>
|
fn parse(data: Data) -> Result<Self>
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ParseVec<T> {
|
fn parse_vec<T: Parse, S: Into<usize>>(data: Data, len: S) -> Result<Vec<T>> {
|
||||||
fn parse_vec(data: &mut Data, len: usize) -> Result<Self>
|
let len = len.into();
|
||||||
where
|
let mut vec = Vec::with_capacity(len);
|
||||||
Self: Sized;
|
for _ in 0..len {
|
||||||
}
|
vec.push(T::parse(data)?);
|
||||||
|
|
||||||
impl<T: Parse> ParseVec<T> for Vec<T> {
|
|
||||||
fn parse_vec(data: &mut Data, len: usize) -> Result<Self> {
|
|
||||||
let mut vec = Vec::with_capacity(len);
|
|
||||||
for _ in 0..len {
|
|
||||||
vec.push(T::parse(data)?);
|
|
||||||
}
|
|
||||||
Ok(vec)
|
|
||||||
}
|
}
|
||||||
|
Ok(vec)
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! parse_primitive {
|
macro_rules! parse_primitive {
|
||||||
($value:ident) => {
|
($($value:ident),*) => {
|
||||||
impl Parse for $value {
|
$(impl Parse for $value {
|
||||||
fn parse(data: &mut Data) -> Result<Self>
|
fn parse(mut data: Data) -> Result<Self>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
data.$value()
|
data.$value()
|
||||||
}
|
}
|
||||||
}
|
})*
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_primitive!(u1);
|
parse_primitive!(u1, u2, u4);
|
||||||
parse_primitive!(u2);
|
|
||||||
parse_primitive!(u4);
|
|
||||||
|
|
||||||
impl Parse for ClassFile {
|
impl Parse for ClassFile {
|
||||||
fn parse(data: &mut Data) -> Result<Self> {
|
fn parse(mut data: Data) -> Result<Self> {
|
||||||
let magic = data.u4()?;
|
let magic = data.u4()?;
|
||||||
assert_eq!(magic, 0xCAFEBABE);
|
assert_eq!(magic, 0xCAFEBABE);
|
||||||
let minor_version = data.u2()?;
|
let minor_version = data.u2()?;
|
||||||
let major_version = data.u2()?;
|
let major_version = data.u2()?;
|
||||||
let constant_pool_count = data.u2()?;
|
let constant_pool_count = data.u2()?;
|
||||||
let constant_pool = Vec::parse_vec(data, constant_pool_count as usize)?;
|
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.u2()?;
|
||||||
let super_class = data.u2()?;
|
let super_class = data.u2()?;
|
||||||
let interfaces_count = data.u2()?;
|
let interfaces_count = data.u2()?;
|
||||||
let interfaces = Vec::parse_vec(data, interfaces_count as usize)?;
|
let interfaces = parse_vec(data, interfaces_count)?;
|
||||||
let fields_count = data.u2()?;
|
let fields_count = data.u2()?;
|
||||||
let fields = Vec::parse_vec(data, fields_count as usize)?;
|
let fields = parse_vec(data, fields_count)?;
|
||||||
let method_count = data.u2()?;
|
let method_count = data.u2()?;
|
||||||
let methods = Vec::parse_vec(data, method_count as usize)?;
|
let methods = parse_vec(data, method_count)?;
|
||||||
let attributes_count = data.u2()?;
|
let attributes_count = data.u2()?;
|
||||||
let attributes = Vec::parse_vec(data, attributes_count as usize)?;
|
let attributes = parse_vec(data, attributes_count)?;
|
||||||
println!("los");
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
magic,
|
magic,
|
||||||
minor_version,
|
minor_version,
|
||||||
|
|
@ -150,7 +137,7 @@ impl Parse for ClassFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for CpInfo {
|
impl Parse for CpInfo {
|
||||||
fn parse(data: &mut Data) -> Result<Self> {
|
fn parse(mut data: Data) -> Result<Self> {
|
||||||
let tag = data.u1()?;
|
let tag = data.u1()?;
|
||||||
|
|
||||||
Ok(match tag {
|
Ok(match tag {
|
||||||
|
|
@ -163,7 +150,7 @@ impl Parse for CpInfo {
|
||||||
class_index: data.u2()?,
|
class_index: data.u2()?,
|
||||||
name_and_type_index: data.u2()?,
|
name_and_type_index: data.u2()?,
|
||||||
},
|
},
|
||||||
10 => Self::Methodref {
|
10 => Self::MethodRef {
|
||||||
tag,
|
tag,
|
||||||
class_index: data.u2()?,
|
class_index: data.u2()?,
|
||||||
name_and_type_index: data.u2()?,
|
name_and_type_index: data.u2()?,
|
||||||
|
|
@ -203,7 +190,7 @@ impl Parse for CpInfo {
|
||||||
1 => Self::Utf8 {
|
1 => Self::Utf8 {
|
||||||
tag,
|
tag,
|
||||||
length: data.u2()?,
|
length: data.u2()?,
|
||||||
bytes: Vec::parse_vec(data, data.last_u2()? as usize)?,
|
bytes: parse_vec(data, data.last_u2()?)?,
|
||||||
},
|
},
|
||||||
15 => Self::MethodHandle {
|
15 => Self::MethodHandle {
|
||||||
tag,
|
tag,
|
||||||
|
|
@ -225,41 +212,41 @@ impl Parse for CpInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for FieldInfo {
|
impl Parse for FieldInfo {
|
||||||
fn parse(data: &mut Data) -> Result<Self> {
|
fn parse(mut data: Data) -> Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
access_flags: data.u2()?,
|
access_flags: data.u2()?,
|
||||||
name_index: data.u2()?,
|
name_index: data.u2()?,
|
||||||
descriptor_index: data.u2()?,
|
descriptor_index: data.u2()?,
|
||||||
attributes_count: data.u2()?,
|
attributes_count: data.u2()?,
|
||||||
attributes: Vec::parse_vec(data, data.last_u2()? as usize)?,
|
attributes: parse_vec(data, data.last_u2()?)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for MethodInfo {
|
impl Parse for MethodInfo {
|
||||||
fn parse(data: &mut Data) -> Result<Self> {
|
fn parse(mut data: Data) -> Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
access_flags: data.u2()?,
|
access_flags: data.u2()?,
|
||||||
name_index: data.u2()?,
|
name_index: data.u2()?,
|
||||||
descriptor_index: data.u2()?,
|
descriptor_index: data.u2()?,
|
||||||
attributes_count: data.u2()?,
|
attributes_count: data.u2()?,
|
||||||
attributes: Vec::parse_vec(data, data.last_u2()? as usize)?,
|
attributes: parse_vec(data, data.last_u2()?)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for Attribute {
|
impl Parse for Attribute {
|
||||||
fn parse(data: &mut Data) -> Result<Self> {
|
fn parse(mut data: Data) -> Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
attribute_name_index: data.u2()?,
|
attribute_name_index: data.u2()?,
|
||||||
attribute_length: data.u4()?,
|
attribute_length: data.u4()?,
|
||||||
attribute_content: Vec::parse_vec(data, data.last_u4()? as usize)?,
|
attribute_content: parse_vec(data, data.last_u4()? as usize)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for AttributeCodeException {
|
impl Parse for AttributeCodeException {
|
||||||
fn parse(data: &mut Data) -> Result<Self> {
|
fn parse(data: Data) -> Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
start_pc: data.last_u2()?,
|
start_pc: data.last_u2()?,
|
||||||
end_pc: data.last_u2()?,
|
end_pc: data.last_u2()?,
|
||||||
|
|
@ -270,7 +257,7 @@ impl Parse for AttributeCodeException {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for StackMapFrame {
|
impl Parse for StackMapFrame {
|
||||||
fn parse(data: &mut Data) -> Result<Self> {
|
fn parse(mut data: Data) -> Result<Self> {
|
||||||
let frame_type = data.u1()?;
|
let frame_type = data.u1()?;
|
||||||
|
|
||||||
Ok(match frame_type {
|
Ok(match frame_type {
|
||||||
|
|
@ -295,15 +282,15 @@ impl Parse for StackMapFrame {
|
||||||
252..=254 => Self::AppendFrame {
|
252..=254 => Self::AppendFrame {
|
||||||
frame_type,
|
frame_type,
|
||||||
offset_delta: data.u2()?,
|
offset_delta: data.u2()?,
|
||||||
locals: Vec::parse_vec(data, data.last_u2()? as usize)?,
|
locals: parse_vec(data, data.last_u2()?)?,
|
||||||
},
|
},
|
||||||
255 => Self::FullFrame {
|
255 => Self::FullFrame {
|
||||||
frame_type,
|
frame_type,
|
||||||
offset_delta: data.u2()?,
|
offset_delta: data.u2()?,
|
||||||
number_of_locals: data.u2()?,
|
number_of_locals: data.u2()?,
|
||||||
locals: Vec::parse_vec(data, data.last_u2()? as usize)?,
|
locals: parse_vec(data, data.last_u2()?)?,
|
||||||
number_of_stack_items: data.u2()?,
|
number_of_stack_items: data.u2()?,
|
||||||
stack: Vec::parse_vec(data, data.last_u2()? as usize)?,
|
stack: parse_vec(data, data.last_u2()?)?,
|
||||||
},
|
},
|
||||||
_ => Err(ParseErr(format!(
|
_ => Err(ParseErr(format!(
|
||||||
"Invalid StackMapFrame type: {}",
|
"Invalid StackMapFrame type: {}",
|
||||||
|
|
@ -314,7 +301,7 @@ impl Parse for StackMapFrame {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for VerificationTypeInfo {
|
impl Parse for VerificationTypeInfo {
|
||||||
fn parse(data: &mut Data) -> Result<Self> {
|
fn parse(mut data: Data) -> Result<Self> {
|
||||||
let tag = data.u1()?;
|
let tag = data.u1()?;
|
||||||
Ok(match tag {
|
Ok(match tag {
|
||||||
0 => Self::Top { tag },
|
0 => Self::Top { tag },
|
||||||
|
|
@ -341,7 +328,7 @@ impl Parse for VerificationTypeInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for AttributeInnerClass {
|
impl Parse for AttributeInnerClass {
|
||||||
fn parse(data: &mut Data) -> Result<Self> {
|
fn parse(mut data: Data) -> Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
inner_class_info_index: data.u2()?,
|
inner_class_info_index: data.u2()?,
|
||||||
outer_class_info_index: data.u2()?,
|
outer_class_info_index: data.u2()?,
|
||||||
|
|
@ -352,7 +339,7 @@ impl Parse for AttributeInnerClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for AttributeLineNumber {
|
impl Parse for AttributeLineNumber {
|
||||||
fn parse(data: &mut Data) -> Result<Self> {
|
fn parse(mut data: Data) -> Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
start_pc: data.u2()?,
|
start_pc: data.u2()?,
|
||||||
line_number: data.u2()?,
|
line_number: data.u2()?,
|
||||||
|
|
@ -361,7 +348,7 @@ impl Parse for AttributeLineNumber {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for AttributeLocalVariableTable {
|
impl Parse for AttributeLocalVariableTable {
|
||||||
fn parse(data: &mut Data) -> Result<Self> {
|
fn parse(mut data: Data) -> Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
start_pc: data.u2()?,
|
start_pc: data.u2()?,
|
||||||
length: data.u2()?,
|
length: data.u2()?,
|
||||||
|
|
@ -373,17 +360,17 @@ impl Parse for AttributeLocalVariableTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for Annotation {
|
impl Parse for Annotation {
|
||||||
fn parse(data: &mut Data) -> Result<Self> {
|
fn parse(mut data: Data) -> Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
type_index: data.u2()?,
|
type_index: data.u2()?,
|
||||||
num_element_value_pairs: data.u2()?,
|
num_element_value_pairs: data.u2()?,
|
||||||
element_value_pairs: Vec::parse_vec(data, data.last_u2()? as usize)?,
|
element_value_pairs: parse_vec(data, data.last_u2()?)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for AnnotationElementValuePair {
|
impl Parse for AnnotationElementValuePair {
|
||||||
fn parse(data: &mut Data) -> Result<Self> {
|
fn parse(mut data: Data) -> Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
element_name_index: data.u2()?,
|
element_name_index: data.u2()?,
|
||||||
element_name_name: AnnotationElementValue::parse(data)?,
|
element_name_name: AnnotationElementValue::parse(data)?,
|
||||||
|
|
@ -392,7 +379,7 @@ impl Parse for AnnotationElementValuePair {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for AnnotationElementValue {
|
impl Parse for AnnotationElementValue {
|
||||||
fn parse(data: &mut Data) -> Result<Self> {
|
fn parse(mut data: Data) -> Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
tag: data.u1()?,
|
tag: data.u1()?,
|
||||||
value: AnnotationElementValueValue::parse(data)?,
|
value: AnnotationElementValueValue::parse(data)?,
|
||||||
|
|
@ -401,7 +388,7 @@ impl Parse for AnnotationElementValue {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for AnnotationElementValueValue {
|
impl Parse for AnnotationElementValueValue {
|
||||||
fn parse(data: &mut Data) -> Result<Self> {
|
fn parse(mut data: Data) -> Result<Self> {
|
||||||
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' => {
|
||||||
|
|
@ -417,7 +404,7 @@ impl Parse for AnnotationElementValueValue {
|
||||||
},
|
},
|
||||||
'[' => Self::ArrayValue {
|
'[' => Self::ArrayValue {
|
||||||
num_values: data.u2()?,
|
num_values: data.u2()?,
|
||||||
values: Vec::parse_vec(data, data.last_u2()? as usize)?,
|
values: parse_vec(data, data.last_u2()?)?,
|
||||||
},
|
},
|
||||||
_ => Err(ParseErr(format!(
|
_ => Err(ParseErr(format!(
|
||||||
"Invalid AnnotationElementValueValue tag: {}",
|
"Invalid AnnotationElementValueValue tag: {}",
|
||||||
|
|
@ -428,57 +415,20 @@ impl Parse for AnnotationElementValueValue {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for ParameterAnnotation {
|
impl Parse for ParameterAnnotation {
|
||||||
fn parse(data: &mut Data) -> Result<Self> {
|
fn parse(mut data: Data) -> Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
num_annotations: data.u2()?,
|
num_annotations: data.u2()?,
|
||||||
annotations: Vec::parse_vec(data, data.last_u2()? as usize)?,
|
annotations: parse_vec(data, data.last_u2()?)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for BootstrapMethod {
|
impl Parse for BootstrapMethod {
|
||||||
fn parse(data: &mut Data) -> Result<Self> {
|
fn parse(mut data: Data) -> Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
bootstrap_method_ref: data.u2()?,
|
bootstrap_method_ref: data.u2()?,
|
||||||
num_bootstrap_arguments: data.u2()?,
|
num_bootstrap_arguments: data.u2()?,
|
||||||
bootstrap_arguments: Vec::parse_vec(data, data.last_u2()? as usize)?,
|
bootstrap_arguments: parse_vec(data, data.last_u2()?)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use crate::parse::Data;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn data_u1() {
|
|
||||||
let mut data = Data {
|
|
||||||
data: vec![0xff, 0x00],
|
|
||||||
pointer: 0,
|
|
||||||
};
|
|
||||||
assert_eq!(data.u1().unwrap(), 0xff);
|
|
||||||
assert_eq!(data.u1().unwrap(), 0x00);
|
|
||||||
assert_eq!(data.last_u1().unwrap(), 0x00);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn data_u2() {
|
|
||||||
let mut data = Data {
|
|
||||||
data: vec![0xff, 0x33, 0x11, 0x00],
|
|
||||||
pointer: 0,
|
|
||||||
};
|
|
||||||
assert_eq!(data.u2().unwrap(), 0xff33);
|
|
||||||
assert_eq!(data.u2().unwrap(), 0x1100);
|
|
||||||
assert_eq!(data.last_u2().unwrap(), 0x1100);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn data_u4() {
|
|
||||||
let mut data = Data {
|
|
||||||
data: vec![0xff, 0x33, 0x11, 0x00],
|
|
||||||
pointer: 0,
|
|
||||||
};
|
|
||||||
assert_eq!(data.u4().unwrap(), 0xff331100);
|
|
||||||
assert_eq!(data.last_u4().unwrap(), 0xff331100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
//! The models for a .class file
|
//! The models for a .class file
|
||||||
//!
|
//!
|
||||||
//! [The .class specs](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html)
|
//! [The .class specs](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html)
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
// The types used in the specs
|
// The types used in the specs
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
|
|
@ -14,7 +15,7 @@ pub type u4 = u32;
|
||||||
///
|
///
|
||||||
/// # Represents a .class file
|
/// # Represents a .class file
|
||||||
///
|
///
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||||
pub struct ClassFile {
|
pub struct ClassFile {
|
||||||
/// Magic number identifying the format (= 0xCAFEBABE)
|
/// Magic number identifying the format (= 0xCAFEBABE)
|
||||||
pub magic: u4,
|
pub magic: u4,
|
||||||
|
|
@ -53,7 +54,7 @@ pub struct ClassFile {
|
||||||
/// A constant from the constant pool
|
/// A constant from the constant pool
|
||||||
/// 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)]
|
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||||
pub enum CpInfo {
|
pub enum CpInfo {
|
||||||
Class {
|
Class {
|
||||||
tag: u1, // 7
|
tag: u1, // 7
|
||||||
|
|
@ -67,7 +68,7 @@ pub enum CpInfo {
|
||||||
/// Entry must be `NameAndType`
|
/// Entry must be `NameAndType`
|
||||||
name_and_type_index: u2,
|
name_and_type_index: u2,
|
||||||
},
|
},
|
||||||
Methodref {
|
MethodRef {
|
||||||
tag: u1, // 10
|
tag: u1, // 10
|
||||||
/// Must be a class type
|
/// Must be a class type
|
||||||
class_index: u2,
|
class_index: u2,
|
||||||
|
|
@ -150,7 +151,7 @@ pub enum CpInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information about a field
|
/// Information about a field
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[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: u2,
|
||||||
|
|
@ -160,7 +161,7 @@ pub struct FieldInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information about a method
|
/// Information about a method
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||||
pub struct MethodInfo {
|
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,
|
||||||
|
|
@ -175,7 +176,7 @@ pub struct MethodInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See `AttributeInfo`
|
/// See `AttributeInfo`
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||||
pub struct Attribute {
|
pub struct Attribute {
|
||||||
pub attribute_name_index: u2,
|
pub attribute_name_index: u2,
|
||||||
pub attribute_length: u4,
|
pub attribute_length: u4,
|
||||||
|
|
@ -188,7 +189,7 @@ pub struct Attribute {
|
||||||
/// `attribute_length`: The length of the subsequent bytes, does not include the first 6
|
/// `attribute_length`: The length of the subsequent bytes, does not include the first 6
|
||||||
///
|
///
|
||||||
/// _index: Index to the `constant_pool` table of any type
|
/// _index: Index to the `constant_pool` table of any type
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||||
#[allow(dead_code)] // todo yeah lol
|
#[allow(dead_code)] // todo yeah lol
|
||||||
pub enum AttributeInfo {
|
pub enum AttributeInfo {
|
||||||
/// Only on fields, the constant value of that field
|
/// Only on fields, the constant value of that field
|
||||||
|
|
@ -350,7 +351,7 @@ pub enum AttributeInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An exception handler in the JVM bytecode array
|
/// An exception handler in the JVM bytecode array
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
pub struct AttributeCodeException {
|
pub struct AttributeCodeException {
|
||||||
/// The ranges in the code in which the handler is active. Must be a valid index into the code array.
|
/// The ranges in the code in which the handler is active. Must be a valid index into the code array.
|
||||||
/// The `start_pc` is inclusive
|
/// The `start_pc` is inclusive
|
||||||
|
|
@ -367,7 +368,7 @@ pub struct AttributeCodeException {
|
||||||
|
|
||||||
/// Specifies the type state at a particular bytecode offset
|
/// Specifies the type state at a particular bytecode offset
|
||||||
/// Has a offset_delta, the offset is calculated by adding offset_delta + 1 to the previous offset
|
/// Has a offset_delta, the offset is calculated by adding offset_delta + 1 to the previous offset
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||||
pub enum StackMapFrame {
|
pub enum StackMapFrame {
|
||||||
/// Exactly the same locals as the previous frame and zero stack items, offset_delta is frame_type
|
/// Exactly the same locals as the previous frame and zero stack items, offset_delta is frame_type
|
||||||
SameFrame {
|
SameFrame {
|
||||||
|
|
@ -413,7 +414,7 @@ pub enum StackMapFrame {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A stack value/local variable type `StackMapFrame`
|
/// A stack value/local variable type `StackMapFrame`
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
pub enum VerificationTypeInfo {
|
pub enum VerificationTypeInfo {
|
||||||
Top {
|
Top {
|
||||||
tag: u1, // 0
|
tag: u1, // 0
|
||||||
|
|
@ -448,7 +449,7 @@ pub enum VerificationTypeInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A struct for the `AttributeInfo::InnerClasses`
|
/// A struct for the `AttributeInfo::InnerClasses`
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[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: u2,
|
||||||
|
|
@ -461,7 +462,7 @@ pub struct AttributeInnerClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Line number information for `AttributeInfo::LineNumberTable`
|
/// Line number information for `AttributeInfo::LineNumberTable`
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
pub struct AttributeLineNumber {
|
pub struct AttributeLineNumber {
|
||||||
/// Index into the code array where a new line in the source begins
|
/// Index into the code array where a new line in the source begins
|
||||||
pub start_pc: u2,
|
pub start_pc: u2,
|
||||||
|
|
@ -470,7 +471,7 @@ pub struct AttributeLineNumber {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Local variable information for `AttributeInfo::LocalVariableTable` and `AttributeInfo::LocalVariableTypeTable`
|
/// Local variable information for `AttributeInfo::LocalVariableTable` and `AttributeInfo::LocalVariableTypeTable`
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
pub struct AttributeLocalVariableTable {
|
pub struct AttributeLocalVariableTable {
|
||||||
/// The local variable must have a value between `start_pc` and `start_pc + length`. Must be a valid opcode
|
/// The local variable must have a value between `start_pc` and `start_pc + length`. Must be a valid opcode
|
||||||
pub start_pc: u2,
|
pub start_pc: u2,
|
||||||
|
|
@ -485,7 +486,7 @@ pub struct AttributeLocalVariableTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A runtime-visible annotation to the program
|
/// A runtime-visible annotation to the program
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[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: u2,
|
||||||
|
|
@ -496,7 +497,7 @@ pub struct Annotation {
|
||||||
// these type names have just become java at this point. no shame.
|
// these type names have just become java at this point. no shame.
|
||||||
|
|
||||||
/// A element-value pair in the `Annotation`
|
/// A element-value pair in the `Annotation`
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[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: u2,
|
||||||
|
|
@ -504,7 +505,7 @@ pub struct AnnotationElementValuePair {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The value of an `AnnotationElementValuePair`
|
/// The value of an `AnnotationElementValuePair`
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||||
pub struct AnnotationElementValue {
|
pub struct AnnotationElementValue {
|
||||||
/// B, C, D, F, I, J, S, Z or s, e, c, @,
|
/// B, C, D, F, I, J, S, Z or s, e, c, @,
|
||||||
pub tag: u1,
|
pub tag: u1,
|
||||||
|
|
@ -512,7 +513,7 @@ pub struct AnnotationElementValue {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The value of a `AnnotationElementValue`
|
/// The value of a `AnnotationElementValue`
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||||
pub enum AnnotationElementValueValue {
|
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 {
|
||||||
|
|
@ -544,14 +545,14 @@ pub enum AnnotationElementValueValue {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used in `AttributeInfo::RuntimeVisibleParameterAnnotations`
|
/// Used in `AttributeInfo::RuntimeVisibleParameterAnnotations`
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||||
pub struct ParameterAnnotation {
|
pub struct ParameterAnnotation {
|
||||||
pub num_annotations: u2,
|
pub num_annotations: u2,
|
||||||
pub annotations: Vec<Annotation>,
|
pub annotations: Vec<Annotation>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used in `AttributeInfo::BootstrapMethods `
|
/// Used in `AttributeInfo::BootstrapMethods `
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[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: u2,
|
||||||
|
|
@ -564,7 +565,7 @@ pub struct BootstrapMethod {
|
||||||
|
|
||||||
/// Access Flags of a class
|
/// Access Flags of a class
|
||||||
#[repr(u16)]
|
#[repr(u16)]
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
pub enum ClassAccessFlag {
|
pub enum ClassAccessFlag {
|
||||||
/// Declared public; may be accessed from outside its package.
|
/// Declared public; may be accessed from outside its package.
|
||||||
Public = 0x0001,
|
Public = 0x0001,
|
||||||
|
|
@ -586,7 +587,7 @@ pub enum ClassAccessFlag {
|
||||||
|
|
||||||
/// Access Flags of a method
|
/// Access Flags of a method
|
||||||
#[repr(u16)]
|
#[repr(u16)]
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
pub enum MethodAccessFlag {
|
pub enum MethodAccessFlag {
|
||||||
// Declared public; may be accessed from outside its package.
|
// Declared public; may be accessed from outside its package.
|
||||||
PUBLIC = 0x0001,
|
PUBLIC = 0x0001,
|
||||||
|
|
@ -616,7 +617,7 @@ pub enum MethodAccessFlag {
|
||||||
|
|
||||||
/// Access flags for an inner class
|
/// Access flags for an inner class
|
||||||
#[repr(u16)]
|
#[repr(u16)]
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
pub enum InnerClassAccessFlags {
|
pub enum InnerClassAccessFlags {
|
||||||
/// Marked or implicitly public in source.
|
/// Marked or implicitly public in source.
|
||||||
PUBLIC = 0x0001,
|
PUBLIC = 0x0001,
|
||||||
|
|
@ -642,7 +643,7 @@ pub enum InnerClassAccessFlags {
|
||||||
|
|
||||||
/// Access flags for a field
|
/// Access flags for a field
|
||||||
#[repr(u16)]
|
#[repr(u16)]
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
pub enum FieldAccessFlags {
|
pub enum FieldAccessFlags {
|
||||||
/// Declared public; may be accessed from outside its package.
|
/// Declared public; may be accessed from outside its package.
|
||||||
PUBLIC = 0x0001,
|
PUBLIC = 0x0001,
|
||||||
|
|
|
||||||
125
src/parse/test.rs
Normal file
125
src/parse/test.rs
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn data_u1() {
|
||||||
|
let bytes = [0xff, 0x00];
|
||||||
|
let mut data = Data {
|
||||||
|
data: &bytes,
|
||||||
|
pointer: 0,
|
||||||
|
};
|
||||||
|
assert_eq!(data.u1().unwrap(), 0xff);
|
||||||
|
assert_eq!(data.u1().unwrap(), 0x00);
|
||||||
|
assert_eq!(data.last_u1().unwrap(), 0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn data_u2() {
|
||||||
|
let bytes = [0xff, 0x33, 0x11, 0x00];
|
||||||
|
let mut data = Data {
|
||||||
|
data: &bytes,
|
||||||
|
pointer: 0,
|
||||||
|
};
|
||||||
|
assert_eq!(data.u2().unwrap(), 0xff33);
|
||||||
|
assert_eq!(data.u2().unwrap(), 0x1100);
|
||||||
|
assert_eq!(data.last_u2().unwrap(), 0x1100);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn data_u4() {
|
||||||
|
let bytes = [0xff, 0x33, 0x11, 0x00];
|
||||||
|
let mut data = Data {
|
||||||
|
data: &bytes,
|
||||||
|
pointer: 0,
|
||||||
|
};
|
||||||
|
assert_eq!(data.u4().unwrap(), 0xff331100);
|
||||||
|
assert_eq!(data.last_u4().unwrap(), 0xff331100);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_empty_class() {
|
||||||
|
let class = include_bytes!("../../testdata/Test.class");
|
||||||
|
println!("Starting test...");
|
||||||
|
let parsed = parse_class_file(class).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(parsed.minor_version, 0);
|
||||||
|
assert_eq!(parsed.major_version, 0x003b);
|
||||||
|
assert_eq!(parsed.constant_pool_count, 0x000d);
|
||||||
|
assert_eq!(parsed.constant_pool.len(), 12);
|
||||||
|
assert_eq!(
|
||||||
|
parsed.constant_pool,
|
||||||
|
vec![
|
||||||
|
CpInfo::MethodRef {
|
||||||
|
tag: 0x0a,
|
||||||
|
class_index: 2,
|
||||||
|
name_and_type_index: 3
|
||||||
|
},
|
||||||
|
CpInfo::Class {
|
||||||
|
tag: 7,
|
||||||
|
name_index: 4
|
||||||
|
},
|
||||||
|
CpInfo::NameAndType {
|
||||||
|
tag: 0xc,
|
||||||
|
name_index: 5,
|
||||||
|
descriptor_index: 6
|
||||||
|
},
|
||||||
|
CpInfo::Utf8 {
|
||||||
|
tag: 1,
|
||||||
|
length: 0x10,
|
||||||
|
bytes: "java/lang/Object".bytes().collect()
|
||||||
|
},
|
||||||
|
CpInfo::Utf8 {
|
||||||
|
tag: 1,
|
||||||
|
length: 6,
|
||||||
|
bytes: "init".bytes().collect()
|
||||||
|
},
|
||||||
|
CpInfo::Utf8 {
|
||||||
|
tag: 1,
|
||||||
|
length: 3,
|
||||||
|
bytes: "()V".bytes().collect()
|
||||||
|
},
|
||||||
|
CpInfo::Class {
|
||||||
|
tag: 7,
|
||||||
|
name_index: 8
|
||||||
|
},
|
||||||
|
CpInfo::Utf8 {
|
||||||
|
tag: 1,
|
||||||
|
length: 4,
|
||||||
|
bytes: "Test".bytes().collect()
|
||||||
|
},
|
||||||
|
CpInfo::Utf8 {
|
||||||
|
tag: 1,
|
||||||
|
length: 4,
|
||||||
|
bytes: "Code".bytes().collect()
|
||||||
|
},
|
||||||
|
CpInfo::Utf8 {
|
||||||
|
tag: 1,
|
||||||
|
length: 15,
|
||||||
|
bytes: "LineNumberTable".bytes().collect()
|
||||||
|
},
|
||||||
|
CpInfo::Utf8 {
|
||||||
|
tag: 1,
|
||||||
|
length: 10,
|
||||||
|
bytes: "SourceFile".bytes().collect()
|
||||||
|
},
|
||||||
|
CpInfo::Utf8 {
|
||||||
|
tag: 1,
|
||||||
|
length: 9,
|
||||||
|
bytes: "Test.java".bytes().collect()
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
|
assert_eq!(parsed.access_flags, 0x0021);
|
||||||
|
assert_eq!(parsed.this_class, 7);
|
||||||
|
assert_eq!(parsed.super_class, 2);
|
||||||
|
assert_eq!(parsed.interfaces_count, 0);
|
||||||
|
assert_eq!(parsed.interfaces, vec![]);
|
||||||
|
assert_eq!(parsed.fields_count, 0);
|
||||||
|
assert_eq!(parsed.fields, vec![]);
|
||||||
|
assert_eq!(parsed.method_count, 1);
|
||||||
|
assert_eq!(parsed.methods[0].access_flags, 1);
|
||||||
|
assert_eq!(parsed.methods[0].name_index, 5);
|
||||||
|
assert_eq!(parsed.methods[0].descriptor_index, 6);
|
||||||
|
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_length, 0x1d);
|
||||||
|
}
|
||||||
BIN
testdata/Test.class
vendored
Normal file
BIN
testdata/Test.class
vendored
Normal file
Binary file not shown.
133
testdata/Test.class.txt
vendored
Normal file
133
testdata/Test.class.txt
vendored
Normal file
|
|
@ -0,0 +1,133 @@
|
||||||
|
Manually parsed by hand
|
||||||
|
|
||||||
|
hexdump -C Test.class
|
||||||
|
|
||||||
|
00000000 |ca fe ba be|00 00|00 3b |00 0d|0a.00 02.00 03|07. |.......;........|
|
||||||
|
00000010 00 04|0c.00 05.00 06|01 .00 10.6a 61 76 61 2f 6c |..........java/l|
|
||||||
|
00000020 61 6e 67 2f 4f 62 6a 65 63 74|01.00 06.3c 69 6e |ang/Object...<in|
|
||||||
|
00000030 69 74 3e|01.00 03.28 29 56|07.00 08|01.00 04.54 |it>...()V......T|
|
||||||
|
00000040 65 73 74|01.00 04.43 6f 64 65|01.00 0f.4c 69 6e |est...Code...Lin|
|
||||||
|
00000050 65 4e 75 6d 62 65 72 54 61 62 6c 65|01.00 0a.53 |eNumberTable...S|
|
||||||
|
00000060 6f 75 72 63 65 46 69 6c 65|01.00 09.54 65 73 74 |ourceFile...Test|
|
||||||
|
00000070 2e 6a 61 76 61|00 21|00 07|00 02|00 00|00 00|00 |.java.!.........|
|
||||||
|
00000080 01|00 01.00 05.00 06.00 01:00 09.00 00 00 1d.00 |................|
|
||||||
|
00000090 01.00 01.00 00 00 05.2a b7 00 01 b1.00 00.00 01: |.......*........|
|
||||||
|
000000a0 00 0a.00 00 00 06.00 01 :00 00.00 01|00 01|00 0b. |................|
|
||||||
|
000000b0 00 00 00 02.00 0c |......|
|
||||||
|
000000b6
|
||||||
|
|
||||||
|
|
||||||
|
Magic: ca fe ba be
|
||||||
|
Minor: 00 00
|
||||||
|
Major: 00 3b
|
||||||
|
CpCount: 00 0d (13) (13 - 1 = 12)
|
||||||
|
Cp: [
|
||||||
|
1: {
|
||||||
|
tag: 0a (10, MethodRef)
|
||||||
|
class_index: 00 02 (2)
|
||||||
|
name_and_type_index: 00 03 (2)
|
||||||
|
}
|
||||||
|
2: {
|
||||||
|
tag: 07 (7, Class)
|
||||||
|
name_index: 00 04 (4) (java/lang/Object)
|
||||||
|
}
|
||||||
|
3: {
|
||||||
|
tag: 0c (12, NameAndType)
|
||||||
|
name_index: 00 05 (05)
|
||||||
|
descriptor_index: 00 06 (6)
|
||||||
|
}
|
||||||
|
4: {
|
||||||
|
tag: 01 (1, Utf8)
|
||||||
|
length: 00 10 (16)
|
||||||
|
string: 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 (java/lang/Object)
|
||||||
|
}
|
||||||
|
5: {
|
||||||
|
tag: 01 (1, Utf8)
|
||||||
|
length: 00 06 (6)
|
||||||
|
string: 3c 69 6e 69 74 3e (<init>)
|
||||||
|
}
|
||||||
|
6: {
|
||||||
|
tag: 01 (1, Utf8)
|
||||||
|
length: 00 03 (3)
|
||||||
|
bytes: 28 29 56 (()V)
|
||||||
|
}
|
||||||
|
7: {
|
||||||
|
tag: 07 (7, Class)
|
||||||
|
name_index: 00 08 (8) (Test)
|
||||||
|
}
|
||||||
|
8: {
|
||||||
|
tag: 01 (1, Utf8)
|
||||||
|
length: 00 04 (4)
|
||||||
|
bytes: 54 65 73 74 (Test)
|
||||||
|
}
|
||||||
|
9: {
|
||||||
|
tag: 01 (1, Utf8)
|
||||||
|
length: 00 04 (4)
|
||||||
|
bytes: 43 6f 64 65 (Code)
|
||||||
|
}
|
||||||
|
10: {
|
||||||
|
tag: 01 (1, Utf8)
|
||||||
|
length: 00 0f (15)
|
||||||
|
bytes: 4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 6c 65 (LineNumberTable)
|
||||||
|
}
|
||||||
|
11: {
|
||||||
|
tag: 01 (1, Utf8)
|
||||||
|
length: 00 0a (10)
|
||||||
|
bytes: 53 6f 75 72 63 65 46 69 6c 65 (SourceFile)
|
||||||
|
}
|
||||||
|
12: {
|
||||||
|
tag: 01 (1, Utf8)
|
||||||
|
length: 00 09 (9)
|
||||||
|
bytes: 54 65 73 74 2e 6a 61 76 61 (Test.java)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
access_flags: 00 21
|
||||||
|
this_class: 00 07 (Test)
|
||||||
|
super_class: 00 02 (java/lang/Object)
|
||||||
|
interfaces_count: 00 00
|
||||||
|
interfaces: []
|
||||||
|
fields_count: 00 00
|
||||||
|
fields: []
|
||||||
|
methods_count: 00 01
|
||||||
|
methods: [
|
||||||
|
{
|
||||||
|
access_flags: 00 01
|
||||||
|
name_index: 00 05
|
||||||
|
descriptor_index: 00 06
|
||||||
|
attributes_count: 00 01
|
||||||
|
attributes: [
|
||||||
|
{
|
||||||
|
name_index: 00 09 (Code)
|
||||||
|
attribute_length: 00 00 00 1d (29)
|
||||||
|
max_stack: 00 01
|
||||||
|
max_locals: 00 01
|
||||||
|
code_length: 00 00 00 05
|
||||||
|
code: 2a b7 00 01 b1
|
||||||
|
exception_table_length: 00 00
|
||||||
|
exception_table: []
|
||||||
|
attributes_count: 00 01
|
||||||
|
attributes: [
|
||||||
|
{
|
||||||
|
attribute_name_index: 00 0a (LineNumberTable)
|
||||||
|
attribute_length: 00 00 00 06
|
||||||
|
line_number_table_length: 00 01
|
||||||
|
line_number_table: [
|
||||||
|
{
|
||||||
|
start_pc: 00 00
|
||||||
|
line_number: 00 01
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
attributes_count: 00 01
|
||||||
|
attributes: [
|
||||||
|
{
|
||||||
|
attribute_name_index: 00 0b (SourceFile)
|
||||||
|
attribute_length: 00 00 00 02
|
||||||
|
sourcefile_index: 00 0c
|
||||||
|
}
|
||||||
|
]
|
||||||
1
testdata/Test.java
vendored
Normal file
1
testdata/Test.java
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
public class Test {}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue