Skip to main content

PageTableMonitor

Struct PageTableMonitor 

Source
pub struct PageTableMonitor<Driver, Tag = &'static str>
where Driver: VmiRead + VmiQueryProtection + VmiSetProtection, <Driver as VmiDriver>::Architecture: ArchAdapter<Driver, Tag>, Tag: TagType,
{ /* private fields */ }
Available on crate features ptm and utils only.
Expand description

Architecture-independent page table monitor.

Thin wrapper that delegates to an architecture-specific implementation selected via ArchAdapter.

Implementations§

Source§

impl<Driver, Tag> PageTableMonitor<Driver, Tag>
where Driver: VmiRead + VmiQueryProtection + VmiSetProtection, <Driver as VmiDriver>::Architecture: ArchAdapter<Driver, Tag>, Tag: TagType,

Source

pub fn new() -> PageTableMonitor<Driver, Tag>

Creates a new page table monitor.

Examples found in repository?
examples/windows-bridge/monitor/mod.rs (line 184)
161    pub fn new(
162        session: &VmiSession<WindowsOs<Driver>>,
163        profile: &Profile,
164        terminate_flag: Arc<AtomicBool>,
165        output_directory: PathBuf,
166    ) -> Result<Self, VmiError> {
167        let paused = session.pause_guard()?;
168        let vmi = paused.state();
169
170        let kernel_image_base = vmi.os().kernel_image_base()?;
171        let root = vmi.os().system_process()?.translation_root()?;
172        let symbols = Symbols::new(profile)?;
173
174        vmi.monitor_enable(EventMonitor::Interrupt(ExceptionVector::Breakpoint))?;
175        vmi.monitor_enable(EventMonitor::Singlestep)?;
176        vmi.monitor_enable(EventMonitor::Hypercall {
177            allow_userspace: true,
178        })?;
179
180        let view = vmi.create_view(MemoryAccess::RWX)?;
181        vmi.switch_to_view(view)?;
182
183        let mut bpm = BreakpointManager::new();
184        let mut ptm = PageTableMonitor::new();
185
186        macro_rules! install {
187            ($($name:ident),+ $(,)?) => {
188                $(
189                    let va = kernel_image_base + symbols.$name;
190                    let context = (va, root);
191                    let hook = MonitorHook {
192                        name: stringify!($name),
193                        callback: self::hooks::$name::<Driver>,
194                    };
195                    let breakpoint = Breakpoint::new(context, view).global().with_tag(hook);
196                    bpm.insert(&vmi, breakpoint)?;
197                    ptm.monitor(&vmi, context, view, hook)?;
198                    tracing::debug!(
199                        ?hook,
200                        %va,
201                        "installed monitor hook"
202                    );
203                )+
204            };
205        }
206
207        install!(
208            PspInsertProcess,
209            PspInsertThread,
210            KeTerminateThread,
211            MmCleanProcessAddressSpace,
212            NtWriteFile,
213            NtClose,
214        );
215
216        Ok(Self {
217            terminate_flag,
218            view,
219            bpm,
220            ptm,
221            bridge: Bridge::new((
222                DeployBridge::new(
223                    DeployPolicy::default().execute_response(ExecuteResponse::ContinueAndNotify),
224                ),
225                FileTransferBridge::new(output_directory),
226            )),
227            state: MonitorState {
228                tracker: Tracker::default(),
229                creator_thread: None,
230                target_process: None,
231                output: None,
232            },
233        })
234    }
More examples
Hide additional examples
examples/windows-breakpoint-manager.rs (line 183)
68    pub fn new(
69        session: &VmiSession<WindowsOs<Driver>>,
70        profile: &Profile,
71        terminate_flag: Arc<AtomicBool>,
72    ) -> Result<Self, VmiError> {
73        // Capture the current state of the vCPU and get the base address of
74        // the kernel.
75        //
76        // This base address is essential to correctly offset monitored
77        // functions.
78        //
79        // NOTE: `kernel_image_base` tries to find the kernel in the memory
80        //       with the help of the CPU registers. On AMD64 architecture,
81        //       the kernel image base is usually found using the `MSR_LSTAR`
82        //       register, which contains the address of the system call
83        //       handler. This register is set by the operating system during
84        //       boot and is left unchanged (unless some rootkits are involved).
85        //
86        //       Therefore, we can take an arbitrary registers at any point
87        //       in time (as long as the OS has booted and the page tables are
88        //       set up) and use them to find the kernel image base.
89        let registers = session.registers(VcpuId(0))?;
90        let vmi = session.with_registers(&registers);
91
92        let kernel_image_base = vmi.os().kernel_image_base()?;
93        tracing::info!(%kernel_image_base);
94
95        // Get the system process.
96        //
97        // The system process is the first process created by the kernel.
98        // In Windows, it is referenced by the kernel symbol `PsInitialSystemProcess`.
99        // To monitor page table entries, we need to locate the translation root
100        // of this process.
101        let system_process = vmi.os().system_process()?;
102        tracing::info!(system_process = %system_process.object()?);
103
104        // Get the translation root of the system process.
105        // This is effectively "the CR3 of the kernel".
106        //
107        // The translation root is the root of the page table hierarchy (also
108        // known as the Directory Table Base or PML4).
109        let root = system_process.translation_root()?;
110        tracing::info!(%root);
111
112        // Load the symbols from the profile.
113        let symbols = Symbols::new(profile)?;
114
115        // Enable monitoring of the INT3 and singlestep events.
116        //
117        // INT3 is used to monitor the execution of specific functions.
118        // Singlestep is used to monitor the modifications of page table
119        // entries.
120        vmi.monitor_enable(EventMonitor::Interrupt(ExceptionVector::Breakpoint))?;
121        vmi.monitor_enable(EventMonitor::Singlestep)?;
122
123        // Create a new view for the monitor.
124        // This view is used for monitoring function calls and memory accesses.
125        let view = vmi.create_view(MemoryAccess::RWX)?;
126        vmi.switch_to_view(view)?;
127
128        // Create a new breakpoint controller.
129        //
130        // The breakpoint controller is used to insert breakpoints for specific
131        // functions.
132        //
133        // From the guest's perspective, these breakpoints are "hidden", since
134        // the breakpoint controller will unset the read/write access to the
135        // physical memory page where the breakpoint is inserted, while keeping
136        // the execute access.
137        //
138        // This way, the guest will be able to execute the code, but attempts to
139        // read or write the memory will trigger the `memory_access` callback.
140        //
141        // When a vCPU tries to execute the breakpoint instruction:
142        // - an `interrupt` callback will be triggered
143        // - the breakpoint will be handled (e.g., log the function call)
144        // - a fast-singlestep[1] will be performed over the INT3 instruction
145        //
146        // When a vCPU tries to read from this page (e.g., a PatchGuard check):
147        // - `memory_access` callback will be triggered (with the `MemoryAccess::R`
148        //   access type)
149        // - fast-singlestep[1] will be performed over the instruction that tried to
150        //   read the memory
151        //
152        // This way, the instruction will read the original memory content.
153        //
154        // [1] Fast-singlestep is a VMI feature that allows to switch the vCPU
155        //     to a different view, execute a single instruction, and then
156        //     switch back to the original view. In this case, the view is
157        //     switched to the `default_view` (which is unmodified).
158        let mut bpm = BreakpointManager::new();
159
160        // Create a new page table monitor.
161        //
162        // The page table monitor is used to monitor the page table entries of
163        // the hooked functions.
164        //
165        // More specifically, it is used to monitor the pages that the breakpoint
166        // was inserted into. This is necessary to handle the case when the
167        // page containing the breakpoint is paged out (and then paged in
168        // again).
169        //
170        // `PageTableMonitor` works by unsetting the write access to the page
171        // tables of the hooked functions. When the page is paged out, the
172        // `PRESENT` bit in the page table entry is unset and, conversely, when
173        // the page is paged in, the `PRESENT` bit is set again.
174        //
175        // When that happens:
176        // - the `memory_access` callback will be triggered (with the `MemoryAccess::R`
177        //   access type)
178        // - the callback will mark the page as dirty in the page table monitor
179        // - a singlestep will be performed over the instruction that tried to modify
180        //   the memory containing the page table entry
181        // - the `singlestep` handler will process the dirty page table entries and
182        //   inform the breakpoint controller to handle the changes
183        let mut ptm = PageTableMonitor::new();
184
185        // Pause the VM to avoid race conditions between inserting breakpoints
186        // and monitoring page table entries. The VM resumes when the pause
187        // guard is dropped.
188        let _pause_guard = vmi.pause_guard()?;
189
190        // Insert breakpoint for the `NtCreateFile` function.
191        let va_NtCreateFile = kernel_image_base + symbols.NtCreateFile;
192        let cx_NtCreateFile = (va_NtCreateFile, root);
193        let bp_NtCreateFile = Breakpoint::new(cx_NtCreateFile, view)
194            .global()
195            .with_tag("NtCreateFile");
196        bpm.insert(&vmi, bp_NtCreateFile)?;
197        ptm.monitor(&vmi, cx_NtCreateFile, view, "NtCreateFile")?;
198        tracing::info!(%va_NtCreateFile);
199
200        // Insert breakpoint for the `NtWriteFile` function.
201        let va_NtWriteFile = kernel_image_base + symbols.NtWriteFile;
202        let cx_NtWriteFile = (va_NtWriteFile, root);
203        let bp_NtWriteFile = Breakpoint::new(cx_NtWriteFile, view)
204            .global()
205            .with_tag("NtWriteFile");
206        bpm.insert(&vmi, bp_NtWriteFile)?;
207        ptm.monitor(&vmi, cx_NtWriteFile, view, "NtWriteFile")?;
208        tracing::info!(%va_NtWriteFile);
209
210        // Insert breakpoint for the `PspInsertProcess` function.
211        let va_PspInsertProcess = kernel_image_base + symbols.PspInsertProcess;
212        let cx_PspInsertProcess = (va_PspInsertProcess, root);
213        let bp_PspInsertProcess = Breakpoint::new(cx_PspInsertProcess, view)
214            .global()
215            .with_tag("PspInsertProcess");
216        bpm.insert(&vmi, bp_PspInsertProcess)?;
217        ptm.monitor(&vmi, cx_PspInsertProcess, view, "PspInsertProcess")?;
218
219        // Insert breakpoint for the `MmCleanProcessAddressSpace` function.
220        let va_MmCleanProcessAddressSpace = kernel_image_base + symbols.MmCleanProcessAddressSpace;
221        let cx_MmCleanProcessAddressSpace = (va_MmCleanProcessAddressSpace, root);
222        let bp_MmCleanProcessAddressSpace = Breakpoint::new(cx_MmCleanProcessAddressSpace, view)
223            .global()
224            .with_tag("MmCleanProcessAddressSpace");
225        bpm.insert(&vmi, bp_MmCleanProcessAddressSpace)?;
226        ptm.monitor(
227            &vmi,
228            cx_MmCleanProcessAddressSpace,
229            view,
230            "MmCleanProcessAddressSpace",
231        )?;
232
233        Ok(Self {
234            terminate_flag,
235            view,
236            bpm,
237            ptm,
238        })
239    }
Source

