Coverage Report

Created: 2026-02-14 07:33

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