Coverage Report

Created: 2025-02-25 06:39

/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
}