pub fn monitored_tables(&self) -> usize

Returns the number of write-protected page table pages.

Source

pub fn monitored_entries(&self) -> usize

Returns the number of monitored entries.

Source

pub fn paged_in_entries(&self) -> usize

Returns the number of monitored addresses currently backed by physical memory.

Source

pub fn dump(&self)

Logs the monitor state for debugging.

Source

pub fn monitor( &mut self, vmi: &VmiCore<Driver>, ctx: impl Into<AddressContext>, view: View, tag: Tag, ) -> Result<(), VmiError>

Acquires a reference to monitoring a virtual address for page table changes.

On the first reference, walks the page table hierarchy and write-protects the relevant pages. Repeated calls for the same address and view increment its reference count.

Examples found in repository?
examples/windows-breakpoint-manager.rs (line 197)
68    pub fn new(
69        session: &VmiSession<WindowsOs<Driver>>,
70        profile: &Profile,
71        terminate_flag: Arc<AtomicBool>,
72    ) -> Result<Self, VmiError> {
73        // Capture the current state of the vCPU and get the base address of
74        // the kernel.
75        //
76        // This base address is essential to correctly offset monitored
77        // functions.
78        //
79        // NOTE: `kernel_image_base` tries to find the kernel in the memory
80        //       with the help of the CPU registers. On AMD64 architecture,
81        //       the kernel image base is usually found using the `MSR_LSTAR`
82        //       register, which contains the address of the system call
83        //       handler. This register is set by the operating system during
84        //       boot and is left unchanged (unless some rootkits are involved).
85        //
86        //       Therefore, we can take an arbitrary registers at any point
87        //       in time (as long as the OS has booted and the page tables are
88        //       set up) and use them to find the kernel image base.
89        let registers = session.registers(VcpuId(0))?;
90        let vmi = session.with_registers(&registers);
91
92        let kernel_image_base = vmi.os().kernel_image_base()?;
93        tracing::info!(%kernel_image_base);
94
95        // Get the system process.
96        //
97        // The system process is the first process created by the kernel.
98        // In Windows, it is referenced by the kernel symbol `PsInitialSystemProcess`.
99        // To monitor page table entries, we need to locate the translation root
100        // of this process.
101        let system_process = vmi.os().system_process()?;
102        tracing::info!(system_process = %system_process.object()?);
103
104        // Get the translation root of the system process.
105        // This is effectively "the CR3 of the kernel".
106        //
107        // The translation root is the root of the page table hierarchy (also
108        // known as the Directory Table Base or PML4).
109        let root = system_process.translation_root()?;
110        tracing::info!(%root);
111
112        // Load the symbols from the profile.
113        let symbols = Symbols::new(profile)?;
114
115        // Enable monitoring of the INT3 and singlestep events.
116        //
117        // INT3 is used to monitor the execution of specific functions.
118        // Singlestep is used to monitor the modifications of page table
119        // entries.
120        vmi.monitor_enable(EventMonitor::Interrupt(ExceptionVector::Breakpoint))?;
121        vmi.monitor_enable(EventMonitor::Singlestep)?;
122
123        // Create a new view for the monitor.
124        // This view is used for monitoring function calls and memory accesses.
125        let view = vmi.create_view(MemoryAccess::RWX)?;
126        vmi.switch_to_view(view)?;
127
128        // Create a new breakpoint controller.
129        //
130        // The breakpoint controller is used to insert breakpoints for specific
131        // functions.
132        //
133        // From the guest's perspective, these breakpoints are "hidden", since
134        // the breakpoint controller will unset the read/write access to the
135        // physical memory page where the breakpoint is inserted, while keeping
136        // the execute access.
137        //
138        // This way, the guest will be able to execute the code, but attempts to
139        // read or write the memory will trigger the `memory_access` callback.
140        //
141        // When a vCPU tries to execute the breakpoint instruction:
142        // - an `interrupt` callback will be triggered
143        // - the breakpoint will be handled (e.g., log the function call)
144        // - a fast-singlestep[1] will be performed over the INT3 instruction
145        //
146        // When a vCPU tries to read from this page (e.g., a PatchGuard check):
147        // - `memory_access` callback will be triggered (with the `MemoryAccess::R`
148        //   access type)
149        // - fast-singlestep[1] will be performed over the instruction that tried to
150        //   read the memory
151        //
152        // This way, the instruction will read the original memory content.
153        //
154        // [1] Fast-singlestep is a VMI feature that allows to switch the vCPU
155        //     to a different view, execute a single instruction, and then
156        //     switch back to the original view. In this case, the view is
157        //     switched to the `default_view` (which is unmodified).
158        let mut bpm = BreakpointManager::new();
159
160        // Create a new page table monitor.
161        //
162        // The page table monitor is used to monitor the page table entries of
163        // the hooked functions.
164        //
165        // More specifically, it is used to monitor the pages that the breakpoint
166        // was inserted into. This is necessary to handle the case when the
167        // page containing the breakpoint is paged out (and then paged in
168        // again).
169        //
170        // `PageTableMonitor` works by unsetting the write access to the page
171        // tables of the hooked functions. When the page is paged out, the
172        // `PRESENT` bit in the page table entry is unset and, conversely, when
173        // the page is paged in, the `PRESENT` bit is set again.
174        //
175        // When that happens:
176        // - the `memory_access` callback will be triggered (with the `MemoryAccess::R`
177        //   access type)
178        // - the callback will mark the page as dirty in the page table monitor
179        // - a singlestep will be performed over the instruction that tried to modify
180        //   the memory containing the page table entry
181        // - the `singlestep` handler will process the dirty page table entries and
182        //   inform the breakpoint controller to handle the changes
183        let mut ptm = PageTableMonitor::new();
184
185        // Pause the VM to avoid race conditions between inserting breakpoints
186        // and monitoring page table entries. The VM resumes when the pause
187        // guard is dropped.
188        let _pause_guard = vmi.pause_guard()?;
189
190        // Insert breakpoint for the `NtCreateFile` function.
191        let va_NtCreateFile = kernel_image_base + symbols.NtCreateFile;
192        let cx_NtCreateFile = (va_NtCreateFile, root);
193        let bp_NtCreateFile = Breakpoint::new(cx_NtCreateFile, view)
194            .global()
195            .with_tag("NtCreateFile");
196        bpm.insert(&vmi, bp_NtCreateFile)?;
197        ptm.monitor(&vmi, cx_NtCreateFile, view, "NtCreateFile")?;
198        tracing::info!(%va_NtCreateFile);
199
200        // Insert breakpoint for the `NtWriteFile` function.
201        let va_NtWriteFile = kernel_image_base + symbols.NtWriteFile;
202        let cx_NtWriteFile = (va_NtWriteFile, root);
203        let bp_NtWriteFile = Breakpoint::new(cx_NtWriteFile, view)
204            .global()
205            .with_tag("NtWriteFile");
206        bpm.insert(&vmi, bp_NtWriteFile)?;
207        ptm.monitor(&vmi, cx_NtWriteFile, view, "NtWriteFile")?;
208        tracing::info!(%va_NtWriteFile);
209
210        // Insert breakpoint for the `PspInsertProcess` function.
211        let va_PspInsertProcess = kernel_image_base + symbols.PspInsertProcess;
212        let cx_PspInsertProcess = (va_PspInsertProcess, root);
213        let bp_PspInsertProcess = Breakpoint::new(cx_PspInsertProcess, view)
214            .global()
215            .with_tag("PspInsertProcess");
216        bpm.insert(&vmi, bp_PspInsertProcess)?;
217        ptm.monitor(&vmi, cx_PspInsertProcess, view, "PspInsertProcess")?;
218
219        // Insert breakpoint for the `MmCleanProcessAddressSpace` function.
220        let va_MmCleanProcessAddressSpace = kernel_image_base + symbols.MmCleanProcessAddressSpace;
221        let cx_MmCleanProcessAddressSpace = (va_MmCleanProcessAddressSpace, root);
222        let bp_MmCleanProcessAddressSpace = Breakpoint::new(cx_MmCleanProcessAddressSpace, view)
223            .global()
224            .with_tag("MmCleanProcessAddressSpace");
225        bpm.insert(&vmi, bp_MmCleanProcessAddressSpace)?;
226        ptm.monitor(
227            &vmi,
228            cx_MmCleanProcessAddressSpace,
229            view,
230            "MmCleanProcessAddressSpace",
231        )?;
232
233        Ok(Self {
234            terminate_flag,
235            view,
236            bpm,
237            ptm,
238        })
239    }
Source

