foundry_debugger/
dump.rs

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