fuel_vm/state/
debug.rs

1use fuel_asm::Instruction;
2use fuel_types::{
3    ContractId,
4    Word,
5};
6
7use crate::consts::VM_MAX_RAM;
8
9#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11/// Breakpoint description that binds a tuple `(contract, $pc)` to a debugger
12/// implementation.
13///
14/// Breakpoints should be context-sensitive; hence, should target contract Ids.
15///
16/// For script/predicate verification, the contract id should be zero.
17pub struct Breakpoint {
18    contract: ContractId,
19    pc: Word,
20}
21
22impl Breakpoint {
23    pub(crate) const fn raw(contract: ContractId, pc: Word) -> Self {
24        Self { contract, pc }
25    }
26
27    /// Create a new contract breakpoint
28    ///
29    /// The `$pc` is provided in op count and internally is multiplied by the op
30    /// size. Also, the op count is always relative to `$is` so it should
31    /// consider only the bytecode of the contract.
32    ///
33    /// Panics if the `pc` cannot ever fit into the VM memory.
34    pub const fn new(contract: ContractId, pc: Word) -> Self {
35        let pc = pc.saturating_mul(Instruction::SIZE as Word);
36        assert!(pc <= VM_MAX_RAM, "Breakpoint cannot fit into vm memory");
37        Self::raw(contract, pc)
38    }
39
40    /// Create a new script breakpoint
41    ///
42    /// The `$pc` is provided in op count and internally is multiplied by the op
43    /// size
44    pub fn script(pc: Word) -> Self {
45        let contract = Default::default();
46
47        Self::new(contract, pc)
48    }
49
50    /// Contract that will trigger the breakpoint.
51    pub const fn contract(&self) -> &ContractId {
52        &self.contract
53    }
54
55    /// Program counter that will trigger the breakpoint.
56    pub const fn pc(&self) -> Word {
57        self.pc
58    }
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
62#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
63/// State evaluation of the interpreter that will describe if a program should
64/// break or continue.
65pub enum DebugEval {
66    /// This evaluation should break the program in the location described in
67    /// `Breakpoint`.
68    Breakpoint(Breakpoint),
69    /// This evaluation should not break the program.
70    Continue,
71}
72
73impl Default for DebugEval {
74    fn default() -> Self {
75        Self::Continue
76    }
77}
78
79impl From<Breakpoint> for DebugEval {
80    fn from(b: Breakpoint) -> Self {
81        Self::Breakpoint(b)
82    }
83}
84
85impl DebugEval {
86    /// Flag whether the program execution should break.
87    pub const fn should_continue(&self) -> bool {
88        matches!(self, Self::Continue)
89    }
90
91    /// Return a breakpoint description if the current evaluation should break;
92    /// return `None` otherwise.
93    pub const fn breakpoint(&self) -> Option<&Breakpoint> {
94        match self {
95            Self::Breakpoint(b) => Some(b),
96            _ => None,
97        }
98    }
99}