pub fn unmonitor( &mut self, vmi: &VmiCore<Driver>, ctx: impl Into<AddressContext>, view: View, ) -> Result<(), VmiError>

Releases one reference to a monitored virtual address.

The address is removed after its last reference is released. This also removes write protection from page table pages that no longer have any monitored entries.

Source

pub fn unmonitor_by_force( &mut self, vmi: &VmiCore<Driver>, ctx: impl Into<AddressContext>, view: View, ) -> Result<(), VmiError>

Stops monitoring a virtual address regardless of its reference count.

This releases all references to the address.

Source

pub fn unmonitor_all(&mut self, vmi: &VmiCore<Driver>)

Stops monitoring all virtual addresses and restores memory access.

Examples found in repository?
examples/windows-bridge/monitor/mod.rs (line 422)
397    fn cleanup(&mut self, vmi: &VmiSession<WindowsOs<Driver>>) {
398        if let Err(err) = vmi.switch_to_view(vmi.default_view()) {
399            tracing::error!(%err, "failed to switch to the default view");
400        }
401
402        if let Err(err) = vmi.monitor_disable(EventMonitor::Singlestep) {
403            tracing::error!(%err, "failed to disable singlestep monitoring");
404        }
405
406        if let Err(err) = vmi.monitor_disable(EventMonitor::Interrupt(ExceptionVector::Breakpoint))
407        {
408            tracing::error!(%err, "failed to disable breakpoint monitoring");
409        }
410
411        if let Err(err) = vmi.monitor_disable(EventMonitor::Hypercall {
412            allow_userspace: true,
413        }) {
414            tracing::error!(%err, "failed to disable hypercall monitoring");
415        }
416
417        match self.bpm.remove_by_view(vmi, self.view) {
418            Ok(true) => {}
419            Ok(false) => tracing::warn!("no deploy monitor breakpoints to remove"),
420            Err(err) => tracing::error!(%err, "failed to remove deploy monitor breakpoints"),
421        }
422        self.ptm.unmonitor_all(vmi);
423
424        if let Err(err) = vmi.destroy_view(self.view) {
425            tracing::error!(%err, "failed to destroy deploy monitor view");
426        }
427    }
Source

