use std::ops::Range;
pub trait ModuleInfoRecord {
fn avma_range(&self) -> &Range<u64>;
fn is_python(&self) -> bool;
}
pub trait ModuleSource {
type Module: ModuleInfoRecord;
fn modules(&self) -> &[Self::Module];
fn find_module(&self, addr: u64) -> Option<&Self::Module> {
self.modules()
.iter()
.find(|m| m.avma_range().contains(&addr))
}
fn is_python_address(&self, addr: u64) -> bool {
self.find_module(addr)
.is_some_and(ModuleInfoRecord::is_python)
}
}
#[cfg(target_os = "linux")]
pub(crate) fn find_module_by_address_sorted<T: ModuleInfoRecord>(
modules: &[T],
addr: u64,
) -> Option<&T> {
let idx = modules.partition_point(|module| module.avma_range().start <= addr);
let module = modules.get(idx.checked_sub(1)?)?;
module.avma_range().contains(&addr).then_some(module)
}
#[cfg(target_os = "linux")]
pub(crate) fn sort_modules_by_avma_start<T: ModuleInfoRecord>(modules: &mut [T]) {
modules.sort_by_key(|module| module.avma_range().start);
debug_assert!(
modules
.windows(2)
.all(|w| w[0].avma_range().end <= w[1].avma_range().start),
"sorted modules must be non-overlapping for binary search",
);
}