#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct AddressRange {
pub start: u64,
pub end: u64,
}
impl AddressRange {
#[must_use]
pub const fn new(start: u64, end: u64) -> Self {
Self { start, end }
}
#[must_use]
pub const fn size(self) -> u64 {
self.end.saturating_sub(self.start)
}
#[must_use]
pub const fn is_valid(self) -> bool {
self.start <= self.end
}
#[must_use]
pub const fn is_empty(self) -> bool {
self.start == self.end
}
#[must_use]
pub const fn contains(self, address: u64) -> bool {
self.is_valid() && self.start <= address && address < self.end
}
#[must_use]
pub const fn contains_range(self, other: Self) -> bool {
self.is_valid() && other.is_valid() && self.start <= other.start && other.end <= self.end
}
}
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
pub struct FileEntry {
pub directory: Vec<u8>,
pub basename: Vec<u8>,
}
impl FileEntry {
#[must_use]
pub fn new(directory: impl Into<Vec<u8>>, basename: impl Into<Vec<u8>>) -> Self {
Self {
directory: directory.into(),
basename: basename.into(),
}
}
}
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct FileIndex(u32);
impl FileIndex {
pub const ZERO: Self = Self(0);
#[must_use]
pub const fn new(index: u32) -> Self {
Self(index)
}
#[must_use]
pub const fn get(self) -> u32 {
self.0
}
}
impl From<u32> for FileIndex {
fn from(index: u32) -> Self {
Self::new(index)
}
}
impl From<FileIndex> for u32 {
fn from(index: FileIndex) -> Self {
index.get()
}
}
impl From<FileIndex> for u64 {
fn from(index: FileIndex) -> Self {
Self::from(index.get())
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct LineEntry {
pub address: u64,
pub file: FileIndex,
pub line: u32,
}
impl LineEntry {
#[must_use]
pub const fn new(address: u64, file: FileIndex, line: u32) -> Self {
Self {
address,
file,
line,
}
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct InlineNode {
pub ranges: Vec<AddressRange>,
pub name: Vec<u8>,
pub call_file: FileIndex,
pub call_line: u32,
pub children: Vec<Self>,
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct CallSite {
pub return_offset: u64,
pub flags: CallSiteFlags,
pub match_regex: Vec<Vec<u8>>,
}
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
#[repr(transparent)]
pub struct CallSiteFlags(u8);
impl CallSiteFlags {
pub const INTERNAL: Self = Self(1 << 0);
pub const EXTERNAL: Self = Self(1 << 1);
#[must_use]
pub const fn from_bits_retain(bits: u8) -> Self {
Self(bits)
}
#[must_use]
pub const fn bits(self) -> u8 {
self.0
}
#[must_use]
pub const fn is_empty(self) -> bool {
self.0 == 0
}
#[must_use]
pub const fn contains(self, flag: Self) -> bool {
self.0 & flag.0 == flag.0
}
}
impl std::ops::BitOr for CallSiteFlags {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self(self.0 | rhs.0)
}
}
impl std::ops::BitOrAssign for CallSiteFlags {
fn bitor_assign(&mut self, rhs: Self) {
self.0 |= rhs.0;
}
}
impl From<u8> for CallSiteFlags {
fn from(value: u8) -> Self {
Self::from_bits_retain(value)
}
}
impl From<CallSiteFlags> for u8 {
fn from(value: CallSiteFlags) -> Self {
value.bits()
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Function {
pub range: AddressRange,
pub name: Vec<u8>,
pub lines: Vec<LineEntry>,
pub inline: Option<InlineNode>,
pub merged: Vec<Self>,
pub call_sites: Vec<CallSite>,
}
impl Function {
#[must_use]
pub fn new(range: AddressRange, name: impl Into<Vec<u8>>) -> Self {
Self {
range,
name: name.into(),
..Self::default()
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub struct LookupFrame<'data> {
pub name: &'data [u8],
pub directory: &'data [u8],
pub basename: &'data [u8],
pub line: u32,
pub offset: u64,
pub inlined: bool,
}
#[derive(Debug, Eq, PartialEq)]
#[non_exhaustive]
pub struct Lookup<'data> {
pub address: u64,
pub function: AddressRange,
frames: Box<[LookupFrame<'data>]>,
call_site_patterns: Box<[&'data [u8]]>,
}
impl<'data> Lookup<'data> {
pub(crate) const fn new(
address: u64,
function: AddressRange,
frames: Box<[LookupFrame<'data>]>,
call_site_patterns: Box<[&'data [u8]]>,
) -> Self {
Self {
address,
function,
frames,
call_site_patterns,
}
}
#[must_use]
pub fn frames(&self) -> &[LookupFrame<'data>] {
&self.frames
}
#[must_use]
pub fn call_site_patterns(&self) -> &[&'data [u8]] {
&self.call_site_patterns
}
}