pub fn unmonitor_view(&mut self, vmi: &VmiCore<Driver>, view: View)

Stops monitoring all virtual addresses associated with a view.

Source

pub fn mark_dirty_entry( &mut self, entry_pa: Pa, view: View, vcpu_id: VcpuId, ) -> bool

Marks a page table entry as dirty after a write to a monitored page.

Returns true if the entry is being monitored (and was marked), false otherwise.

Examples found in repository?
examples/windows-bridge/monitor/mod.rs (line 245)
237    fn memory_access(
238        &mut self,
239        vmi: &VmiContext<WindowsOs<Driver>>,
240    ) -> Result<VmiEventResponse<Amd64>, VmiError> {
241        let memory_access = vmi.event().reason().as_memory_access();
242
243        if memory_access.access.contains(MemoryAccess::W) {
244            self.ptm
245                .mark_dirty_entry(memory_access.pa, self.view, vmi.event().vcpu_id());
246
247            Ok(VmiEventResponse::singlestep().with_view(vmi.default_view()))
248        }
249        else if memory_access.access.contains(MemoryAccess::R) {
250            Ok(VmiEventResponse::fast_singlestep(vmi.default_view()))
251        }
252        else {
253            panic!("unhandled memory access: {memory_access:?}");
254        }
255    }
More examples
Hide additional examples
examples/windows-breakpoint-manager.rs (line 261)
242    fn memory_access(
243        &mut self,
244        vmi: &VmiContext<WindowsOs<Driver>>,
245    ) -> Result<VmiEventResponse<Amd64>, VmiError> {
246        let memory_access = vmi.event().reason().as_memory_access();
247
248        tracing::trace!(
249            pa = %memory_access.pa,
250            va = %memory_access.va,
251            access = %memory_access.access,
252        );
253
254        if memory_access.access.contains(MemoryAccess::W) {
255            // It is assumed that a write memory access event is caused by a
256            // page table modification.
257            //
258            // The page table entry is marked as dirty in the page table monitor
259            // and a singlestep is performed to process the dirty entries.
260            self.ptm
261                .mark_dirty_entry(memory_access.pa, self.view, vmi.event().vcpu_id());
262
263            Ok(VmiEventResponse::singlestep().with_view(vmi.default_view()))
264        }
265        else if memory_access.access.contains(MemoryAccess::R) {
266            // When the guest tries to read from the memory, a fast-singlestep
267            // is performed over the instruction that tried to read the memory.
268            // This is done to allow the instruction to read the original memory
269            // content.
270            Ok(VmiEventResponse::fast_singlestep(vmi.default_view()))
271        }
272        else {
273            panic!("Unhandled memory access: {memory_access:?}");
274        }
275    }
Source

