samply_symbols/
symbol_map.rs1use std::borrow::Cow;
2use std::sync::Arc;
3
4use debugid::DebugId;
5
6use crate::shared::LookupAddress;
7use crate::{
8 AddressInfo, ExternalFileAddressRef, ExternalFileRef, FileAndPathHelper, FileLocation,
9 FrameDebugInfo, FramesLookupResult, SyncAddressInfo,
10};
11
12pub trait SymbolMapTrait {
13 fn debug_id(&self) -> DebugId;
14
15 fn symbol_count(&self) -> usize;
16
17 fn iter_symbols(&self) -> Box<dyn Iterator<Item = (u32, Cow<'_, str>)> + '_>;
18
19 fn lookup_sync(&self, address: LookupAddress) -> Option<SyncAddressInfo>;
27}
28
29pub trait SymbolMapTraitWithExternalFileSupport<FC>: SymbolMapTrait {
30 fn get_as_symbol_map(&self) -> &dyn SymbolMapTrait;
31 fn try_lookup_external(&self, external: &ExternalFileAddressRef) -> Option<FramesLookupResult>;
32 fn try_lookup_external_with_file_contents(
33 &self,
34 external: &ExternalFileAddressRef,
35 file_contents: Option<FC>,
36 ) -> Option<FramesLookupResult>;
37}
38
39pub trait GetInnerSymbolMap {
40 fn get_inner_symbol_map<'a>(&'a self) -> &'a (dyn SymbolMapTrait + 'a);
41}
42
43pub trait GetInnerSymbolMapWithLookupFramesExt<FC> {
44 fn get_inner_symbol_map<'a>(
45 &'a self,
46 ) -> &'a (dyn SymbolMapTraitWithExternalFileSupport<FC> + Send + Sync + 'a);
47}
48
49enum InnerSymbolMap<FC> {
50 WithoutAddFile(Box<dyn GetInnerSymbolMap + Send + Sync>),
51 WithAddFile(Box<dyn GetInnerSymbolMapWithLookupFramesExt<FC> + Send + Sync>),
52 Direct(Arc<dyn SymbolMapTrait + Send + Sync>),
53}
54
55pub struct SymbolMap<H: FileAndPathHelper> {
56 debug_file_location: H::FL,
57 inner: InnerSymbolMap<H::F>,
58 helper: Option<Arc<H>>,
59}
60
61impl<H: FileAndPathHelper> SymbolMap<H> {
62 pub(crate) fn new_plain(
63 debug_file_location: H::FL,
64 inner: Box<dyn GetInnerSymbolMap + Send + Sync>,
65 ) -> Self {
66 Self {
67 debug_file_location,
68 inner: InnerSymbolMap::WithoutAddFile(inner),
69 helper: None,
70 }
71 }
72
73 pub(crate) fn new_with_external_file_support(
74 debug_file_location: H::FL,
75 inner: Box<dyn GetInnerSymbolMapWithLookupFramesExt<H::F> + Send + Sync>,
76 helper: Arc<H>,
77 ) -> Self {
78 Self {
79 debug_file_location,
80 inner: InnerSymbolMap::WithAddFile(inner),
81 helper: Some(helper),
82 }
83 }
84
85 pub fn with_symbol_map_trait(
86 debug_file_location: H::FL,
87 inner: Arc<dyn SymbolMapTrait + Send + Sync>,
88 ) -> Self {
89 Self {
90 debug_file_location,
91 inner: InnerSymbolMap::Direct(inner),
92 helper: None,
93 }
94 }
95
96 fn inner(&self) -> &dyn SymbolMapTrait {
97 match &self.inner {
98 InnerSymbolMap::WithoutAddFile(inner) => inner.get_inner_symbol_map(),
99 InnerSymbolMap::WithAddFile(inner) => inner.get_inner_symbol_map().get_as_symbol_map(),
100 InnerSymbolMap::Direct(inner) => inner.as_ref(),
101 }
102 }
103
104 pub fn debug_file_location(&self) -> &H::FL {
105 &self.debug_file_location
106 }
107
108 pub fn debug_id(&self) -> debugid::DebugId {
109 self.inner().debug_id()
110 }
111
112 pub fn symbol_count(&self) -> usize {
113 self.inner().symbol_count()
114 }
115
116 pub fn iter_symbols(&self) -> Box<dyn Iterator<Item = (u32, Cow<'_, str>)> + '_> {
117 self.inner().iter_symbols()
118 }
119
120 pub fn lookup_sync(&self, address: LookupAddress) -> Option<SyncAddressInfo> {
121 self.inner().lookup_sync(address)
122 }
123
124 pub async fn lookup(&self, address: LookupAddress) -> Option<AddressInfo> {
125 let address_info = self.inner().lookup_sync(address)?;
126 let symbol = address_info.symbol;
127 let (mut external, inner) = match (address_info.frames, &self.inner) {
128 (Some(FramesLookupResult::Available(frames)), _) => {
129 return Some(AddressInfo {
130 symbol,
131 frames: Some(frames),
132 });
133 }
134 (None, _) | (_, InnerSymbolMap::WithoutAddFile(_)) | (_, InnerSymbolMap::Direct(_)) => {
135 return Some(AddressInfo {
136 symbol,
137 frames: None,
138 });
139 }
140 (Some(FramesLookupResult::External(external)), InnerSymbolMap::WithAddFile(inner)) => {
141 (external, inner.get_inner_symbol_map())
142 }
143 };
144 let helper = self.helper.as_deref()?;
145 loop {
146 let maybe_file_location = match &external.file_ref {
147 ExternalFileRef::MachoExternalObject { file_path } => self
148 .debug_file_location
149 .location_for_external_object_file(file_path),
150 ExternalFileRef::ElfExternalDwo { comp_dir, path } => {
151 self.debug_file_location.location_for_dwo(comp_dir, path)
152 }
153 };
154 let file_contents = match maybe_file_location {
155 Some(location) => helper.load_file(location).await.ok(),
156 None => None,
157 };
158 let lookup_result =
159 inner.try_lookup_external_with_file_contents(&external, file_contents);
160 external = match lookup_result {
161 Some(FramesLookupResult::Available(frames)) => {
162 return Some(AddressInfo {
163 symbol,
164 frames: Some(frames),
165 });
166 }
167 None => {
168 return Some(AddressInfo {
169 symbol,
170 frames: None,
171 });
172 }
173 Some(FramesLookupResult::External(external)) => external,
174 };
175 }
176 }
177
178 pub async fn lookup_external(
186 &self,
187 external: &ExternalFileAddressRef,
188 ) -> Option<Vec<FrameDebugInfo>> {
189 let helper = self.helper.as_deref()?;
190 let inner = match &self.inner {
191 InnerSymbolMap::WithoutAddFile(_) | InnerSymbolMap::Direct(_) => return None,
192 InnerSymbolMap::WithAddFile(inner) => inner.get_inner_symbol_map(),
193 };
194
195 let mut lookup_result: Option<FramesLookupResult> = inner.try_lookup_external(external);
196 loop {
197 let external = match lookup_result {
198 Some(FramesLookupResult::Available(frames)) => return Some(frames),
199 None => return None,
200 Some(FramesLookupResult::External(external)) => external,
201 };
202 let maybe_file_location = match &external.file_ref {
203 ExternalFileRef::MachoExternalObject { file_path } => self
204 .debug_file_location
205 .location_for_external_object_file(file_path),
206 ExternalFileRef::ElfExternalDwo { comp_dir, path } => {
207 self.debug_file_location.location_for_dwo(comp_dir, path)
208 }
209 };
210 let file_contents = match maybe_file_location {
211 Some(location) => helper.load_file(location).await.ok(),
212 None => None,
213 };
214 lookup_result = inner.try_lookup_external_with_file_contents(&external, file_contents);
215 }
216 }
217}