Skip to main content

foundry_debugger/
debugger.rs

1//! Debugger implementation.
2
3use crate::{DebugNode, DebuggerBuilder, ExitReason, tui::TUI};
4use alloy_primitives::map::AddressHashMap;
5use eyre::Result;
6use foundry_evm_core::Breakpoints;
7use foundry_evm_traces::debug::ContractSources;
8use std::path::Path;
9
10#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
11pub struct DebuggerStats {
12    /// Sum of root-call gas used across every trace arena passed to the debugger.
13    pub session_trace_gas_used: u64,
14    /// Number of subcalls in the traces passed to the debugger.
15    pub session_subcalls: usize,
16}
17
18pub struct DebuggerContext {
19    pub debug_arena: Vec<DebugNode>,
20    pub stats: Option<DebuggerStats>,
21    pub identified_contracts: AddressHashMap<String>,
22    /// Source map of contract sources
23    pub contracts_sources: ContractSources,
24    pub breakpoints: Breakpoints,
25}
26
27pub struct Debugger {
28    context: DebuggerContext,
29}
30
31impl Debugger {
32    /// Creates a new debugger builder.
33    #[inline]
34    pub fn builder() -> DebuggerBuilder {
35        DebuggerBuilder::new()
36    }
37
38    /// Creates a new debugger.
39    pub const fn new(
40        debug_arena: Vec<DebugNode>,
41        identified_contracts: AddressHashMap<String>,
42        contracts_sources: ContractSources,
43        breakpoints: Breakpoints,
44    ) -> Self {
45        Self {
46            context: DebuggerContext {
47                debug_arena,
48                stats: None,
49                identified_contracts,
50                contracts_sources,
51                breakpoints,
52            },
53        }
54    }
55
56    pub(crate) const fn new_with_stats(
57        debug_arena: Vec<DebugNode>,
58        stats: DebuggerStats,
59        identified_contracts: AddressHashMap<String>,
60        contracts_sources: ContractSources,
61        breakpoints: Breakpoints,
62    ) -> Self {
63        Self {
64            context: DebuggerContext {
65                debug_arena,
66                stats: Some(stats),
67                identified_contracts,
68                contracts_sources,
69                breakpoints,
70            },
71        }
72    }
73
74    /// Starts the debugger TUI. Terminates the current process on failure or user exit.
75    pub fn run_tui_exit(mut self) -> ! {
76        let code = match self.try_run_tui() {
77            Ok(ExitReason::CharExit) => 0,
78            Err(e) => {
79                let _ = sh_eprintln!("{e}");
80                1
81            }
82        };
83        std::process::exit(code)
84    }
85
86    /// Starts the debugger TUI.
87    pub fn try_run_tui(&mut self) -> Result<ExitReason> {
88        eyre::ensure!(!self.context.debug_arena.is_empty(), "debug arena is empty");
89
90        let mut tui = TUI::new(&mut self.context);
91        tui.try_run()
92    }
93
94    /// Dumps debugger data to file.
95    pub fn dump_to_file(&mut self, path: &Path) -> Result<()> {
96        eyre::ensure!(!self.context.debug_arena.is_empty(), "debug arena is empty");
97        crate::dump::dump(path, &self.context)
98    }
99}