pub fn process_dirty_entries( &mut self, vmi: &VmiCore<Driver>, vcpu_id: VcpuId, ) -> Result<Vec<PageTableMonitorEvent>, VmiError>

Processes dirty entries for a vCPU, returning page-in/page-out events.

Should be called after singlestepping past the write that triggered the dirty marking, so the new PTE value is committed to memory.

Examples found in repository?
examples/windows-bridge/monitor/mod.rs (line 283)
279    fn singlestep(
280        &mut self,
281        vmi: &VmiContext<WindowsOs<Driver>>,
282    ) -> Result<VmiEventResponse<Amd64>, VmiError> {
283        let events = self.ptm.process_dirty_entries(vmi, vmi.event().vcpu_id())?;
284        self.bpm.handle_ptm_events(vmi, events)?;
285
286        Ok(VmiEventResponse::default().with_view(self.view))
287    }
More examples
Hide additional examples
examples/windows-breakpoint-manager.rs (line 326)
320    fn singlestep(
321        &mut self,
322        vmi: &VmiContext<WindowsOs<Driver>>,
323    ) -> Result<VmiEventResponse<Amd64>, VmiError> {
324        // Get the page table modifications by processing the dirty page table
325        // entries.
326        let ptm_events = self.ptm.process_dirty_entries(vmi, vmi.event().vcpu_id())?;
327
328        // Let the breakpoint controller handle the page table modifications.
329        self.bpm.handle_ptm_events(vmi, ptm_events)?;
330
331        // Disable singlestep and switch back to our view.
332        Ok(VmiEventResponse::default().with_view(self.view))
333    }

