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#[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
144pub(crate) fn dump(path: &Path, context: &DebuggerContext) -> eyre::Result<()> {
146 write_json_file(path, &DebuggerDump::new(context))?;
147 Ok(())
148}