Skip to main content

VmiProber

Struct VmiProber 

Source
pub struct VmiProber { /* private fields */ }
Expand description

Batches the page faults raised by a sequence of memory reads so they can be injected together, while skipping pages already known to be unserviceable.

A read that touches a non-resident page returns VmiError::Translation. Instead of aborting an operation on the first such fault, the prober lets you run a sequence of reads: each probed read that faults yields Ok(None) and its faulting address is recorded, unless that address is in the suppressed set, in which case it is ignored.

§Protocol

  1. Construct a prober with new, passing the set of pages already known to be unserviceable (the suppressed set).
  2. Run one or more reads through probe or the vmi_probe! macro. Each returns Ok(Some(value)) when the read succeeded, or Ok(None) when it faulted (the fault is recorded unless it is suppressed).
  3. Call error_for_page_faults. It returns Err(VmiError::Translation) carrying every recorded, non-suppressed fault, or Ok(()) if there were none. Propagate that error to an event loop that injects page faults: for example, returning it from a vmi-utils reactor handler makes the reactor inject the fault so the guest pages the memory in, after which the operation is retried.
  4. Faults that turn out to be permanently unserviceable are added to the suppressed set by the caller (for instance from a KiDispatchException handler), so a later attempt skips them instead of re-injecting forever.

§Examples

// `suppressed` holds pages a previous round found unserviceable.
let prober = VmiProber::new(&suppressed);

// Each probed read is `Ok(Some(_))` if resident, `Ok(None)` if it faulted.
let header = vmi_probe!(prober, vmi.read_struct::<Header>(address))?;
let name = vmi_probe!(prober, vmi.read_string(name_address))?;

// Surface the accumulated, non-suppressed faults. Returning this error from
// a reactor handler injects the fault and retries the operation.
prober.error_for_page_faults()?;

// No faults pending: `header` and `name` are `Some` (or `None` for a
// suppressed page) and safe to use.

Implementations§

Source§

impl VmiProber

Source

pub fn new(suppressed: &IndexSet<AddressContext>) -> Self

Creates a prober that suppresses faults on the given pages.

suppressed is the set of pages already known to be unserviceable (typically discovered by an earlier round and recorded by an exception handler). Faults on them are ignored rather than reported by error_for_page_faults.

Source

pub fn probe<T, F>(&self, f: F) -> Result<Option<T>, VmiError>
where F: FnOnce() -> Result<T, VmiError>,

Runs f and records any page fault it raises, returning Ok(None) on a fault instead of propagating it.

Equivalent to check_result applied to f(). See the type-level protocol for how to surface the recorded faults.

Source

pub fn check_result<T>( &self, result: Result<T, VmiError>, ) -> Result<Option<T>, VmiError>

Records a page fault carried by result and returns Ok(None) instead of propagating it, so the caller can keep probing further reads.

A successful result becomes Ok(Some(value)). A VmiError::Translation is recorded (unless its address is suppressed) and becomes Ok(None). Any other error is propagated unchanged. Call error_for_page_faults afterwards to surface the recorded faults for injection.

Source

pub fn page_faults(&self) -> IndexSet<AddressContext>

Returns the recorded page faults that are not in the suppressed set.

Source

pub fn error_for_page_faults(&self) -> Result<(), VmiError>

Returns Err(VmiError::Translation) carrying the recorded, non-suppressed page faults, or Ok(()) if none occurred.

The returned error is meant to be propagated to a page-fault-injecting event loop (such as the vmi-utils reactor). Injecting these faults pages the memory in so the probed operation can be retried.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> ArchivePointee for T

Source§

type ArchivedMetadata = ()

The archived version of the pointer metadata for this type.
Source§

fn pointer_metadata( _: &<T as ArchivePointee>::ArchivedMetadata, ) -> <T as Pointee>::Metadata

Converts some archived metadata to the pointer metadata for itself.
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> LayoutRaw for T

Source§

fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>

Returns the layout of the type.
Source§

impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
where T: SharedNiching<N1, N2>, N1: Niching<T>, N2: Niching<T>,

Source§

unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool

Returns whether the given value has been niched. Read more
Source§

fn resolve_niched(out: Place<NichedOption<T, N1>>)

Writes data to out indicating that a T is niched.
Source§

impl<T> Pointee for T

Source§

type Metadata = ()

The metadata type for pointers and references to this type.
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more