Auto Trait Implementations§

§

impl<Driver, Tag> Freeze for PageTableMonitor<Driver, Tag>
where <<Driver as VmiDriver>::Architecture as ArchAdapter<Driver, Tag>>::Monitor: Freeze,

§

impl<Driver, Tag> RefUnwindSafe for PageTableMonitor<Driver, Tag>
where <<Driver as VmiDriver>::Architecture as ArchAdapter<Driver, Tag>>::Monitor: RefUnwindSafe,

§

impl<Driver, Tag> Send for PageTableMonitor<Driver, Tag>
where <<Driver as VmiDriver>::Architecture as ArchAdapter<Driver, Tag>>::Monitor: Send,

§

impl<Driver, Tag> Sync for PageTableMonitor<Driver, Tag>
where <<Driver as VmiDriver>::Architecture as ArchAdapter<Driver, Tag>>::Monitor: Sync,

§

impl<Driver, Tag> Unpin for PageTableMonitor<Driver, Tag>
where <<Driver as VmiDriver>::Architecture as ArchAdapter<Driver, Tag>>::Monitor: Unpin,

§

impl<Driver, Tag> UnsafeUnpin for PageTableMonitor<Driver, Tag>
where <<Driver as VmiDriver>::Architecture as ArchAdapter<Driver, Tag>>::Monitor: UnsafeUnpin,

§

impl<Driver, Tag> UnwindSafe for PageTableMonitor<Driver, Tag>
where <<Driver as VmiDriver>::Architecture as ArchAdapter<Driver, Tag>>::Monitor: UnwindSafe,

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> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
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 = !

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

fn try_from(value: U) -> Result<T, !>

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