1use std::time::SystemTime;
7
8use crate::{
9 arch::ArchitectureOperations,
10 magic::MagicNumber,
11 os::DebugInfoConfig,
12 state::{SolutionKind, StopReason},
13 ManualStartInfo, Tsffs,
14};
15use anyhow::{anyhow, bail, Result};
16use libafl::prelude::ExitKind;
17use simics::{
18 api::{
19 continue_simulation, log_level, object_is_processor, quit, run_alone, set_log_level,
20 AsConfObject, ConfObject, GenericTransaction, LogLevel,
21 },
22 debug, get_processor_number, info, trace, warn,
23};
24
25impl Tsffs {
26 fn on_simulation_stopped_magic_start(&mut self, magic_number: MagicNumber) -> Result<()> {
27 if !self.have_initial_snapshot() {
28 self.start_fuzzer_thread()?;
29
30 let start_processor = self
31 .start_processor()
32 .ok_or_else(|| anyhow!("No start processor"))?;
33 let start_processor_raw = start_processor.cpu();
34
35 let start_info = match magic_number {
36 MagicNumber::StartBufferPtrSizePtr => {
37 start_processor.get_magic_start_buffer_ptr_size_ptr()?
38 }
39 MagicNumber::StartBufferPtrSizeVal => {
40 start_processor.get_magic_start_buffer_ptr_size_val()?
41 }
42 MagicNumber::StartBufferPtrSizePtrVal => {
43 start_processor.get_magic_start_buffer_ptr_size_ptr_val()?
44 }
45 MagicNumber::StopNormal => unreachable!("StopNormal is not handled here"),
46 MagicNumber::StopAssert => unreachable!("StopAssert is not handled here"),
47 };
48
49 debug!(self.as_conf_object(), "Start info: {start_info:?}");
50
51 self.start_info
52 .set(start_info)
53 .map_err(|_| anyhow!("Failed to set start size"))?;
54 self.start_time
55 .set(SystemTime::now())
56 .map_err(|_| anyhow!("Failed to set start time"))?;
57 self.coverage_enabled = true;
58 self.save_initial_snapshot()?;
59 if self.windows && self.symbolic_coverage {
61 info!(self.as_conf_object(), "Collecting initial coverage info");
62 self.windows_os_info.collect(
63 start_processor_raw,
64 &self.debuginfo_download_directory,
65 &mut DebugInfoConfig {
66 system: self.symbolic_coverage_system,
67 user_debug_info: &self.debug_info,
68 coverage: &mut self.coverage,
69 },
70 &self.source_file_cache,
71 )?;
72 }
73 self.get_and_write_testcase()?;
74 self.post_timeout_event()?;
75 }
76
77 self.execution_trace.0.clear();
78 self.save_repro_bookmark_if_needed()?;
79
80 debug!(self.as_conf_object(), "Resuming simulation");
81
82 run_alone(|| {
83 continue_simulation(0)?;
84 Ok(())
85 })?;
86
87 Ok(())
88 }
89
90 fn on_simulation_stopped_magic_assert(&mut self) -> Result<()> {
91 self.on_simulation_stopped_solution(SolutionKind::Manual)
92 }
93
94 fn on_simulation_stopped_magic_stop(&mut self) -> Result<()> {
95 if !self.have_initial_snapshot() {
96 warn!(
97 self.as_conf_object(),
98 "Stopped normally before start was reached (no snapshot). Resuming without restoring non-existent snapshot."
99 );
100 } else {
101 self.cancel_timeout_event()?;
102
103 if self.repro_bookmark_set {
104 self.stopped_for_repro = true;
105 let current_log_level = log_level(self.as_conf_object_mut())?;
106
107 if current_log_level < LogLevel::Info as u32 {
108 set_log_level(self.as_conf_object_mut(), LogLevel::Info)?;
109 }
110
111 info!(
112 self.as_conf_object(),
113 "Stopped for repro. Restore to start bookmark with 'reverse-to start'"
114 );
115
116 return Ok(());
118 }
119
120 self.iterations += 1;
121
122 if self.iteration_limit != 0 && self.iterations >= self.iteration_limit {
123 let duration = SystemTime::now().duration_since(
124 *self
125 .start_time
126 .get()
127 .ok_or_else(|| anyhow!("Start time was not set"))?,
128 )?;
129
130 set_log_level(self.as_conf_object_mut(), LogLevel::Info)?;
132
133 info!(
134 self.as_conf_object(),
135 "Configured iteration count {} reached. Stopping after {} seconds ({} exec/s).",
136 self.iterations,
137 duration.as_secs_f32(),
138 self.iterations as f32 / duration.as_secs_f32()
139 );
140
141 self.send_shutdown()?;
142
143 if self.quit_on_iteration_limit {
144 quit(0)?;
145 } else {
146 return Ok(());
147 }
148 }
149
150 let fuzzer_tx = self
151 .fuzzer_tx
152 .get()
153 .ok_or_else(|| anyhow!("No fuzzer tx channel"))?;
154
155 fuzzer_tx.send(ExitKind::Ok)?;
156
157 self.restore_initial_snapshot()?;
158 self.coverage_prev_loc = 0;
159
160 if self.start_info.get().is_some() {
161 self.get_and_write_testcase()?;
162 } else {
163 debug!(
164 self.as_conf_object(),
165 "Missing start buffer or size, not writing testcase."
166 );
167 }
168
169 self.post_timeout_event()?;
170 }
171
172 if self.save_all_execution_traces {
173 self.save_execution_trace()?;
174 }
175
176 if self.symbolic_coverage {
177 self.save_symbolic_coverage()?;
178 }
179
180 debug!(self.as_conf_object(), "Resuming simulation");
181
182 run_alone(|| {
183 continue_simulation(0)?;
184 Ok(())
185 })?;
186
187 Ok(())
188 }
189
190 fn on_simulation_stopped_with_magic(&mut self, magic_number: MagicNumber) -> Result<()> {
191 match magic_number {
192 MagicNumber::StartBufferPtrSizePtr
193 | MagicNumber::StartBufferPtrSizeVal
194 | MagicNumber::StartBufferPtrSizePtrVal => {
195 self.on_simulation_stopped_magic_start(magic_number)?
196 }
197 MagicNumber::StopNormal => self.on_simulation_stopped_magic_stop()?,
198 MagicNumber::StopAssert => self.on_simulation_stopped_magic_assert()?,
199 }
200
201 Ok(())
202 }
203
204 fn on_simulation_stopped_with_manual_start(
205 &mut self,
206 processor: *mut ConfObject,
207 info: ManualStartInfo,
208 ) -> Result<()> {
209 if !self.have_initial_snapshot() {
210 self.start_fuzzer_thread()?;
211 self.add_processor(processor, true)?;
212
213 let start_info = self
214 .start_processor()
215 .ok_or_else(|| anyhow!("No start processor"))?
216 .get_manual_start_info(&info)?;
217
218 self.start_info
219 .set(start_info)
220 .map_err(|_| anyhow!("Failed to set start info"))?;
221 self.start_time
222 .set(SystemTime::now())
223 .map_err(|_| anyhow!("Failed to set start time"))?;
224 self.coverage_enabled = true;
225 self.save_initial_snapshot()?;
226
227 if self.windows && self.symbolic_coverage {
229 info!(self.as_conf_object(), "Collecting initial coverage info");
230 self.windows_os_info.collect(
231 processor,
232 &self.debuginfo_download_directory,
233 &mut DebugInfoConfig {
234 system: self.symbolic_coverage_system,
235 user_debug_info: &self.debug_info,
236 coverage: &mut self.coverage,
237 },
238 &self.source_file_cache,
239 )?;
240 }
241
242 self.get_and_write_testcase()?;
243
244 self.post_timeout_event()?;
245 }
246
247 self.execution_trace.0.clear();
248 self.save_repro_bookmark_if_needed()?;
249
250 debug!(self.as_conf_object(), "Resuming simulation");
251
252 run_alone(|| {
253 continue_simulation(0)?;
254 Ok(())
255 })?;
256
257 Ok(())
258 }
259
260 fn on_simulation_stopped_manual_start_without_buffer(
261 &mut self,
262 processor: *mut ConfObject,
263 ) -> Result<()> {
264 if !self.have_initial_snapshot() {
265 self.start_fuzzer_thread()?;
266 self.add_processor(processor, true)?;
267
268 self.start_time
269 .set(SystemTime::now())
270 .map_err(|_| anyhow!("Failed to set start time"))?;
271 self.coverage_enabled = true;
272 self.save_initial_snapshot()?;
273
274 if self.windows && self.symbolic_coverage {
276 info!(self.as_conf_object(), "Collecting initial coverage info");
277 self.windows_os_info.collect(
278 processor,
279 &self.debuginfo_download_directory,
280 &mut DebugInfoConfig {
281 system: self.symbolic_coverage_system,
282 user_debug_info: &self.debug_info,
283 coverage: &mut self.coverage,
284 },
285 &self.source_file_cache,
286 )?;
287 }
288
289 self.post_timeout_event()?;
290 }
291
292 self.execution_trace.0.clear();
293 self.save_repro_bookmark_if_needed()?;
294
295 debug!(self.as_conf_object(), "Resuming simulation");
296
297 run_alone(|| {
298 continue_simulation(0)?;
299 Ok(())
300 })?;
301
302 Ok(())
303 }
304
305 fn on_simulation_stopped_manual_stop(&mut self) -> Result<()> {
306 if !self.have_initial_snapshot() {
307 warn!(
308 self.as_conf_object(),
309 "Stopped for manual stop before start was reached (no snapshot). Resuming without restoring non-existent snapshot."
310 );
311 } else {
312 self.cancel_timeout_event()?;
313
314 if self.repro_bookmark_set {
315 self.stopped_for_repro = true;
316 let current_log_level = log_level(self.as_conf_object_mut())?;
317
318 if current_log_level < LogLevel::Info as u32 {
319 set_log_level(self.as_conf_object_mut(), LogLevel::Info)?;
320 }
321
322 info!(
323 self.as_conf_object(),
324 "Stopped for repro. Restore to start bookmark with 'reverse-to start'"
325 );
326
327 return Ok(());
329 }
330
331 self.iterations += 1;
332
333 if self.iteration_limit != 0 && self.iterations >= self.iteration_limit {
334 let duration = SystemTime::now().duration_since(
335 *self
336 .start_time
337 .get()
338 .ok_or_else(|| anyhow!("Start time was not set"))?,
339 )?;
340
341 set_log_level(self.as_conf_object_mut(), LogLevel::Info)?;
343
344 info!(
345 self.as_conf_object(),
346 "Configured iteration count {} reached. Stopping after {} seconds ({} exec/s).",
347 self.iterations,
348 duration.as_secs_f32(),
349 self.iterations as f32 / duration.as_secs_f32()
350 );
351
352 self.send_shutdown()?;
353
354 if self.quit_on_iteration_limit {
355 quit(0)?;
356 } else {
357 return Ok(());
358 }
359 }
360
361 let fuzzer_tx = self
362 .fuzzer_tx
363 .get()
364 .ok_or_else(|| anyhow!("No fuzzer tx channel"))?;
365
366 fuzzer_tx.send(ExitKind::Ok)?;
367
368 self.restore_initial_snapshot()?;
369 self.coverage_prev_loc = 0;
370
371 if self.start_info.get().is_some() {
372 self.get_and_write_testcase()?;
373 } else {
374 debug!(
375 self.as_conf_object(),
376 "Missing start buffer or size, not writing testcase. This may be due to using manual no-buffer harnessing."
377 );
378 }
379
380 self.post_timeout_event()?;
381 }
382
383 if self.save_all_execution_traces {
384 self.save_execution_trace()?;
385 }
386
387 if self.symbolic_coverage {
388 self.save_symbolic_coverage()?;
389 }
390
391 debug!(self.as_conf_object(), "Resuming simulation");
392
393 run_alone(|| {
394 continue_simulation(0)?;
395 Ok(())
396 })?;
397
398 Ok(())
399 }
400
401 fn on_simulation_stopped_solution(&mut self, kind: SolutionKind) -> Result<()> {
402 if !self.have_initial_snapshot() {
403 warn!(
404 self.as_conf_object(),
405 "Solution {kind:?} before start was reached (no snapshot). Resuming without restoring non-existent snapshot."
406 );
407 } else {
408 self.cancel_timeout_event()?;
409
410 if self.repro_bookmark_set {
411 self.stopped_for_repro = true;
412 let current_log_level = log_level(self.as_conf_object_mut())?;
413
414 if current_log_level < LogLevel::Info as u32 {
415 set_log_level(self.as_conf_object_mut(), LogLevel::Info)?;
416 }
417
418 info!(
419 self.as_conf_object(),
420 "Stopped for repro. Restore to start bookmark with 'reverse-to start'"
421 );
422
423 return Ok(());
425 }
426
427 self.iterations += 1;
428
429 if self.iteration_limit != 0 && self.iterations >= self.iteration_limit {
430 let duration = SystemTime::now().duration_since(
431 *self
432 .start_time
433 .get()
434 .ok_or_else(|| anyhow!("Start time was not set"))?,
435 )?;
436
437 set_log_level(self.as_conf_object_mut(), LogLevel::Info)?;
439
440 info!(
441 self.as_conf_object(),
442 "Configured iteration count {} reached. Stopping after {} seconds ({} exec/s).",
443 self.iterations,
444 duration.as_secs_f32(),
445 self.iterations as f32 / duration.as_secs_f32()
446 );
447
448 self.send_shutdown()?;
449
450 if self.quit_on_iteration_limit {
451 quit(0)?;
452 } else {
453 return Ok(());
454 }
455 }
456
457 let fuzzer_tx = self
458 .fuzzer_tx
459 .get()
460 .ok_or_else(|| anyhow!("No fuzzer tx channel"))?;
461
462 match kind {
463 SolutionKind::Timeout => {
464 self.timeouts += 1;
465 fuzzer_tx.send(ExitKind::Timeout)?
466 }
467 SolutionKind::Exception | SolutionKind::Breakpoint | SolutionKind::Manual => {
468 self.solutions += 1;
469 fuzzer_tx.send(ExitKind::Crash)?
470 }
471 }
472
473 self.restore_initial_snapshot()?;
474 self.coverage_prev_loc = 0;
475
476 if self.start_info.get().is_some() {
477 self.get_and_write_testcase()?;
478 } else {
479 debug!(
480 self.as_conf_object(),
481 "Missing start buffer or size, not writing testcase."
482 );
483 }
484
485 self.post_timeout_event()?;
486 }
487
488 if self.save_all_execution_traces {
489 self.save_execution_trace()?;
490 }
491
492 if self.symbolic_coverage {
493 self.save_symbolic_coverage()?;
494 }
495
496 debug!(self.as_conf_object(), "Resuming simulation");
497
498 run_alone(|| {
499 continue_simulation(0)?;
500 Ok(())
501 })?;
502
503 Ok(())
504 }
505
506 fn on_simulation_stopped_with_reason(&mut self, reason: StopReason) -> Result<()> {
507 debug!(
508 self.as_conf_object(),
509 "Simulation stopped with reason {reason:?}"
510 );
511
512 match reason {
513 StopReason::Magic { magic_number } => {
514 self.on_simulation_stopped_with_magic(magic_number)
515 }
516 StopReason::ManualStart { processor, info } => {
517 self.on_simulation_stopped_with_manual_start(processor, info)
518 }
519 StopReason::ManualStartWithoutBuffer { processor } => {
520 self.on_simulation_stopped_manual_start_without_buffer(processor)
521 }
522 StopReason::ManualStop => self.on_simulation_stopped_manual_stop(),
523 StopReason::Solution { kind } => self.on_simulation_stopped_solution(kind),
524 }
525 }
526
527 fn on_simulation_stopped_without_reason(&mut self) -> Result<()> {
528 if self.have_initial_snapshot() {
529 self.cancel_timeout_event()?;
532
533 let fuzzer_tx = self
534 .fuzzer_tx
535 .get()
536 .ok_or_else(|| anyhow!("No fuzzer tx channel"))?;
537
538 fuzzer_tx.send(ExitKind::Ok)?;
539
540 info!(
541 self.as_conf_object(),
542 "Simulation stopped without reason, not resuming."
543 );
544
545 let duration = SystemTime::now().duration_since(
546 *self
547 .start_time
548 .get()
549 .ok_or_else(|| anyhow!("Start time was not set"))?,
550 )?;
551
552 set_log_level(self.as_conf_object_mut(), LogLevel::Info)?;
554
555 info!(
556 self.as_conf_object(),
557 "Stopped after {} iterations in {} seconds ({} exec/s).",
558 self.iterations,
559 duration.as_secs_f32(),
560 self.iterations as f32 / duration.as_secs_f32()
561 );
562
563 if self.shutdown_on_stop_without_reason {
564 self.send_shutdown()?;
565 }
566 }
567
568 Ok(())
569 }
570
571 pub fn on_simulation_stopped(&mut self) -> Result<()> {
573 if self.stopped_for_repro {
574 return Ok(());
576 }
577
578 self.log_messages()?;
580
581 if let Some(reason) = self.stop_reason.take() {
582 self.on_simulation_stopped_with_reason(reason)
583 } else {
584 self.on_simulation_stopped_without_reason()
585 }
586 }
587
588 pub fn on_exception(&mut self, _obj: *mut ConfObject, exception: i64) -> Result<()> {
591 if self.all_exceptions_are_solutions || self.exceptions.contains(&exception) {
592 self.stop_simulation(StopReason::Solution {
593 kind: SolutionKind::Exception,
594 })?;
595 }
596 Ok(())
597 }
598
599 pub fn on_breakpoint_memop(
602 &mut self,
603 obj: *mut ConfObject,
604 breakpoint: i64,
605 transaction: *mut GenericTransaction,
606 ) -> Result<()> {
607 if self.all_breakpoints_are_solutions || self.breakpoints.contains(&(breakpoint as i32)) {
608 info!(
609 self.as_conf_object(),
610 "on_breakpoint_memop({:#x}, {}, {:#x})",
611 obj as usize,
612 breakpoint,
613 transaction as usize
614 );
615
616 self.stop_simulation(StopReason::Solution {
617 kind: SolutionKind::Breakpoint,
618 })?;
619 }
620 Ok(())
621 }
622
623 pub fn on_magic_instruction(
626 &mut self,
627 trigger_obj: *mut ConfObject,
628 magic_number: MagicNumber,
629 ) -> Result<()> {
630 trace!(
631 self.as_conf_object(),
632 "Got magic instruction with magic #{magic_number})"
633 );
634
635 if object_is_processor(trigger_obj)? {
636 let processor_number = get_processor_number(trigger_obj)?;
637
638 if !self.processors.contains_key(&processor_number) {
639 self.add_processor(trigger_obj, false)?;
640 }
641
642 let processor = self
643 .processors
644 .get_mut(&processor_number)
645 .ok_or_else(|| anyhow!("Processor not found"))?;
646
647 let index_selector = processor.get_magic_index_selector()?;
648
649 if match magic_number {
650 MagicNumber::StartBufferPtrSizePtr
651 | MagicNumber::StartBufferPtrSizeVal
652 | MagicNumber::StartBufferPtrSizePtrVal => {
653 self.start_on_harness
654 && (if self.magic_start_index == index_selector {
655 let _ = self.start_processor_number.get_or_init(|| processor_number);
658 true
659 } else {
660 debug!(
661 "Not setting processor {} as start processor",
662 processor_number
663 );
664 false
665 })
666 }
667 MagicNumber::StopNormal => {
668 self.stop_on_harness && self.magic_stop_indices.contains(&index_selector)
669 }
670 MagicNumber::StopAssert => {
671 self.stop_on_harness && self.magic_assert_indices.contains(&index_selector)
672 }
673 } {
674 self.stop_simulation(StopReason::Magic { magic_number })?;
675 } else {
676 debug!(
677 self.as_conf_object(),
678 "Magic instruction {magic_number} was triggered by processor {trigger_obj:?} with index {index_selector} but the index is not configured for this magic number or start/stop on harness was disabled. Configured indices are: start: {}, stop: {:?}, assert: {:?}",
679 self.magic_start_index,
680 self.magic_stop_indices,
681 self.magic_assert_indices
682 );
683 }
684 } else {
685 bail!("Magic instruction was triggered by a non-processor object");
686 }
687
688 Ok(())
689 }
690
691 pub fn on_control_register_write(
692 &mut self,
693 trigger_obj: *mut ConfObject,
694 register_nr: i64,
695 value: i64,
696 ) -> Result<()> {
697 self.on_control_register_write_windows_symcov(trigger_obj, register_nr, value)?;
698
699 Ok(())
700 }
701}