use std::iter::FusedIterator;
use vmi_core::{Pa, Registers as _, Va, VmiError, VmiState, driver::VmiRead};
use crate::{
WindowsOs, WindowsWow64Kind,
arch::{ArchAdapter, StructLayout, StructLayout32, StructLayout64},
};
pub trait ListEntry<Layout>
where
Layout: StructLayout,
{
const OFFSET_FLINK: u64;
const OFFSET_BLINK: u64;
}
pub struct ListEntryLayout;
impl ListEntry<StructLayout32> for ListEntryLayout {
const OFFSET_FLINK: u64 = 0x00;
const OFFSET_BLINK: u64 = 0x04;
}
impl ListEntry<StructLayout64> for ListEntryLayout {
const OFFSET_FLINK: u64 = 0x00;
const OFFSET_BLINK: u64 = 0x08;
}
pub struct ListEntryIteratorBase<'a, Driver, Layout>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
Layout: StructLayout,
ListEntryLayout: ListEntry<Layout>,
{
vmi: VmiState<'a, WindowsOs<Driver>>,
list_head: Va,
offset: u64,
root: Pa,
current: Option<Va>,
initialized: bool,
_marker: std::marker::PhantomData<Layout>,
}
impl<'a, Driver, Layout> ListEntryIteratorBase<'a, Driver, Layout>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
Layout: StructLayout,
ListEntryLayout: ListEntry<Layout>,
{
pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, list_head: Va, offset: u64, root: Pa) -> Self {
Self {
vmi,
list_head,
offset,
root,
current: None,
initialized: false,
_marker: std::marker::PhantomData,
}
}
fn next_entry(&self, entry: Va) -> Result<Va, VmiError> {
Layout::read_va(
self.vmi,
(
entry + <ListEntryLayout as ListEntry<Layout>>::OFFSET_FLINK,
self.root,
),
)
}
fn previous_entry(&self, entry: Va) -> Result<Va, VmiError> {
Layout::read_va(
self.vmi,
(
entry + <ListEntryLayout as ListEntry<Layout>>::OFFSET_BLINK,
self.root,
),
)
}
fn first_entry(&self) -> Result<Option<Va>, VmiError> {
if self.list_head.is_null() {
return Ok(None);
}
Ok(Some(self.next_entry(self.list_head)?))
}
fn last_entry(&self) -> Result<Option<Va>, VmiError> {
if self.list_head.is_null() {
return Ok(None);
}
Ok(Some(self.previous_entry(self.list_head)?))
}
fn walk_next(&mut self) -> Result<Option<Va>, VmiError> {
let entry = match self.current {
Some(entry) => entry,
None => {
if self.initialized {
return Ok(None);
}
self.initialized = true;
match self.first_entry() {
Ok(Some(first)) => first,
Ok(None) => return Ok(None),
Err(err) => return Err(err),
}
}
};
if entry == self.list_head {
return Ok(None);
}
match self.next_entry(entry) {
Ok(next) => self.current = Some(next),
Err(err) => {
self.current = None;
return Err(err);
}
}
Ok(Some(entry - self.offset))
}
fn walk_next_back(&mut self) -> Result<Option<Va>, VmiError> {
let entry = match self.current {
Some(entry) => entry,
None => {
if self.initialized {
return Ok(None);
}
self.initialized = true;
match self.last_entry() {
Ok(Some(last)) => last,
Ok(None) => return Ok(None),
Err(err) => return Err(err),
}
}
};
if entry == self.list_head {
return Ok(None);
}
match self.previous_entry(entry) {
Ok(prev) => self.current = Some(prev),
Err(err) => {
self.current = None;
return Err(err);
}
}
Ok(Some(entry - self.offset))
}
}
impl<Driver, Layout> Iterator for ListEntryIteratorBase<'_, Driver, Layout>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
Layout: StructLayout,
ListEntryLayout: ListEntry<Layout>,
{
type Item = Result<Va, VmiError>;
fn next(&mut self) -> Option<Self::Item> {
self.walk_next().transpose()
}
}
impl<Driver, Layout> DoubleEndedIterator for ListEntryIteratorBase<'_, Driver, Layout>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
Layout: StructLayout,
ListEntryLayout: ListEntry<Layout>,
{
fn next_back(&mut self) -> Option<Self::Item> {
self.walk_next_back().transpose()
}
}
impl<Driver, Layout> FusedIterator for ListEntryIteratorBase<'_, Driver, Layout>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
Layout: StructLayout,
ListEntryLayout: ListEntry<Layout>,
{
}
enum ListEntryWrapper<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
W32(ListEntryIteratorBase<'a, Driver, StructLayout32>),
W64(ListEntryIteratorBase<'a, Driver, StructLayout64>),
}
impl<'a, Driver> ListEntryWrapper<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
fn w32(vmi: VmiState<'a, WindowsOs<Driver>>, list_head: Va, offset: u64, root: Pa) -> Self {
Self::W32(ListEntryIteratorBase::new(vmi, list_head, offset, root))
}
fn w64(vmi: VmiState<'a, WindowsOs<Driver>>, list_head: Va, offset: u64, root: Pa) -> Self {
Self::W64(ListEntryIteratorBase::new(vmi, list_head, offset, root))
}
fn native(vmi: VmiState<'a, WindowsOs<Driver>>, list_head: Va, offset: u64, root: Pa) -> Self {
match vmi.registers().address_width() {
4 => Self::w32(vmi, list_head, offset, root),
8 => Self::w64(vmi, list_head, offset, root),
_ => panic!("Unsupported address width"),
}
}
fn walk_next(&mut self) -> Result<Option<Va>, VmiError> {
match self {
Self::W32(inner) => inner.walk_next(),
Self::W64(inner) => inner.walk_next(),
}
}
fn walk_next_back(&mut self) -> Result<Option<Va>, VmiError> {
match self {
Self::W32(inner) => inner.walk_next_back(),
Self::W64(inner) => inner.walk_next_back(),
}
}
}
pub struct ListEntryIterator<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
inner: ListEntryWrapper<'a, Driver>,
}
impl<'a, Driver> From<ListEntryIteratorBase<'a, Driver, StructLayout32>>
for ListEntryIterator<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
fn from(value: ListEntryIteratorBase<'a, Driver, StructLayout32>) -> Self {
Self {
inner: ListEntryWrapper::W32(value),
}
}
}
impl<'a, Driver> From<ListEntryIteratorBase<'a, Driver, StructLayout64>>
for ListEntryIterator<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
fn from(value: ListEntryIteratorBase<'a, Driver, StructLayout64>) -> Self {
Self {
inner: ListEntryWrapper::W64(value),
}
}
}
impl<'a, Driver> ListEntryIterator<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, list_head: Va, offset: u64) -> Self {
Self::with_kind(
vmi,
list_head,
offset,
vmi.translation_root(list_head),
WindowsWow64Kind::Native,
)
}
pub fn with_kind(
vmi: VmiState<'a, WindowsOs<Driver>>,
list_head: Va,
offset: u64,
root: Pa,
kind: WindowsWow64Kind,
) -> Self {
let inner = match kind {
WindowsWow64Kind::Native => ListEntryWrapper::native(vmi, list_head, offset, root),
WindowsWow64Kind::X86 => ListEntryWrapper::w32(vmi, list_head, offset, root),
};
Self { inner }
}
fn walk_next(&mut self) -> Result<Option<Va>, VmiError> {
self.inner.walk_next()
}
fn walk_next_back(&mut self) -> Result<Option<Va>, VmiError> {
self.inner.walk_next_back()
}
}
impl<Driver> Iterator for ListEntryIterator<'_, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
type Item = Result<Va, VmiError>;
fn next(&mut self) -> Option<Self::Item> {
self.walk_next().transpose()
}
}
impl<Driver> DoubleEndedIterator for ListEntryIterator<'_, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
fn next_back(&mut self) -> Option<Self::Item> {
self.walk_next_back().transpose()
}
}
impl<Driver> FusedIterator for ListEntryIterator<'_, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
}