/rust/registry/src/index.crates.io-6f17d22bba15001f/addr2line-0.24.2/src/unit.rs
Line | Count | Source (jump to first uncovered line) |
1 | | use alloc::boxed::Box; |
2 | | use alloc::sync::Arc; |
3 | | use alloc::vec::Vec; |
4 | | use core::cmp; |
5 | | |
6 | | use crate::lazy::LazyResult; |
7 | | use crate::{ |
8 | | Context, DebugFile, Error, Function, Functions, LazyFunctions, LazyLines, |
9 | | LineLocationRangeIter, Lines, Location, LookupContinuation, LookupResult, RangeAttributes, |
10 | | SimpleLookup, SplitDwarfLoad, |
11 | | }; |
12 | | |
13 | | pub(crate) struct UnitRange { |
14 | | unit_id: usize, |
15 | | min_begin: u64, |
16 | | range: gimli::Range, |
17 | | } |
18 | | |
19 | | pub(crate) struct ResUnit<R: gimli::Reader> { |
20 | | offset: gimli::DebugInfoOffset<R::Offset>, |
21 | | dw_unit: gimli::Unit<R>, |
22 | | pub(crate) lang: Option<gimli::DwLang>, |
23 | | lines: LazyLines, |
24 | | functions: LazyFunctions<R>, |
25 | | dwo: LazyResult<Option<Box<DwoUnit<R>>>>, |
26 | | } |
27 | | |
28 | | type UnitRef<'unit, R> = (DebugFile, gimli::UnitRef<'unit, R>); |
29 | | |
30 | | impl<R: gimli::Reader> ResUnit<R> { |
31 | 0 | pub(crate) fn unit_ref<'a>(&'a self, sections: &'a gimli::Dwarf<R>) -> gimli::UnitRef<'a, R> { |
32 | 0 | gimli::UnitRef::new(sections, &self.dw_unit) |
33 | 0 | } Unexecuted instantiation: <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::unit_ref Unexecuted instantiation: <addr2line::unit::ResUnit<_>>::unit_ref |
34 | | |
35 | | /// Returns the DWARF sections and the unit. |
36 | | /// |
37 | | /// Loads the DWO unit if necessary. |
38 | 0 | pub(crate) fn dwarf_and_unit<'unit, 'ctx: 'unit>( |
39 | 0 | &'unit self, |
40 | 0 | ctx: &'ctx Context<R>, |
41 | 0 | ) -> LookupResult< |
42 | 0 | SimpleLookup< |
43 | 0 | Result<UnitRef<'unit, R>, Error>, |
44 | 0 | R, |
45 | 0 | impl FnOnce(Option<Arc<gimli::Dwarf<R>>>) -> Result<UnitRef<'unit, R>, Error>, |
46 | 0 | >, |
47 | 0 | > { |
48 | 0 | let map_dwo = move |dwo: &'unit Result<Option<Box<DwoUnit<R>>>, Error>| match dwo { |
49 | 0 | Ok(Some(dwo)) => Ok((DebugFile::Dwo, dwo.unit_ref())), |
50 | 0 | Ok(None) => Ok((DebugFile::Primary, self.unit_ref(&*ctx.sections))), |
51 | 0 | Err(e) => Err(*e), |
52 | 0 | }; Unexecuted instantiation: <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::dwarf_and_unit::{closure#0} Unexecuted instantiation: <addr2line::unit::ResUnit<_>>::dwarf_and_unit::{closure#0} |
53 | 0 | let complete = |dwo| SimpleLookup::new_complete(map_dwo(dwo)); Unexecuted instantiation: <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::dwarf_and_unit::{closure#1} Unexecuted instantiation: <addr2line::unit::ResUnit<_>>::dwarf_and_unit::{closure#1} |
54 | | |
55 | 0 | if let Some(dwo) = self.dwo.borrow() { |
56 | 0 | return complete(dwo); |
57 | 0 | } |
58 | | |
59 | 0 | let dwo_id = match self.dw_unit.dwo_id { |
60 | | None => { |
61 | 0 | return complete(self.dwo.borrow_with(|| Ok(None))); Unexecuted instantiation: <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::dwarf_and_unit::{closure#2} Unexecuted instantiation: <addr2line::unit::ResUnit<_>>::dwarf_and_unit::{closure#2} |
62 | | } |
63 | 0 | Some(dwo_id) => dwo_id, |
64 | 0 | }; |
65 | 0 |
|
66 | 0 | let comp_dir = self.dw_unit.comp_dir.clone(); |
67 | 0 |
|
68 | 0 | let dwo_name = self.dw_unit.dwo_name().and_then(|s| { |
69 | 0 | if let Some(s) = s { |
70 | 0 | Ok(Some(ctx.sections.attr_string(&self.dw_unit, s)?)) |
71 | | } else { |
72 | 0 | Ok(None) |
73 | | } |
74 | 0 | }); Unexecuted instantiation: <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::dwarf_and_unit::{closure#3} Unexecuted instantiation: <addr2line::unit::ResUnit<_>>::dwarf_and_unit::{closure#3} |
75 | | |
76 | 0 | let path = match dwo_name { |
77 | 0 | Ok(v) => v, |
78 | 0 | Err(e) => { |
79 | 0 | return complete(self.dwo.borrow_with(|| Err(e))); Unexecuted instantiation: <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::dwarf_and_unit::{closure#4} Unexecuted instantiation: <addr2line::unit::ResUnit<_>>::dwarf_and_unit::{closure#4} |
80 | | } |
81 | | }; |
82 | | |
83 | 0 | let process_dwo = move |dwo_dwarf: Option<Arc<gimli::Dwarf<R>>>| { |
84 | 0 | let dwo_dwarf = match dwo_dwarf { |
85 | 0 | None => return Ok(None), |
86 | 0 | Some(dwo_dwarf) => dwo_dwarf, |
87 | 0 | }; |
88 | 0 | let mut dwo_units = dwo_dwarf.units(); |
89 | 0 | let dwo_header = match dwo_units.next()? { |
90 | 0 | Some(dwo_header) => dwo_header, |
91 | 0 | None => return Ok(None), |
92 | | }; |
93 | | |
94 | 0 | let mut dwo_unit = dwo_dwarf.unit(dwo_header)?; |
95 | 0 | dwo_unit.copy_relocated_attributes(&self.dw_unit); |
96 | 0 | Ok(Some(Box::new(DwoUnit { |
97 | 0 | sections: dwo_dwarf, |
98 | 0 | dw_unit: dwo_unit, |
99 | 0 | }))) |
100 | 0 | }; Unexecuted instantiation: <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::dwarf_and_unit::{closure#5} Unexecuted instantiation: <addr2line::unit::ResUnit<_>>::dwarf_and_unit::{closure#5} |
101 | | |
102 | 0 | SimpleLookup::new_needs_load( |
103 | 0 | SplitDwarfLoad { |
104 | 0 | dwo_id, |
105 | 0 | comp_dir, |
106 | 0 | path, |
107 | 0 | parent: ctx.sections.clone(), |
108 | 0 | }, |
109 | 0 | move |dwo_dwarf| map_dwo(self.dwo.borrow_with(|| process_dwo(dwo_dwarf))), Unexecuted instantiation: <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::dwarf_and_unit::{closure#6} Unexecuted instantiation: <addr2line::unit::ResUnit<_>>::dwarf_and_unit::{closure#6} Unexecuted instantiation: <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::dwarf_and_unit::{closure#6}::{closure#0} Unexecuted instantiation: <addr2line::unit::ResUnit<_>>::dwarf_and_unit::{closure#6}::{closure#0} |
110 | 0 | ) |
111 | 0 | } Unexecuted instantiation: <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::dwarf_and_unit Unexecuted instantiation: <addr2line::unit::ResUnit<_>>::dwarf_and_unit |
112 | | |
113 | 0 | pub(crate) fn parse_lines(&self, sections: &gimli::Dwarf<R>) -> Result<Option<&Lines>, Error> { |
114 | | // NB: line information is always stored in the main debug file so this does not need |
115 | | // to handle DWOs. |
116 | 0 | let ilnp = match self.dw_unit.line_program { |
117 | 0 | Some(ref ilnp) => ilnp, |
118 | 0 | None => return Ok(None), |
119 | | }; |
120 | 0 | self.lines.borrow(self.unit_ref(sections), ilnp).map(Some) |
121 | 0 | } Unexecuted instantiation: <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::parse_lines Unexecuted instantiation: <addr2line::unit::ResUnit<_>>::parse_lines |
122 | | |
123 | 0 | pub(crate) fn parse_functions<'unit, 'ctx: 'unit>( |
124 | 0 | &'unit self, |
125 | 0 | ctx: &'ctx Context<R>, |
126 | 0 | ) -> LookupResult<impl LookupContinuation<Output = Result<&'unit Functions<R>, Error>, Buf = R>> |
127 | 0 | { |
128 | 0 | self.dwarf_and_unit(ctx).map(move |r| { |
129 | 0 | let (_file, unit) = r?; |
130 | 0 | self.functions.borrow(unit) |
131 | 0 | }) |
132 | 0 | } |
133 | | |
134 | 0 | pub(crate) fn parse_inlined_functions<'unit, 'ctx: 'unit>( |
135 | 0 | &'unit self, |
136 | 0 | ctx: &'ctx Context<R>, |
137 | 0 | ) -> LookupResult<impl LookupContinuation<Output = Result<(), Error>, Buf = R> + 'unit> { |
138 | 0 | self.dwarf_and_unit(ctx).map(move |r| { |
139 | 0 | let (file, unit) = r?; |
140 | 0 | self.functions |
141 | 0 | .borrow(unit)? |
142 | 0 | .parse_inlined_functions(file, unit, ctx) |
143 | 0 | }) |
144 | 0 | } |
145 | | |
146 | 0 | pub(crate) fn find_location( |
147 | 0 | &self, |
148 | 0 | probe: u64, |
149 | 0 | sections: &gimli::Dwarf<R>, |
150 | 0 | ) -> Result<Option<Location<'_>>, Error> { |
151 | 0 | let Some(lines) = self.parse_lines(sections)? else { |
152 | 0 | return Ok(None); |
153 | | }; |
154 | 0 | lines.find_location(probe) |
155 | 0 | } Unexecuted instantiation: <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::find_location Unexecuted instantiation: <addr2line::unit::ResUnit<_>>::find_location |
156 | | |
157 | | #[inline] |
158 | 0 | pub(crate) fn find_location_range( |
159 | 0 | &self, |
160 | 0 | probe_low: u64, |
161 | 0 | probe_high: u64, |
162 | 0 | sections: &gimli::Dwarf<R>, |
163 | 0 | ) -> Result<Option<LineLocationRangeIter<'_>>, Error> { |
164 | 0 | let Some(lines) = self.parse_lines(sections)? else { |
165 | 0 | return Ok(None); |
166 | | }; |
167 | 0 | lines.find_location_range(probe_low, probe_high).map(Some) |
168 | 0 | } |
169 | | |
170 | 0 | pub(crate) fn find_function_or_location<'unit, 'ctx: 'unit>( |
171 | 0 | &'unit self, |
172 | 0 | probe: u64, |
173 | 0 | ctx: &'ctx Context<R>, |
174 | 0 | ) -> LookupResult< |
175 | 0 | impl LookupContinuation< |
176 | 0 | Output = Result<(Option<&'unit Function<R>>, Option<Location<'unit>>), Error>, |
177 | 0 | Buf = R, |
178 | 0 | >, |
179 | 0 | > { |
180 | 0 | self.dwarf_and_unit(ctx).map(move |r| { |
181 | 0 | let (file, unit) = r?; |
182 | 0 | let functions = self.functions.borrow(unit)?; |
183 | 0 | let function = match functions.find_address(probe) { |
184 | 0 | Some(address) => { |
185 | 0 | let function_index = functions.addresses[address].function; |
186 | 0 | let function = &functions.functions[function_index]; |
187 | 0 | Some(function.borrow(file, unit, ctx)?) |
188 | | } |
189 | 0 | None => None, |
190 | | }; |
191 | 0 | let location = self.find_location(probe, unit.dwarf)?; |
192 | 0 | Ok((function, location)) |
193 | 0 | }) Unexecuted instantiation: <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::find_function_or_location::{closure#0} Unexecuted instantiation: <addr2line::unit::ResUnit<_>>::find_function_or_location::{closure#0} |
194 | 0 | } Unexecuted instantiation: <addr2line::unit::ResUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::find_function_or_location Unexecuted instantiation: <addr2line::unit::ResUnit<_>>::find_function_or_location |
195 | | } |
196 | | |
197 | | pub(crate) struct ResUnits<R: gimli::Reader> { |
198 | | ranges: Box<[UnitRange]>, |
199 | | units: Box<[ResUnit<R>]>, |
200 | | } |
201 | | |
202 | | impl<R: gimli::Reader> ResUnits<R> { |
203 | 0 | pub(crate) fn parse(sections: &gimli::Dwarf<R>) -> Result<Self, Error> { |
204 | 0 | // Find all the references to compilation units in .debug_aranges. |
205 | 0 | // Note that we always also iterate through all of .debug_info to |
206 | 0 | // find compilation units, because .debug_aranges may be missing some. |
207 | 0 | let mut aranges = Vec::new(); |
208 | 0 | let mut headers = sections.debug_aranges.headers(); |
209 | 0 | while let Some(header) = headers.next()? { |
210 | 0 | aranges.push((header.debug_info_offset(), header.offset())); |
211 | 0 | } |
212 | 0 | aranges.sort_by_key(|i| i.0); Unexecuted instantiation: <addr2line::unit::ResUnits<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::parse::{closure#0} Unexecuted instantiation: <addr2line::unit::ResUnits<_>>::parse::{closure#0} |
213 | 0 |
|
214 | 0 | let mut unit_ranges = Vec::new(); |
215 | 0 | let mut res_units = Vec::new(); |
216 | 0 | let mut units = sections.units(); |
217 | 0 | while let Some(header) = units.next()? { |
218 | 0 | let unit_id = res_units.len(); |
219 | 0 | let offset = match header.offset().as_debug_info_offset() { |
220 | 0 | Some(offset) => offset, |
221 | 0 | None => continue, |
222 | | }; |
223 | | // We mainly want compile units, but we may need to follow references to entries |
224 | | // within other units for function names. We don't need anything from type units. |
225 | 0 | let mut need_unit_range = match header.type_() { |
226 | 0 | gimli::UnitType::Type { .. } | gimli::UnitType::SplitType { .. } => continue, |
227 | | gimli::UnitType::Partial => { |
228 | | // Partial units are only needed for references from other units. |
229 | | // They shouldn't have any address ranges. |
230 | 0 | false |
231 | | } |
232 | 0 | _ => true, |
233 | | }; |
234 | 0 | let dw_unit = match sections.unit(header) { |
235 | 0 | Ok(dw_unit) => dw_unit, |
236 | 0 | Err(_) => continue, |
237 | | }; |
238 | 0 | let dw_unit_ref = gimli::UnitRef::new(sections, &dw_unit); |
239 | 0 |
|
240 | 0 | let mut lang = None; |
241 | 0 | if need_unit_range { |
242 | 0 | let mut entries = dw_unit_ref.entries_raw(None)?; |
243 | | |
244 | 0 | let abbrev = match entries.read_abbreviation()? { |
245 | 0 | Some(abbrev) => abbrev, |
246 | 0 | None => continue, |
247 | | }; |
248 | | |
249 | 0 | let mut ranges = RangeAttributes::default(); |
250 | 0 | for spec in abbrev.attributes() { |
251 | 0 | let attr = entries.read_attribute(*spec)?; |
252 | 0 | match attr.name() { |
253 | 0 | gimli::DW_AT_low_pc => match attr.value() { |
254 | 0 | gimli::AttributeValue::Addr(val) => ranges.low_pc = Some(val), |
255 | 0 | gimli::AttributeValue::DebugAddrIndex(index) => { |
256 | 0 | ranges.low_pc = Some(dw_unit_ref.address(index)?); |
257 | | } |
258 | 0 | _ => {} |
259 | | }, |
260 | 0 | gimli::DW_AT_high_pc => match attr.value() { |
261 | 0 | gimli::AttributeValue::Addr(val) => ranges.high_pc = Some(val), |
262 | 0 | gimli::AttributeValue::DebugAddrIndex(index) => { |
263 | 0 | ranges.high_pc = Some(dw_unit_ref.address(index)?); |
264 | | } |
265 | 0 | gimli::AttributeValue::Udata(val) => ranges.size = Some(val), |
266 | 0 | _ => {} |
267 | | }, |
268 | | gimli::DW_AT_ranges => { |
269 | 0 | ranges.ranges_offset = dw_unit_ref.attr_ranges_offset(attr.value())?; |
270 | | } |
271 | | gimli::DW_AT_language => { |
272 | 0 | if let gimli::AttributeValue::Language(val) = attr.value() { |
273 | 0 | lang = Some(val); |
274 | 0 | } |
275 | | } |
276 | 0 | _ => {} |
277 | | } |
278 | | } |
279 | | |
280 | | // Find the address ranges for the CU, using in order of preference: |
281 | | // - DW_AT_ranges |
282 | | // - .debug_aranges |
283 | | // - DW_AT_low_pc/DW_AT_high_pc |
284 | | // |
285 | | // Using DW_AT_ranges before .debug_aranges is possibly an arbitrary choice, |
286 | | // but the feeling is that DW_AT_ranges is more likely to be reliable or complete |
287 | | // if it is present. |
288 | | // |
289 | | // .debug_aranges must be used before DW_AT_low_pc/DW_AT_high_pc because |
290 | | // it has been observed on macOS that DW_AT_ranges was not emitted even for |
291 | | // discontiguous CUs. |
292 | 0 | let i = match ranges.ranges_offset { |
293 | 0 | Some(_) => None, |
294 | 0 | None => aranges.binary_search_by_key(&offset, |x| x.0).ok(), Unexecuted instantiation: <addr2line::unit::ResUnits<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::parse::{closure#1} Unexecuted instantiation: <addr2line::unit::ResUnits<_>>::parse::{closure#1} |
295 | | }; |
296 | 0 | if let Some(mut i) = i { |
297 | | // There should be only one set per CU, but in practice multiple |
298 | | // sets have been observed. This is probably a compiler bug, but |
299 | | // either way we need to handle it. |
300 | 0 | while i > 0 && aranges[i - 1].0 == offset { |
301 | 0 | i -= 1; |
302 | 0 | } |
303 | 0 | for (_, aranges_offset) in aranges[i..].iter().take_while(|x| x.0 == offset) { Unexecuted instantiation: <addr2line::unit::ResUnits<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::parse::{closure#2} Unexecuted instantiation: <addr2line::unit::ResUnits<_>>::parse::{closure#2} |
304 | 0 | let aranges_header = sections.debug_aranges.header(*aranges_offset)?; |
305 | 0 | let mut aranges = aranges_header.entries(); |
306 | 0 | while let Some(arange) = aranges.next()? { |
307 | 0 | if arange.length() != 0 { |
308 | 0 | unit_ranges.push(UnitRange { |
309 | 0 | range: arange.range(), |
310 | 0 | unit_id, |
311 | 0 | min_begin: 0, |
312 | 0 | }); |
313 | 0 | need_unit_range = false; |
314 | 0 | } |
315 | | } |
316 | | } |
317 | | } else { |
318 | 0 | need_unit_range &= !ranges.for_each_range(dw_unit_ref, |range| { |
319 | 0 | unit_ranges.push(UnitRange { |
320 | 0 | range, |
321 | 0 | unit_id, |
322 | 0 | min_begin: 0, |
323 | 0 | }); |
324 | 0 | })?; Unexecuted instantiation: <addr2line::unit::ResUnits<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::parse::{closure#3} Unexecuted instantiation: <addr2line::unit::ResUnits<_>>::parse::{closure#3} |
325 | | } |
326 | 0 | } |
327 | | |
328 | 0 | let lines = LazyLines::new(); |
329 | 0 | if need_unit_range { |
330 | | // The unit did not declare any ranges. |
331 | | // Try to get some ranges from the line program sequences. |
332 | 0 | if let Some(ref ilnp) = dw_unit_ref.line_program { |
333 | 0 | if let Ok(lines) = lines.borrow(dw_unit_ref, ilnp) { |
334 | 0 | for range in lines.ranges() { |
335 | 0 | unit_ranges.push(UnitRange { |
336 | 0 | range, |
337 | 0 | unit_id, |
338 | 0 | min_begin: 0, |
339 | 0 | }) |
340 | | } |
341 | 0 | } |
342 | 0 | } |
343 | 0 | } |
344 | | |
345 | 0 | res_units.push(ResUnit { |
346 | 0 | offset, |
347 | 0 | dw_unit, |
348 | 0 | lang, |
349 | 0 | lines, |
350 | 0 | functions: LazyFunctions::new(), |
351 | 0 | dwo: LazyResult::new(), |
352 | 0 | }); |
353 | | } |
354 | | |
355 | | // Sort this for faster lookup in `Self::find_range`. |
356 | 0 | unit_ranges.sort_by_key(|i| i.range.end); Unexecuted instantiation: <addr2line::unit::ResUnits<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::parse::{closure#4} Unexecuted instantiation: <addr2line::unit::ResUnits<_>>::parse::{closure#4} |
357 | 0 |
|
358 | 0 | // Calculate the `min_begin` field now that we've determined the order of |
359 | 0 | // CUs. |
360 | 0 | let mut min = !0; |
361 | 0 | for i in unit_ranges.iter_mut().rev() { |
362 | 0 | min = min.min(i.range.begin); |
363 | 0 | i.min_begin = min; |
364 | 0 | } |
365 | | |
366 | 0 | Ok(ResUnits { |
367 | 0 | ranges: unit_ranges.into_boxed_slice(), |
368 | 0 | units: res_units.into_boxed_slice(), |
369 | 0 | }) |
370 | 0 | } Unexecuted instantiation: <addr2line::unit::ResUnits<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::parse Unexecuted instantiation: <addr2line::unit::ResUnits<_>>::parse |
371 | | |
372 | 0 | pub(crate) fn iter(&self) -> impl Iterator<Item = &ResUnit<R>> { |
373 | 0 | self.units.iter() |
374 | 0 | } |
375 | | |
376 | 0 | pub(crate) fn find_offset( |
377 | 0 | &self, |
378 | 0 | offset: gimli::DebugInfoOffset<R::Offset>, |
379 | 0 | ) -> Result<&gimli::Unit<R>, Error> { |
380 | 0 | match self |
381 | 0 | .units |
382 | 0 | .binary_search_by_key(&offset.0, |unit| unit.offset.0) Unexecuted instantiation: <addr2line::unit::ResUnits<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::find_offset::{closure#0} Unexecuted instantiation: <addr2line::unit::ResUnits<_>>::find_offset::{closure#0} |
383 | | { |
384 | | // There is never a DIE at the unit offset or before the first unit. |
385 | 0 | Ok(_) | Err(0) => Err(gimli::Error::NoEntryAtGivenOffset), |
386 | 0 | Err(i) => Ok(&self.units[i - 1].dw_unit), |
387 | | } |
388 | 0 | } Unexecuted instantiation: <addr2line::unit::ResUnits<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::find_offset Unexecuted instantiation: <addr2line::unit::ResUnits<_>>::find_offset |
389 | | |
390 | | /// Finds the CUs for the function address given. |
391 | | /// |
392 | | /// There might be multiple CUs whose range contains this address. |
393 | | /// Weak symbols have shown up in the wild which cause this to happen |
394 | | /// but otherwise this can happen if the CU has non-contiguous functions |
395 | | /// but only reports a single range. |
396 | | /// |
397 | | /// Consequently we return an iterator for all CUs which may contain the |
398 | | /// address, and the caller must check if there is actually a function or |
399 | | /// location in the CU for that address. |
400 | 0 | pub(crate) fn find(&self, probe: u64) -> impl Iterator<Item = &ResUnit<R>> { |
401 | 0 | self.find_range(probe, probe + 1).map(|(unit, _range)| unit) Unexecuted instantiation: <addr2line::unit::ResUnits<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::find::{closure#0} Unexecuted instantiation: <addr2line::unit::ResUnits<_>>::find::{closure#0} |
402 | 0 | } Unexecuted instantiation: <addr2line::unit::ResUnits<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::find Unexecuted instantiation: <addr2line::unit::ResUnits<_>>::find |
403 | | |
404 | | /// Finds the CUs covering the range of addresses given. |
405 | | /// |
406 | | /// The range is [low, high) (ie, the upper bound is exclusive). This can return multiple |
407 | | /// ranges for the same unit. |
408 | | #[inline] |
409 | 0 | pub(crate) fn find_range( |
410 | 0 | &self, |
411 | 0 | probe_low: u64, |
412 | 0 | probe_high: u64, |
413 | 0 | ) -> impl Iterator<Item = (&ResUnit<R>, &gimli::Range)> { |
414 | | // Find the position of the next range after a range which |
415 | | // ends at `probe_low` or lower. |
416 | 0 | let pos = match self |
417 | 0 | .ranges |
418 | 0 | .binary_search_by_key(&probe_low, |i| i.range.end) Unexecuted instantiation: <addr2line::unit::ResUnits<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::find_range::{closure#0} Unexecuted instantiation: <addr2line::unit::ResUnits<_>>::find_range::{closure#0} |
419 | | { |
420 | 0 | Ok(i) => i + 1, // Range `i` ends at exactly `probe_low`. |
421 | 0 | Err(i) => i, // Range `i - 1` ends at a lower address. |
422 | | }; |
423 | | |
424 | | // Iterate from that position to find matching CUs. |
425 | 0 | self.ranges[pos..] |
426 | 0 | .iter() |
427 | 0 | .take_while(move |i| { |
428 | 0 | // We know that this CU's end is at least `probe_low` because |
429 | 0 | // of our sorted array. |
430 | 0 | debug_assert!(i.range.end >= probe_low); |
431 | | |
432 | | // Each entry keeps track of the minimum begin address for the |
433 | | // remainder of the array of unit ranges. If our probe is before |
434 | | // the minimum range begin of this entry, then it's guaranteed |
435 | | // to not fit in any subsequent entries, so we break out. |
436 | 0 | probe_high > i.min_begin |
437 | 0 | }) Unexecuted instantiation: <addr2line::unit::ResUnits<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::find_range::{closure#1} Unexecuted instantiation: <addr2line::unit::ResUnits<_>>::find_range::{closure#1} |
438 | 0 | .filter_map(move |i| { |
439 | 0 | // If this CU doesn't actually contain this address, move to the |
440 | 0 | // next CU. |
441 | 0 | if probe_low >= i.range.end || probe_high <= i.range.begin { |
442 | 0 | return None; |
443 | 0 | } |
444 | 0 | Some((&self.units[i.unit_id], &i.range)) |
445 | 0 | }) Unexecuted instantiation: <addr2line::unit::ResUnits<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::find_range::{closure#2} Unexecuted instantiation: <addr2line::unit::ResUnits<_>>::find_range::{closure#2} |
446 | 0 | } Unexecuted instantiation: <addr2line::unit::ResUnits<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::find_range Unexecuted instantiation: <addr2line::unit::ResUnits<_>>::find_range |
447 | | |
448 | 0 | pub(crate) fn find_location_range<'a>( |
449 | 0 | &'a self, |
450 | 0 | probe_low: u64, |
451 | 0 | probe_high: u64, |
452 | 0 | sections: &'a gimli::Dwarf<R>, |
453 | 0 | ) -> Result<LocationRangeIter<'a, R>, Error> { |
454 | 0 | let unit_iter = Box::new(self.find_range(probe_low, probe_high)); |
455 | 0 | Ok(LocationRangeIter { |
456 | 0 | unit_iter, |
457 | 0 | iter: None, |
458 | 0 | probe_low, |
459 | 0 | probe_high, |
460 | 0 | sections, |
461 | 0 | }) |
462 | 0 | } |
463 | | } |
464 | | |
465 | | /// A DWO unit has its own DWARF sections. |
466 | | struct DwoUnit<R: gimli::Reader> { |
467 | | sections: Arc<gimli::Dwarf<R>>, |
468 | | dw_unit: gimli::Unit<R>, |
469 | | } |
470 | | |
471 | | impl<R: gimli::Reader> DwoUnit<R> { |
472 | 0 | fn unit_ref(&self) -> gimli::UnitRef<R> { |
473 | 0 | gimli::UnitRef::new(&self.sections, &self.dw_unit) |
474 | 0 | } Unexecuted instantiation: <addr2line::unit::DwoUnit<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::unit_ref Unexecuted instantiation: <addr2line::unit::DwoUnit<_>>::unit_ref |
475 | | } |
476 | | |
477 | | pub(crate) struct SupUnit<R: gimli::Reader> { |
478 | | offset: gimli::DebugInfoOffset<R::Offset>, |
479 | | dw_unit: gimli::Unit<R>, |
480 | | } |
481 | | |
482 | | pub(crate) struct SupUnits<R: gimli::Reader> { |
483 | | units: Box<[SupUnit<R>]>, |
484 | | } |
485 | | |
486 | | impl<R: gimli::Reader> Default for SupUnits<R> { |
487 | 0 | fn default() -> Self { |
488 | 0 | SupUnits { |
489 | 0 | units: Box::default(), |
490 | 0 | } |
491 | 0 | } Unexecuted instantiation: <addr2line::unit::SupUnits<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>> as core::default::Default>::default Unexecuted instantiation: <addr2line::unit::SupUnits<_> as core::default::Default>::default |
492 | | } |
493 | | |
494 | | impl<R: gimli::Reader> SupUnits<R> { |
495 | 0 | pub(crate) fn parse(sections: &gimli::Dwarf<R>) -> Result<Self, Error> { |
496 | 0 | let mut sup_units = Vec::new(); |
497 | 0 | let mut units = sections.units(); |
498 | 0 | while let Some(header) = units.next()? { |
499 | 0 | let offset = match header.offset().as_debug_info_offset() { |
500 | 0 | Some(offset) => offset, |
501 | 0 | None => continue, |
502 | | }; |
503 | 0 | let dw_unit = match sections.unit(header) { |
504 | 0 | Ok(dw_unit) => dw_unit, |
505 | 0 | Err(_) => continue, |
506 | | }; |
507 | 0 | sup_units.push(SupUnit { dw_unit, offset }); |
508 | | } |
509 | 0 | Ok(SupUnits { |
510 | 0 | units: sup_units.into_boxed_slice(), |
511 | 0 | }) |
512 | 0 | } Unexecuted instantiation: <addr2line::unit::SupUnits<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::parse Unexecuted instantiation: <addr2line::unit::SupUnits<_>>::parse |
513 | | |
514 | 0 | pub(crate) fn find_offset( |
515 | 0 | &self, |
516 | 0 | offset: gimli::DebugInfoOffset<R::Offset>, |
517 | 0 | ) -> Result<&gimli::Unit<R>, Error> { |
518 | 0 | match self |
519 | 0 | .units |
520 | 0 | .binary_search_by_key(&offset.0, |unit| unit.offset.0) Unexecuted instantiation: <addr2line::unit::SupUnits<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::find_offset::{closure#0} Unexecuted instantiation: <addr2line::unit::SupUnits<_>>::find_offset::{closure#0} |
521 | | { |
522 | | // There is never a DIE at the unit offset or before the first unit. |
523 | 0 | Ok(_) | Err(0) => Err(gimli::Error::NoEntryAtGivenOffset), |
524 | 0 | Err(i) => Ok(&self.units[i - 1].dw_unit), |
525 | | } |
526 | 0 | } Unexecuted instantiation: <addr2line::unit::SupUnits<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::find_offset Unexecuted instantiation: <addr2line::unit::SupUnits<_>>::find_offset |
527 | | } |
528 | | |
529 | | /// Iterator over `Location`s in a range of addresses, returned by `Context::find_location_range`. |
530 | | pub struct LocationRangeIter<'ctx, R: gimli::Reader> { |
531 | | unit_iter: Box<dyn Iterator<Item = (&'ctx ResUnit<R>, &'ctx gimli::Range)> + 'ctx>, |
532 | | iter: Option<LineLocationRangeIter<'ctx>>, |
533 | | |
534 | | probe_low: u64, |
535 | | probe_high: u64, |
536 | | sections: &'ctx gimli::Dwarf<R>, |
537 | | } |
538 | | |
539 | | impl<'ctx, R: gimli::Reader> LocationRangeIter<'ctx, R> { |
540 | 0 | fn next_loc(&mut self) -> Result<Option<(u64, u64, Location<'ctx>)>, Error> { |
541 | | loop { |
542 | 0 | let iter = self.iter.take(); |
543 | 0 | match iter { |
544 | 0 | None => match self.unit_iter.next() { |
545 | 0 | Some((unit, range)) => { |
546 | 0 | self.iter = unit.find_location_range( |
547 | 0 | cmp::max(self.probe_low, range.begin), |
548 | 0 | cmp::min(self.probe_high, range.end), |
549 | 0 | self.sections, |
550 | 0 | )?; |
551 | | } |
552 | 0 | None => return Ok(None), |
553 | | }, |
554 | 0 | Some(mut iter) => { |
555 | 0 | if let item @ Some(_) = iter.next() { |
556 | 0 | self.iter = Some(iter); |
557 | 0 | return Ok(item); |
558 | 0 | } |
559 | | } |
560 | | } |
561 | | } |
562 | 0 | } |
563 | | } |
564 | | |
565 | | impl<'ctx, R> Iterator for LocationRangeIter<'ctx, R> |
566 | | where |
567 | | R: gimli::Reader + 'ctx, |
568 | | { |
569 | | type Item = (u64, u64, Location<'ctx>); |
570 | | |
571 | | #[inline] |
572 | 0 | fn next(&mut self) -> Option<Self::Item> { |
573 | 0 | self.next_loc().unwrap_or_default() |
574 | 0 | } |
575 | | } |
576 | | |
577 | | #[cfg(feature = "fallible-iterator")] |
578 | | impl<'ctx, R> fallible_iterator::FallibleIterator for LocationRangeIter<'ctx, R> |
579 | | where |
580 | | R: gimli::Reader + 'ctx, |
581 | | { |
582 | | type Item = (u64, u64, Location<'ctx>); |
583 | | type Error = Error; |
584 | | |
585 | | #[inline] |
586 | | fn next(&mut self) -> Result<Option<Self::Item>, Self::Error> { |
587 | | self.next_loc() |
588 | | } |
589 | | } |