use crate::api::{self, cache, dump_assembly};
use crate::logger;
use crate::structs::core::Class;
use std::ffi::c_void;
use super::image::Image;
#[derive(Debug, Clone)]
pub struct Assembly {
pub image: Image,
pub address: *mut c_void,
pub file: String,
pub name: String,
pub classes: Vec<Class>,
}
unsafe impl Send for Assembly {}
unsafe impl Sync for Assembly {}
impl std::fmt::Display for Assembly {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.fmt_assembly())
}
}
impl Assembly {
fn fmt_assembly(&self) -> String {
let mut s = format!(
"// Assembly: {} ({}) @ {:?}\n",
self.name, self.file, self.address
);
if !self.classes.is_empty() {
for class in &self.classes {
s.push('\n');
s.push_str(&class.to_string());
}
}
s
}
pub fn class(&self, name: &str) -> Option<Class> {
let (namespace, class_name) = if let Some(last_dot) = name.rfind('.') {
(&name[..last_dot], &name[last_dot + 1..])
} else {
("", name)
};
let namespace_cstr = std::ffi::CString::new(namespace).ok()?;
let name_cstr = std::ffi::CString::new(class_name).ok()?;
unsafe {
let class_ptr = api::class_from_name(
self.image.address,
namespace_cstr.as_ptr(),
name_cstr.as_ptr(),
);
if !class_ptr.is_null() {
return cache::class_from_ptr(class_ptr);
}
}
if let Some(class) = cache::CACHE.classes.get(name) {
return Some((**class).clone());
}
None
}
pub fn dump(&self) -> &Self {
if dump_assembly(Some(&self.name)).is_none() {
logger::error("Failed to dump assembly");
}
self
}
}