Skip to content

Commit

Permalink
Improve constant pool handling
Browse files Browse the repository at this point in the history
Work on decompilation

This commit syncs changes from long ago as I'd like to give another try
to decompilation soon.

Signed-off-by: Tin Svagelj <[email protected]>
  • Loading branch information
Caellian committed Oct 20, 2023
1 parent c6a2beb commit 56020f3
Show file tree
Hide file tree
Showing 23 changed files with 678 additions and 425 deletions.
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,20 @@ edition = "2021"
[[bin]]
name = "jaded"
path = "src/bin/main.rs"
required-features = ["clap"]
required-features = ["tracing-subscriber", "clap"]

[dependencies]
jvm-class-format = { path = "class_format" }

tracing = { version = "0.1", features = ["log"] }
tracing-subscriber = "0.3"
tracing-subscriber = { version = "0.3", optional = true }
thiserror = "1.0"

paste = "1.0"

byteorder = "1.4"
bytemuck = "1.7"
num_enum = "0.6"
num_enum = "0.7"
bitflags = "2.2"

zip = "0.6"
Expand Down
6 changes: 3 additions & 3 deletions class_format/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ edition = "2021"
[dependencies]
byteorder = "1.4"

num_enum = "0.6"
num_enum = "0.7"
bitflags = "2.2"

ordered-float = "3.7"
ordered-float = "4.1"

paste = "1.0"

log = "0.4"
log = { version = "0.4", features = ["release_max_level_info"] }

thiserror = "1.0"
3 changes: 2 additions & 1 deletion class_format/src/access_flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use byteorder::{ReadBytesExt, BE};
use std::io::Read;

