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
- Construct a prober with
new, passing the set of pages already known to be unserviceable (thesuppressedset). - Run one or more reads through
probeor thevmi_probe!macro. Each returnsOk(Some(value))when the read succeeded, orOk(None)when it faulted (the fault is recorded unless it is suppressed). - Call
error_for_page_faults. It returnsErr(VmiError::Translation)carrying every recorded, non-suppressed fault, orOk(())if there were none. Propagate that error to an event loop that injects page faults: for example, returning it from avmi-utilsreactor handler makes the reactor inject the fault so the guest pages the memory in, after which the operation is retried. - Faults that turn out to be permanently unserviceable are added to the
suppressedset by the caller (for instance from aKiDispatchExceptionhandler), 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
impl VmiProber
Sourcepub fn new(suppressed: &IndexSet<AddressContext>) -> Self
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.
Sourcepub fn probe<T, F>(&self, f: F) -> Result<Option<T>, VmiError>
pub fn probe<T, F>(&self, f: F) -> Result<Option<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.
Sourcepub fn check_result<T>(
&self,
result: Result<T, VmiError>,
) -> Result<Option<T>, VmiError>
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.
Sourcepub fn page_faults(&self) -> IndexSet<AddressContext>
pub fn page_faults(&self) -> IndexSet<AddressContext>
Returns the recorded page faults that are not in the suppressed set.
Sourcepub fn error_for_page_faults(&self) -> Result<(), VmiError>
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§
impl !Freeze for VmiProber
impl !RefUnwindSafe for VmiProber
impl !Sync for VmiProber
impl Send for VmiProber
impl Unpin for VmiProber
impl UnsafeUnpin for VmiProber
impl UnwindSafe for VmiProber
Blanket Implementations§
Source§impl<T> ArchivePointee for T
impl<T> ArchivePointee for T
Source§type ArchivedMetadata = ()
type ArchivedMetadata = ()
Source§fn pointer_metadata(
_: &<T as ArchivePointee>::ArchivedMetadata,
) -> <T as Pointee>::Metadata
fn pointer_metadata( _: &<T as ArchivePointee>::ArchivedMetadata, ) -> <T as Pointee>::Metadata
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> LayoutRaw for T
impl<T> LayoutRaw for T
Source§fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
Source§impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
Source§unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
Source§fn resolve_niched(out: Place<NichedOption<T, N1>>)
fn resolve_niched(out: Place<NichedOption<T, N1>>)
out indicating that a T is niched.