Skip to content

Commit

Permalink
Gets class name from cppbind::type_info
Browse files Browse the repository at this point in the history
  • Loading branch information
ultimaweapon committed Oct 15, 2024
1 parent 2353095 commit 13f86f8
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 28 deletions.
123 changes: 97 additions & 26 deletions macros/src/meta.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
pub use self::ty::*;

use crate::symbol::Symbol;
use crate::symbol::{Segment, Symbol, TemplateArg};
use memmap2::Mmap;
use object::read::archive::ArchiveFile;
use object::read::elf::ElfFile64;
use object::read::macho::MachOFile64;
use object::{Endianness, LittleEndian, Object};
use object::{Endianness, LittleEndian, Object, ObjectSymbol, SymbolIndex};
use std::collections::HashMap;
use std::fs::File;
use std::path::Path;
Expand All @@ -26,42 +26,103 @@ impl Metadata {
let ar = ArchiveFile::parse(file.as_ref()).map_err(MetadataError::ParseFileFailed)?;

// Parse members.
let mut types = HashMap::new();
let mut meta = Self {
types: HashMap::new(),
};

for (i, mem) in ar.members().enumerate() {
// Get member data.
let mem = mem.map_err(|e| MetadataError::ParseMemberHeaderFailed(i, e))?;
let mem = mem
.data(file.as_ref())
.map_err(|e| MetadataError::GetMemberDataFailed(i, e))?;
let name = String::from_utf8_lossy(mem.name());
let data = match mem.data(file.as_ref()) {
Ok(v) => v,
Err(e) => return Err(MetadataError::GetMemberDataFailed(name.into_owned(), e)),
};

// Parse member.
if mem.starts_with(b"\x7FELF") {
ElfFile64::<Endianness>::parse(mem)
.map_err(|e| MetadataError::ParseMemberFailed(i, e))
.and_then(|m| Self::parse_obj(m, &mut types))?;
} else if mem.starts_with(&0xFEEDFACFu32.to_le_bytes()) {
MachOFile64::<LittleEndian>::parse(mem)
.map_err(|e| MetadataError::ParseMemberFailed(i, e))
.and_then(|m| Self::parse_obj(m, &mut types))?;
let r = if data.starts_with(b"\x7FELF") {
let obj = match ElfFile64::<Endianness>::parse(data) {
Ok(v) => v,
Err(e) => return Err(MetadataError::ParseMemberFailed(name.into_owned(), e)),
};

meta.parse_obj(obj)
} else if data.starts_with(&0xFEEDFACFu32.to_le_bytes()) {
let obj = match MachOFile64::<LittleEndian>::parse(data) {
Ok(v) => v,
Err(e) => return Err(MetadataError::ParseMemberFailed(name.into_owned(), e)),
};

meta.parse_obj(obj)
} else {
return Err(MetadataError::UnknownMember(
mem.iter().take(4).map(|v| *v).collect(),
data.iter().take(4).map(|v| *v).collect(),
));
};

if let Err(e) = r {
return Err(MetadataError::ParseSymbolFailed(name.into_owned(), e));
}
}

Ok(Self { types })
Ok(meta)
}

pub fn get_type(&self, name: impl AsRef<str>) -> Option<&TypeInfo> {
self.types.get(name.as_ref())
}

fn parse_obj<'a>(
_: impl Object<'a>,
_: &mut HashMap<String, TypeInfo>,
) -> Result<(), MetadataError> {
fn parse_obj<'a>(&mut self, obj: impl Object<'a>) -> Result<(), SymbolError> {
// Parse symbols.
for sym in obj.symbols() {
use std::collections::hash_map::Entry;

// Get symbol name.
let raw = match sym.name_bytes() {
Ok(v) => v,
Err(e) => return Err(SymbolError::GetNameFailed(sym.index(), e)),
};

// Parse name.
let addr = sym.address();
let size = sym.size();
let sym = match Symbol::parse(raw) {
Ok(v) => v,
Err(_) => continue, // Ignore unknown symbol.
};

// Check namespace.
let mut iter = sym.name().iter();

if !iter
.next()
.is_some_and(|v| *v == Segment::Ident("cppbind".into()))
{
continue;
}

// Check if type_info.
if !iter
.next()
.is_some_and(|v| *v == Segment::Ident("type_info".into()))
{
return Err(SymbolError::UnknownCppbindSymbol);
}

// Get class name.
let class = iter.next().ok_or(SymbolError::UnknownCppbindSymbol)?;
let class = match class {
Segment::TemplateArg(TemplateArg::Ident(v)) => v,
_ => return Err(SymbolError::UnknownCppbindSymbol),
};

// Get TypeInfo.
let info = match self.types.entry(class.as_ref().to_owned()) {
Entry::Occupied(e) => e.into_mut(),
Entry::Vacant(e) => e.insert(TypeInfo::default()),
};
}

Ok(())
}
}
Expand All @@ -81,15 +142,25 @@ pub enum MetadataError {
#[error("couldn't parse header for member #{0}")]
ParseMemberHeaderFailed(usize, #[source] object::read::Error),

#[error("couldn't get data for member #{0}")]
GetMemberDataFailed(usize, #[source] object::read::Error),
#[error("couldn't get data of {0}")]
GetMemberDataFailed(String, #[source] object::read::Error),

#[error("unknown member ({0:x?})")]
UnknownMember(Vec<u8>),

#[error("couldn't parse member #{0}")]
ParseMemberFailed(usize, #[source] object::read::Error),
#[error("couldn't parse {0}")]
ParseMemberFailed(String, #[source] object::read::Error),

#[error("couldn't parse a symbol on {0}")]
ParseSymbolFailed(String, #[source] SymbolError),
}

/// Represents an error when [`Metadata`] fails to parse a symbol.
#[derive(Debug, Error)]
pub enum SymbolError {
#[error("couldn't get name of symbol #{0}")]
GetNameFailed(SymbolIndex, #[source] object::read::Error),

#[error("unknown symbol in cppbind namespace")]
UnknownDefinition(Symbol),
#[error("unknown symbol on cppbind namespace")]
UnknownCppbindSymbol,
}
4 changes: 2 additions & 2 deletions macros/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ impl Symbol {
if mangled.starts_with(b"_Z") {
self::itanium::parse(&mangled[2..])
} else {
todo!()
Err(SymbolError::UnknownSymbol)
}
}

pub fn name(&self) -> &[Segment] {
pub fn name(&self) -> &[Segment<'static>] {
&self.name
}
}
Expand Down

0 comments on commit 13f86f8

Please sign in to comment.