1use std::time::Duration;
2
3use crate::UnparsedExitReason;
4pub use crate::nyx_vm::NyxVM;
5
6#[derive(Clone, Debug, Eq, PartialEq, Hash)]
7pub enum VMExitUserEvent {
8 Shutdown,
9 Hypercall,
10 Timeout,
11 Breakpoint,
12 HWBreakpoint(u8),
13 SingleStep,
14 Interrupted,
15 BadMemoryAccess,
16}
17
18#[derive(Clone, Debug, Eq, PartialEq, Hash)]
19pub enum VMContinuationState {
20 Main,
21 ForceSingleStep,
22 EmulateHypercall,
23 ForceSingleStepInjectBPs,
24}
25
26#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
27pub enum RunMode {
28 Run,
29 SingleStep,
30 BranchStep,
31}
32
33impl RunMode {
34 pub fn is_step(&self) -> bool {
35 match self {
36 RunMode::Run => false,
37 RunMode::SingleStep => true,
38 RunMode::BranchStep => true,
39 }
40 }
41}
42
43impl VMContinuationState {
44 pub fn step(vm: &mut NyxVM, run_mode: RunMode, timeout: Duration) -> VMExitUserEvent {
45 loop {
46 let (new_state, res) = match vm.continuation_state {
48 Self::Main => Self::run_main(vm, run_mode, timeout),
49 Self::ForceSingleStep => Self::force_ss(vm, run_mode.is_step()),
50 Self::ForceSingleStepInjectBPs => Self::force_ss_inject_bps(vm),
51 Self::EmulateHypercall => Self::emulate_hypercall(vm),
52 };
53 vm.continuation_state = new_state;
54 if let Some(user_event) = res {
55 return user_event;
56 }
57 }
58 }
59
60 fn run_main(
61 vm: &mut NyxVM,
62 run_mode: RunMode,
63 timeout: Duration,
64 ) -> (Self, Option<VMExitUserEvent>) {
65 let vmexit_on_swbp = true;
66 vm.set_debug_state(run_mode, vmexit_on_swbp);
67 vm.breakpoint_manager
68 .enable_all_breakpoints(&mut vm.vmm.lock().unwrap());
69 let exit = vm.run_inner(timeout);
70 match exit {
71 UnparsedExitReason::BadMemoryAccess => {
72 return (Self::Main, Some(VMExitUserEvent::BadMemoryAccess));
73 }
74 UnparsedExitReason::HWBreakpoint(x) => {
75 return (Self::Main, Some(VMExitUserEvent::HWBreakpoint(x)));
76 }
77 UnparsedExitReason::GuestBreakpoint => return (Self::ForceSingleStepInjectBPs, None),
78 UnparsedExitReason::NyxBreakpoint => {
79 return (Self::ForceSingleStep, Some(VMExitUserEvent::Breakpoint));
80 }
81 UnparsedExitReason::Hypercall => {
82 return (Self::EmulateHypercall, Some(VMExitUserEvent::Hypercall));
83 }
84 UnparsedExitReason::Interrupted => return (Self::Main, None),
85 UnparsedExitReason::Shutdown => return (Self::Main, Some(VMExitUserEvent::Shutdown)),
86 UnparsedExitReason::SingleStep => {
87 if run_mode.is_step() {
88 return (Self::Main, Some(VMExitUserEvent::SingleStep));
89 }
90 panic!("We shouldn't see singlestep exceptions unless we asked for them");
91 }
92 UnparsedExitReason::Timeout => return (Self::Main, Some(VMExitUserEvent::Timeout)),
93 };
94 }
95 fn force_ss(
96 vm: &mut NyxVM,
97 user_requested_singlestep: bool,
98 ) -> (Self, Option<VMExitUserEvent>) {
99 let vmexit_on_swbp = true;
100 vm.set_debug_state(RunMode::SingleStep, vmexit_on_swbp);
101 vm.disable_last_nyx_breakpoint(); let no_timeout = Duration::MAX;
103 let exit = vm.run_inner(no_timeout);
104 match exit {
105 UnparsedExitReason::SingleStep => {
106 Self::assert_made_progress(vm);
109 if user_requested_singlestep {
110 return (Self::Main, Some(VMExitUserEvent::SingleStep));
111 }
112 return (Self::Main, None);
113 }
114 UnparsedExitReason::BadMemoryAccess => {
115 return (Self::Main, Some(VMExitUserEvent::BadMemoryAccess));
116 }
117 UnparsedExitReason::GuestBreakpoint => {
118 Self::assert_made_no_progress(vm);
121 return (Self::ForceSingleStepInjectBPs, None);
122 }
123 UnparsedExitReason::HWBreakpoint(x) => {
124 return (Self::Main, Some(VMExitUserEvent::HWBreakpoint(x)));
125 }
126 UnparsedExitReason::NyxBreakpoint => {
127 panic!("We shouild never see a nyx bp when single stepping over a previous BP");
131 }
132 UnparsedExitReason::Hypercall => {
133 Self::assert_made_no_progress(vm);
137 return (Self::EmulateHypercall, Some(VMExitUserEvent::Hypercall));
138 }
139 UnparsedExitReason::Interrupted => return (Self::ForceSingleStep, None),
140 UnparsedExitReason::Shutdown => return (Self::Main, Some(VMExitUserEvent::Shutdown)),
141 UnparsedExitReason::Timeout => {
142 return (Self::ForceSingleStep, Some(VMExitUserEvent::Timeout));
143 }
144 };
145 }
146
147 fn force_ss_inject_bps(vm: &mut NyxVM) -> (Self, Option<VMExitUserEvent>) {
148 let vmexit_on_swbp = false;
149 vm.set_debug_state(RunMode::SingleStep, vmexit_on_swbp);
150 vm.breakpoint_manager
151 .disable_all_breakpoints(&mut vm.vmm.lock().unwrap()); let no_timeout = Duration::MAX;
153 let exit = vm.run_inner(no_timeout);
154 match exit {
155 UnparsedExitReason::SingleStep => {
156 Self::assert_made_progress(vm);
159 return (Self::Main, None);
160 }
161 UnparsedExitReason::HWBreakpoint(x) => {
162 return (Self::Main, Some(VMExitUserEvent::HWBreakpoint(x)));
163 }
164 UnparsedExitReason::BadMemoryAccess => {
165 return (Self::Main, Some(VMExitUserEvent::BadMemoryAccess));
166 }
167 UnparsedExitReason::GuestBreakpoint => {
168 panic!(
169 "We should never see a breakpoint based vm exit while injecting breakpoints interrupts"
170 );
171 }
172 UnparsedExitReason::NyxBreakpoint => {
173 panic!(
174 "We should never see a breakpoint based vm exit while injecting breakpoints interrupts"
175 );
176 }
177 UnparsedExitReason::Hypercall => {
178 panic!(
179 "We should never see a breakpoint based vm exit while injecting breakpoints interrupts"
180 );
181 }
182 UnparsedExitReason::Interrupted => return (Self::ForceSingleStepInjectBPs, None),
183 UnparsedExitReason::Shutdown => return (Self::Main, Some(VMExitUserEvent::Shutdown)),
184 UnparsedExitReason::Timeout => {
185 return (
186 Self::ForceSingleStepInjectBPs,
187 Some(VMExitUserEvent::Timeout),
188 );
189 }
190 };
191 }
192 fn emulate_hypercall(vm: &mut NyxVM) -> (Self, Option<VMExitUserEvent>) {
193 let mut regs = vm.regs();
194 regs.rax = 0; regs.rip += 1;
196 vm.set_regs(®s);
197 return (Self::Main, None);
198 }
199 fn assert_made_progress(_vm: &mut NyxVM) {
200 }
202 fn assert_made_no_progress(_vm: &mut NyxVM) {}
203}