Skip to main content

foundry_debugger/
dump.rs

1use crate::{DebugNode, debugger::DebuggerContext};
2use alloy_primitives::map::AddressMap;
3use foundry_common::fs::write_json_file;
4use foundry_compilers::{
5    artifacts::sourcemap::{Jump, SourceElement},
6    multi::MultiCompilerLanguage,
7};
8use foundry_evm_core::ic::PcIcMap;
9use foundry_evm_traces::debug::{ArtifactData, ContractSources, SourceData};
10use serde::Serialize;
11use std::{collections::HashMap, path::Path};
12
13/// Holds info of debugger dump.
14#[derive(Serialize)]
15struct DebuggerDump<'a> {
16    contracts: ContractsDump<'a>,
17    debug_arena: &'a [DebugNode],
18}
19
20impl<'a> DebuggerDump<'a> {
21    fn new(debugger_context: &'a DebuggerContext) -> Self {
22        Self {
23            contracts: ContractsDump::new(debugger_context),
24            debug_arena: &debugger_context.debug_arena,
25        }
26    }
27}
28
29#[derive(Serialize)]
30struct SourceElementDump {
31    offset: u32,
32    length: u32,
33    index: i32,
34    jump: u32,
35    modifier_depth: u32,
36}
37
38impl SourceElementDump {
39    fn new(v: &SourceElement) -> Self {
40        Self {
41            offset: v.offset(),
42            length: v.length(),
43            index: v.index_i32(),
44            jump: match v.jump() {
45                Jump::In => 0,
46                Jump::Out => 1,
47                Jump::Regular => 2,
48            },
49            modifier_depth: v.modifier_depth(),
50        }
51    }
52}
53
54#[derive(Serialize)]
55struct ContractsDump<'a> {
56    identified_contracts: &'a AddressMap<String>,
57    sources: ContractsSourcesDump<'a>,
58}
59
60impl<'a> ContractsDump<'a> {
61    fn new(debugger_context: &'a DebuggerContext) -> Self {
62        Self {
63            identified_contracts: &debugger_context.identified_contracts,
64            sources: ContractsSourcesDump::new(&debugger_context.contracts_sources),
65        }
66    }
67}
68
69#[derive(Serialize)]
70struct ContractsSourcesDump<'a> {
71    sources_by_id: HashMap<&'a str, HashMap<u32, SourceDataDump<'a>>>,
72    artifacts_by_name: HashMap<&'a str, Vec<ArtifactDataDump<'a>>>,
73}
74
75impl<'a> ContractsSourcesDump<'a> {
76    fn new(contracts_sources: &'a ContractSources) -> Self {
77        Self {
78            sources_by_id: contracts_sources
79                .sources_by_id
80                .iter()
81                .map(|(name, inner_map)| {
82                    (
83                        name.as_str(),
84                        inner_map
85                            .iter()
86                            .map(|(id, source_data)| (*id, SourceDataDump::new(source_data)))
87                            .collect(),
88                    )
89                })
90                .collect(),
91            artifacts_by_name: contracts_sources
92                .artifacts_by_name
93                .iter()
94                .map(|(name, data)| {
95                    (name.as_str(), data.iter().map(ArtifactDataDump::new).collect())
96                })
97                .collect(),
98        }
99    }
100}
101
102#[derive(Serialize)]
103struct SourceDataDump<'a> {
104    source: &'a str,
105    language: MultiCompilerLanguage,
106    path: &'a Path,
107}
108
109impl<'a> SourceDataDump<'a> {
110    fn new(v: &'a SourceData) -> Self {
111        Self { source: &v.source, language: v.language, path: &v.path }
112    }
113}
114
115#[derive(Serialize)]
116struct ArtifactDataDump<'a> {
117    source_map: Option<Vec<SourceElementDump>>,
118    source_map_runtime: Option<Vec<SourceElementDump>>,
119    pc_ic_map: Option<&'a PcIcMap>,
120    pc_ic_map_runtime: Option<&'a PcIcMap>,
121    build_id: &'a str,
122    file_id: u32,
123}
124
125impl<'a> ArtifactDataDump<'a> {
126    fn new(v: &'a ArtifactData) -> Self {
127        Self {
128            source_map: v
129                .source_map
130                .as_ref()
131                .map(|source_map| source_map.iter().map(SourceElementDump::new).collect()),
132            source_map_runtime: v
133                .source_map_runtime
134                .as_ref()
135                .map(|source_map| source_map.iter().map(SourceElementDump::new).collect()),
136            pc_ic_map: v.pc_ic_map.as_ref(),
137            pc_ic_map_runtime: v.pc_ic_map_runtime.as_ref(),
138            build_id: &v.build_id,
139            file_id: v.file_id,
140        }
141    }
142}
143
144/// Dumps debugger data to a JSON file.
145pub(crate) fn dump(path: &Path, context: &DebuggerContext) -> eyre::Result<()> {
146    write_json_file(path, &DebuggerDump::new(context))?;
147    Ok(())
148}