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
13pub(crate) fn dump(path: &Path, context: &DebuggerContext) -> eyre::Result<()> {
15 write_json_file(path, &DebuggerDump::new(context))?;
16 Ok(())
17}
18
19#[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}