foundry_debugger/
debugger.rs1use 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 pub session_trace_gas_used: u64,
14 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 pub contracts_sources: ContractSources,
24 pub breakpoints: Breakpoints,
25}
26
27pub struct Debugger {
28 context: DebuggerContext,
29}
30
31impl Debugger {
32 #[inline]
34 pub fn builder() -> DebuggerBuilder {
35 DebuggerBuilder::new()
36 }
37
38 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 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 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 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}