bitflags::bitflags! {
/// Access flags used by classes and class members.
#[derive(Debug, Clone, Copy)]
pub struct AccessFlags: u16 {
/// Declared public; may be accessed from outside its package.
Expand Down Expand Up @@ -45,7 +46,7 @@ bitflags::bitflags! {
/// Declared strictfp; floating-point mode is FP-strict.
const STRICT = 0x0800;

/// Declared synthetic; not present in the source code.
/// Declared synthetic; generated by compiler (not in source code).
const SYNTHETIC = 0x1000;

/// Declared as an annotation interface.
Expand Down
49 changes: 24 additions & 25 deletions class_format/src/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ pub trait Attribute: Into<AttributeValue> + Sized {

fn read_data<R: std::io::Read>(
r: &mut R,
constant_pool: Option<&ConstantPool>,
constant_pool: &ConstantPool,
) -> Result<Self, AttributeError>;
}

Expand All @@ -100,7 +100,7 @@ impl Attribute for CodeData {
#[inline]
fn read_data<R: std::io::Read>(
r: &mut R,
constant_pool: Option<&ConstantPool>,
constant_pool: &ConstantPool,
) -> Result<Self, AttributeError> {
let max_stack = r.read_u16::<BE>()? as usize;
let max_locals = r.read_u16::<BE>()? as usize;
Expand Down Expand Up @@ -153,7 +153,7 @@ impl Attribute for ExceptionData {
#[inline]
fn read_data<R: std::io::Read>(
r: &mut R,
_constant_pool: Option<&ConstantPool>,
_constant_pool: &ConstantPool,
) -> Result<Self, AttributeError> {
let number_of_exceptions = r.read_u16::<BE>()? as usize;
let mut exceptions = Vec::with_capacity(number_of_exceptions);
Expand Down Expand Up @@ -192,7 +192,7 @@ impl Attribute for InnerClassData {
#[inline]
fn read_data<R: std::io::Read>(
r: &mut R,
_constant_pool: Option<&ConstantPool>,
_constant_pool: &ConstantPool,
) -> Result<Self, AttributeError> {
let number_of_classes = r.read_u16::<BE>()? as usize;
let mut classes = Vec::with_capacity(number_of_classes);
Expand Down Expand Up @@ -231,7 +231,7 @@ impl Attribute for LineNumberTable {
#[inline]
fn read_data<R: std::io::Read>(
r: &mut R,
_constant_pool: Option<&ConstantPool>,
_constant_pool: &ConstantPool,
) -> Result<Self, AttributeError> {
let line_number_table_length = r.read_u16::<BE>()? as usize;
let mut table = Vec::with_capacity(line_number_table_length);
Expand Down Expand Up @@ -269,7 +269,7 @@ impl Attribute for LocalVariableTable {

fn read_data<R: std::io::Read>(
r: &mut R,
_constant_pool: Option<&ConstantPool>,
_constant_pool: &ConstantPool,
) -> Result<Self, AttributeError> {
let local_variable_table_length = r.read_u16::<BE>()? as usize;
let mut table = Vec::with_capacity(local_variable_table_length);
Expand Down Expand Up @@ -307,7 +307,7 @@ impl Attribute for AnnotationDefaultData {

fn read_data<R: std::io::Read>(
r: &mut R,
_constant_pool: Option<&ConstantPool>,
_constant_pool: &ConstantPool,
) -> Result<Self, AttributeError> {
let mut default = Vec::with_capacity(256);
r.read_to_end(&mut default)?;
Expand Down Expand Up @@ -341,7 +341,7 @@ impl Attribute for EnclosingMethodData {

fn read_data<R: std::io::Read>(
r: &mut R,
_constant_pool: Option<&ConstantPool>,
_constant_pool: &ConstantPool,
) -> Result<Self, AttributeError> {
Ok(EnclosingMethodData {
class_index: r.read_u16::<BE>()? as usize,
Expand Down Expand Up @@ -375,7 +375,7 @@ impl Attribute for LocalVariableTypeTable {

fn read_data<R: std::io::Read>(
r: &mut R,
_constant_pool: Option<&ConstantPool>,
_constant_pool: &ConstantPool,
) -> Result<Self, AttributeError> {
let local_variable_type_table_length = r.read_u16::<BE>()? as usize;
let mut table = Vec::with_capacity(local_variable_type_table_length);
Expand Down Expand Up @@ -412,14 +412,15 @@ impl Attribute for SignatureData {
const NAME: &'static str = "Signature";
fn read_data<R: std::io::Read>(
r: &mut R,
constant_pool: Option<&ConstantPool>,
constant_pool: &ConstantPool,
) -> Result<Self, AttributeError> {
let index = r.read_u16::<BE>()?;
match constant_pool.and_then(|cp| cp.get(&index)) {
Some(Constant::Utf8 { value }) => Ok(SignatureData {
let index = r.read_u16::<BE>()? as usize;

match constant_pool.try_get(index)? {
Constant::Utf8 { value } => Ok(SignatureData {
signature: value.clone(),
}),
_ => return Err(AttributeError::MissingContant),
_ => return Err(AttributeError::InvalidData),
}
}
}
Expand Down Expand Up @@ -449,7 +450,7 @@ impl Attribute for MethodParameterData {

fn read_data<R: std::io::Read>(
r: &mut R,
_constant_pool: Option<&ConstantPool>,
_constant_pool: &ConstantPool,
) -> Result<Self, AttributeError> {
let length = r.read_u8()? as usize;
let mut parameters = Vec::with_capacity(length);
Expand Down Expand Up @@ -513,15 +514,13 @@ pub enum AttributeValue {
impl AttributeValue {
pub fn read_from<R: std::io::Read>(
r: &mut R,
constant_pool: Option<&ConstantPool>,
constant_pool: &ConstantPool,
) -> Result<(String, AttributeValue), AttributeError> {
let name_i = r.read_u16::<BE>()?;
let name = match constant_pool.and_then(|cp| cp.get(&name_i)) {
Some(c) => match c {
Constant::Utf8 { value } => value.clone(),
_ => return Err(AttributeError::InvalidNameType),
},
None => return Err(AttributeError::NoAttribName),
let name_i = r.read_u16::<BE>()? as usize;

let name = match constant_pool.try_get(name_i)? {
Constant::Utf8 { value } => value.clone(),
_ => return Err(AttributeError::InvalidNameType),
};

let length = r.read_u32::<BE>()? as usize;
Expand All @@ -534,7 +533,7 @@ impl AttributeValue {

pub fn read_all<R: std::io::Read>(
r: &mut R,
constant_pool: Option<&ConstantPool>,
constant_pool: &ConstantPool,
) -> Result<HashMap<String, AttributeValue>, AttributeError> {
let attributes_count = r.read_u16::<BE>()? as usize;
let mut attributes = HashMap::with_capacity(attributes_count);
Expand All @@ -550,7 +549,7 @@ impl AttributeValue {
pub fn from_name_and_data(
name: impl AsRef<str>,
data: &[u8],
constant_pool: Option<&ConstantPool>,
constant_pool: &ConstantPool,
) -> Result<AttributeValue, AttributeError> {
let mut r = Cursor::new(data);

Expand Down
122 changes: 119 additions & 3 deletions class_format/src/constant.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::error::ConstantError;
use crate::error::{ConstantError, ConstantPoolError};
use crate::ext::ReadByteVecExt;
use byteorder::{ReadBytesExt, BE};
use num_enum::{IntoPrimitive, TryFromPrimitive};
Expand Down Expand Up @@ -44,7 +44,17 @@ pub enum ConstantTag {
Package = 20,
}

#[derive(Debug, Clone, PartialEq, Hash)]
impl ConstantTag {
pub fn length(&self) -> usize {
match self {
ConstantTag::Long => 2,
ConstantTag::Double => 2,
_ => 1,
}
}
}

#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum Constant {
Class {
name_index: u16,
Expand Down Expand Up @@ -138,6 +148,8 @@ impl Constant {
}

pub fn read_from<R: Read>(r: &mut R) -> Result<Constant, ConstantError> {
log::trace!("enter Constant::read_from(impl Read)");

let tag = ConstantTag::try_from(r.read_u8()?)?;

Ok(match tag {
Expand Down Expand Up @@ -214,4 +226,108 @@ impl Constant {
}
}

pub type ConstantPool = HashMap<u16, Constant>;
#[derive(Debug, Clone)]
pub struct ConstantPool {
pub members: HashMap<usize, Constant>,
size: usize,
}

#[macro_export]
macro_rules! constant_match {
($constant: expr, Constant::$exp: ident { $($param: ident),* } ) => {
match $constant {
Constant::$exp { $($param),* } => {
Ok(($($param),*))
}
other => {
Err(ConstantPoolError::UnexpectedType { found: other.tag(), expected: ConstantTag::$exp })
}
}
};
($constant: expr, Constant::$exp: ident { $($param: ident, )* .. } ) => {
match $constant {
Constant::$exp { $($param,)* .. } => {
Ok(($($param),*))
}
other => {
Err(ConstantPoolError::UnexpectedType { found: other.tag(), expected: ConstantTag::$exp })
}
}
};
($constant: expr, Constant::$exp: ident { $($param: ident),* } => $code: block) => {
match $constant {
Constant::$exp { $($param),* } => {
Ok($code)
}
other => {
Err(ConstantPoolError::UnexpectedType { found: other.tag(), expected: ConstantTag::$exp })
}
}
};
($constant: expr, Constant::$exp: ident { $($param: ident,)* .. } => $code: block) => {
match $constant {
Constant::$exp { $($param,)* .. } => {
Ok($code)
}
other => {
Err(ConstantPoolError::UnexpectedType { found: other.tag(), expected: ConstantTag::$exp })
}
}
};
}

impl ConstantPool {
pub fn new() -> ConstantPool {
ConstantPool {
members: HashMap::new(),
size: 1,
}
}

pub fn with_capacity(capacity: usize) -> ConstantPool {
ConstantPool {
members: HashMap::with_capacity(capacity),
size: 1,
}
}

pub fn try_get(&self, index: usize) -> Result<&Constant, ConstantPoolError> {
self.members
.get(&index)
.ok_or(ConstantPoolError::InvalidIndex {
index,
length: self.size,
})
}

pub fn get(&self, index: usize) -> &Constant {
match self.members.get(&index) {
Some(it) => it,
None => panic!(
"no constant pool member at index {} (size: {})",
index,
self.members.len()
),
}
}

pub unsafe fn get_unchecked(&self, index: usize) -> &Constant {
self.members.get(&index).unwrap_unchecked()
}

pub fn insert(&mut self, constant: Constant) {
log::trace!("ConstantPool::insert(&self, {:?})", &constant);
let constant_length = constant.tag().length();
self.members.insert(self.size, constant);
self.size += constant_length;
}

pub fn size(&self) -> usize {
self.size
}

pub fn get_class_name(&mut self, class_index: usize) -> Result<String, ConstantPoolError> {
let name_i = constant_match!(self.get(class_index), Constant::Class { name_index })?;
constant_match!(self.get(*name_i as usize), Constant::Utf8 { value }).cloned()
}
}
Loading

0 comments on commit 56020f3

Please sign in to comment.