fuel_vm/state/
debugger.rs1use crate::state::{
2 Breakpoint,
3 DebugEval,
4 ProgramState,
5};
6
7use fuel_types::{
8 ContractId,
9 Word,
10};
11
12use hashbrown::{
13 HashMap,
14 HashSet,
15};
16
17#[derive(Debug, Default, Clone)]
19pub struct Debugger {
20 is_active: bool,
22 single_stepping: bool,
24 breakpoints: HashMap<ContractId, HashSet<Word>>,
25 last_state: Option<ProgramState>,
26}
27
28impl Debugger {
29 pub const fn is_active(&self) -> bool {
31 self.is_active
32 }
33
34 pub const fn single_stepping(&self) -> bool {
36 self.single_stepping
37 }
38
39 pub fn set_single_stepping(&mut self, single_stepping: bool) {
41 self.is_active = true;
42 self.single_stepping = single_stepping;
43 }
44
45 pub fn clear_breakpoints(&mut self) {
47 self.breakpoints.clear();
48 }
49
50 pub fn set_breakpoint(&mut self, breakpoint: Breakpoint) {
52 self.is_active = true;
53 let contract = *breakpoint.contract();
54 let pc = breakpoint.pc();
55
56 self.breakpoints
57 .get_mut(&contract)
58 .map(|set| set.insert(pc))
59 .map(|_| ())
60 .unwrap_or_else(|| {
61 let mut set = HashSet::new();
62
63 set.insert(pc);
64
65 self.breakpoints.insert(contract, set);
66 });
67 }
68
69 pub fn remove_breakpoint(&mut self, breakpoint: &Breakpoint) {
71 self.is_active = true;
72 self.breakpoints
73 .get_mut(breakpoint.contract())
74 .map(|set| set.remove(&breakpoint.pc()));
75 }
76
77 pub fn eval_state(&mut self, contract: Option<&ContractId>, pc: Word) -> DebugEval {
80 let contract = contract.copied().unwrap_or_default();
82 let last_state = self.last_state.take();
83
84 let current = Breakpoint::raw(contract, pc);
85
86 if self.single_stepping {
87 return match last_state {
88 Some(s) if s == current => DebugEval::Continue,
89 _ => current.into(),
90 }
91 }
92
93 self.breakpoints
94 .get(&contract)
95 .and_then(|set| set.get(&pc))
96 .map(|_| match last_state {
97 Some(s) if s == current => DebugEval::Continue,
98 _ => current.into(),
99 })
100 .unwrap_or_default()
101 }
102
103 pub fn set_last_state(&mut self, state: ProgramState) {
105 self.is_active = true;
106 self.last_state.replace(state);
107 }
108
109 pub const fn last_state(&self) -> &Option<ProgramState> {
112 &self.last_state
113 }
114}