From 13f86f8e2258185fe534630eeecc9674b7c7323d Mon Sep 17 00:00:00 2001 From: Putta Khunchalee Date: Wed, 16 Oct 2024 02:22:03 +0700 Subject: [PATCH] Gets class name from cppbind::type_info --- macros/src/meta.rs | 123 ++++++++++++++++++++++++++++++++++--------- macros/src/symbol.rs | 4 +- 2 files changed, 99 insertions(+), 28 deletions(-) diff --git a/macros/src/meta.rs b/macros/src/meta.rs index 8d37e71..42188ff 100644 --- a/macros/src/meta.rs +++ b/macros/src/meta.rs @@ -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; @@ -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::::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::::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::::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::::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) -> Option<&TypeInfo> { self.types.get(name.as_ref()) } - fn parse_obj<'a>( - _: impl Object<'a>, - _: &mut HashMap, - ) -> 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(()) } } @@ -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), - #[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, } diff --git a/macros/src/symbol.rs b/macros/src/symbol.rs index e74d949..e877f73 100644 --- a/macros/src/symbol.rs +++ b/macros/src/symbol.rs @@ -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 } }