pub mod schema;
pub mod visit;
use crate::schema::{
ArchivedArchitecture, ArchivedArray, ArchivedBase, ArchivedBitfield, ArchivedEnum,
ArchivedEnumRef, ArchivedField, ArchivedPointer, ArchivedProfile, ArchivedStruct,
ArchivedStructKind, ArchivedStructRef, ArchivedType, ArchivedVariant,
};
pub struct Profile<'a> {
inner: &'a ArchivedProfile,
rva_to_symbol: Vec<Symbol<'a>>,
}
#[derive(Debug, Clone, Copy)]
pub struct Symbol<'a> {
pub name: &'a str,
pub rva: u64,
}
impl<'a> Profile<'a> {
pub fn from_archived(archived: &'a ArchivedProfile) -> Self {
let mut rva_to_symbol = archived
.symbols
.iter()
.map(|(name, &rva)| Symbol {
name: name.as_ref(),
rva: rva.into(),
})
.collect::<Vec<_>>();
rva_to_symbol.sort_unstable_by_key(|entry| entry.rva);
Self {
inner: archived,
rva_to_symbol,
}
}
pub fn architecture(&self) -> Architecture {
Architecture::from_archived(&self.inner.architecture)
}
pub fn enums(&self) -> impl ExactSizeIterator<Item = Enum<'a>> {
self.inner.enums.iter().map(|(name, inner)| Enum {
name: name.as_ref(),
inner,
})
}
pub fn structs(&self) -> impl ExactSizeIterator<Item = Struct<'a>> {
self.inner.structs.iter().map(|(name, inner)| Struct {
name: name.as_ref(),
inner,
})
}
pub fn symbols(&self) -> impl ExactSizeIterator<Item = Symbol<'a>> {
self.inner.symbols.iter().map(|(name, &rva)| Symbol {
name: name.as_ref(),
rva: rva.into(),
})
}
pub fn type_size(&self, ty: Type<'a>) -> Option<u64> {
match ty {
Type::Base(v) => Some(v.size()),
Type::Enum(v) => self.enum_size(v.name()),
Type::Struct(v) => self.struct_size(v.name()),
Type::Array(v) => self
.type_size(v.subtype())
.map(|subtype_size| subtype_size * v.dims().product::<u64>()),
Type::Pointer(v) => Some(v.size()),
Type::Bitfield(v) => self.type_size(v.subtype()),
Type::Function => Some(self.pointer_size()),
}
}
pub fn enum_size(&self, name: &str) -> Option<u64> {
let ty = Type::from_archived(&self.inner.enums.get(name)?.subtype);
self.type_size(ty)
}
pub fn struct_size(&self, name: &str) -> Option<u64> {
self.inner.structs.get(name).map(|udt| udt.size.into())
}
pub fn pointer_size(&self) -> u64 {
match self.architecture() {
Architecture::X86 | Architecture::Arm32 => 4,
Architecture::Amd64 | Architecture::Arm64 => 8,
Architecture::Unknown => 0,
}
}
pub fn find_enum(&self, type_name: &str) -> Option<Enum<'a>> {
self.inner
.enums
.get_key_value(type_name)
.map(|(name, inner)| Enum {
name: name.as_ref(),
inner,
})
}
pub fn find_struct(&self, type_name: &str) -> Option<Struct<'a>> {
self.inner
.structs
.get_key_value(type_name)
.map(|(name, inner)| Struct {
name: name.as_ref(),
inner,
})
}
pub fn find_symbol(&self, symbol_name: &str) -> Option<u64> {
self.inner.symbols.get(symbol_name).map(Into::into)
}
pub fn lookup_symbol(&self, rva: u64) -> Option<Symbol<'a>> {
let idx = match self.rva_to_symbol.binary_search_by_key(&rva, |e| e.rva) {
Ok(i) => i,
Err(0) => return None,
Err(i) => i - 1,
};
Some(self.rva_to_symbol[idx])
}
}
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Architecture {
Unknown,
X86,
Amd64,
Arm32,
Arm64,
}
impl Architecture {
fn from_archived(value: &ArchivedArchitecture) -> Self {
match value {
ArchivedArchitecture::Unknown => Self::Unknown,
ArchivedArchitecture::X86 => Self::X86,
ArchivedArchitecture::Amd64 => Self::Amd64,
ArchivedArchitecture::Arm32 => Self::Arm32,
ArchivedArchitecture::Arm64 => Self::Arm64,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct Enum<'a> {
name: &'a str,
inner: &'a ArchivedEnum,
}
impl<'a> Enum<'a> {
pub fn name(&self) -> &'a str {
self.name
}
pub fn subtype(&self) -> Type<'a> {
Type::from_archived(&self.inner.subtype)
}
pub fn fields(&self) -> impl ExactSizeIterator<Item = (&'a str, Variant)> {
self.inner
.fields
.iter()
.map(|(name, variant)| (name.as_ref(), Variant::from_archived(variant)))
}
}
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Variant {
U8(u8),
U16(u16),
U32(u32),
U64(u64),
U128(u128),
I8(i8),
I16(i16),
I32(i32),
I64(i64),
I128(i128),
}
impl Variant {
fn from_archived(value: &ArchivedVariant) -> Self {
match value {
ArchivedVariant::U8(v) => Self::U8(*v),
ArchivedVariant::U16(v) => Self::U16(v.into()),
ArchivedVariant::U32(v) => Self::U32(v.into()),
ArchivedVariant::U64(v) => Self::U64(v.into()),
ArchivedVariant::U128(v) => Self::U128(v.into()),
ArchivedVariant::I8(v) => Self::I8(*v),
ArchivedVariant::I16(v) => Self::I16(v.into()),
ArchivedVariant::I32(v) => Self::I32(v.into()),
ArchivedVariant::I64(v) => Self::I64(v.into()),
ArchivedVariant::I128(v) => Self::I128(v.into()),
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct Struct<'a> {
name: &'a str,
inner: &'a ArchivedStruct,
}
impl<'a> Struct<'a> {
pub fn name(&self) -> &'a str {
self.name
}
pub fn kind(&self) -> StructKind {
StructKind::from_archived(&self.inner.kind)
}
pub fn size(&self) -> u64 {
self.inner.size.into()
}
pub fn field(&self, name: &str) -> Option<Field<'a>> {
self.inner
.fields
.get_key_value(name)
.map(|(name, field)| Field {
name: name.as_ref(),
inner: field,
})
}
pub fn fields(&self) -> impl ExactSizeIterator<Item = Field<'a>> {
self.inner.fields.iter().map(|(name, inner)| Field {
name: name.as_ref(),
inner,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum StructKind {
Struct,
Class,
Union,
Interface,
}
impl StructKind {
fn from_archived(value: &ArchivedStructKind) -> Self {
match value {
ArchivedStructKind::Struct => Self::Struct,
ArchivedStructKind::Class => Self::Class,
ArchivedStructKind::Union => Self::Union,
ArchivedStructKind::Interface => Self::Interface,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct Field<'a> {
name: &'a str,
inner: &'a ArchivedField,
}
impl<'a> Field<'a> {
pub fn name(&self) -> &'a str {
self.name
}
pub fn offset(&self) -> u64 {
self.inner.offset.into()
}
pub fn ty(&self) -> Type<'a> {
Type::from_archived(&self.inner.ty)
}
}
#[derive(Debug, Clone, Copy)]
pub enum Type<'a> {
Base(Base),
Enum(EnumRef<'a>),
Struct(StructRef<'a>),
Array(Array<'a>),
Pointer(Pointer<'a>),
Bitfield(Bitfield<'a>),
Function,
}
impl<'a> Type<'a> {
fn from_archived(value: &'a ArchivedType) -> Self {
match value {
ArchivedType::Base(inner) => Self::Base(Base::from_archived(inner)),
ArchivedType::Enum(inner) => Self::Enum(EnumRef { inner }),
ArchivedType::Struct(inner) => Self::Struct(StructRef { inner }),
ArchivedType::Array(inner) => Self::Array(Array { inner }),
ArchivedType::Pointer(inner) => Self::Pointer(Pointer { inner }),
ArchivedType::Bitfield(inner) => Self::Bitfield(Bitfield { inner }),
ArchivedType::Function => Self::Function,
}
}
}
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Base {
Void,
Bool,
Char8,
Char16,
Char32,
I8,
I16,
I32,
I64,
I128,
U8,
U16,
U32,
U64,
U128,
F8,
F16,
F32,
F64,
F128,
}
impl Base {
fn from_archived(value: &ArchivedBase) -> Self {
match value {
ArchivedBase::Void => Self::Void,
ArchivedBase::Bool => Self::Bool,
ArchivedBase::Char8 => Self::Char8,
ArchivedBase::Char16 => Self::Char16,
ArchivedBase::Char32 => Self::Char32,
ArchivedBase::I8 => Self::I8,
ArchivedBase::I16 => Self::I16,
ArchivedBase::I32 => Self::I32,
ArchivedBase::I64 => Self::I64,
ArchivedBase::I128 => Self::I128,
ArchivedBase::U8 => Self::U8,
ArchivedBase::U16 => Self::U16,
ArchivedBase::U32 => Self::U32,
ArchivedBase::U64 => Self::U64,
ArchivedBase::U128 => Self::U128,
ArchivedBase::F8 => Self::F8,
ArchivedBase::F16 => Self::F16,
ArchivedBase::F32 => Self::F32,
ArchivedBase::F64 => Self::F64,
ArchivedBase::F128 => Self::F128,
}
}
pub fn size(&self) -> u64 {
match self {
Self::Void => 0,
Self::Char8 | Self::I8 | Self::U8 | Self::F8 | Self::Bool => 1,
Self::Char16 | Self::I16 | Self::U16 | Self::F16 => 2,
Self::Char32 | Self::I32 | Self::U32 | Self::F32 => 4,
Self::I64 | Self::U64 | Self::F64 => 8,
Self::I128 | Self::U128 | Self::F128 => 16,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct EnumRef<'a> {
inner: &'a ArchivedEnumRef,
}
impl<'a> EnumRef<'a> {
pub fn name(&self) -> &'a str {
&self.inner.name
}
}
#[derive(Debug, Clone, Copy)]
pub struct StructRef<'a> {
inner: &'a ArchivedStructRef,
}
impl<'a> StructRef<'a> {
pub fn name(&self) -> &'a str {
&self.inner.name
}
}
#[derive(Debug, Clone, Copy)]
pub struct Array<'a> {
inner: &'a ArchivedArray,
}
impl<'a> Array<'a> {
pub fn subtype(&self) -> Type<'a> {
Type::from_archived(self.inner.subtype.as_ref())
}
pub fn dims(&self) -> impl Iterator<Item = u64> + use<'a> {
self.inner.dims.iter().map(|&dim| dim.to_native())
}
}
#[derive(Debug, Clone, Copy)]
pub struct Bitfield<'a> {
inner: &'a ArchivedBitfield,
}
impl<'a> Bitfield<'a> {
pub fn subtype(&self) -> Type<'a> {
Type::from_archived(self.inner.subtype.as_ref())
}
pub fn bit_length(&self) -> u64 {
self.inner.bit_length.into()
}
pub fn bit_position(&self) -> u64 {
self.inner.bit_position.into()
}
}
#[derive(Debug, Clone, Copy)]
pub struct Pointer<'a> {
inner: &'a ArchivedPointer,
}
impl<'a> Pointer<'a> {
pub fn subtype(&self) -> Type<'a> {
Type::from_archived(self.inner.subtype.as_ref())
}
pub fn size(&self) -> u64 {
self.inner.size.into()
}
}