gimli/read/
rnglists.rs

1use crate::common::{
2    DebugAddrBase, DebugAddrIndex, DebugRngListsBase, DebugRngListsIndex, DwarfFileType, Encoding,
3    RangeListsOffset, SectionId,
4};
5use crate::constants;
6use crate::endianity::Endianity;
7use crate::read::{
8    lists::ListsHeader, DebugAddr, EndianSlice, Error, Reader, ReaderAddress, ReaderOffset,
9    ReaderOffsetId, Result, Section,
10};
11
12/// The raw contents of the `.debug_ranges` section.
13#[derive(Debug, Default, Clone, Copy)]
14pub struct DebugRanges<R> {
15    pub(crate) section: R,
16}
17
18impl<'input, Endian> DebugRanges<EndianSlice<'input, Endian>>
19where
20    Endian: Endianity,
21{
22    /// Construct a new `DebugRanges` instance from the data in the `.debug_ranges`
23    /// section.
24    ///
25    /// It is the caller's responsibility to read the `.debug_ranges` section and
26    /// present it as a `&[u8]` slice. That means using some ELF loader on
27    /// Linux, a Mach-O loader on macOS, etc.
28    ///
29    /// ```
30    /// use gimli::{DebugRanges, LittleEndian};
31    ///
32    /// # let buf = [0x00, 0x01, 0x02, 0x03];
33    /// # let read_debug_ranges_section_somehow = || &buf;
34    /// let debug_ranges = DebugRanges::new(read_debug_ranges_section_somehow(), LittleEndian);
35    /// ```
36    pub fn new(section: &'input [u8], endian: Endian) -> Self {
37        Self::from(EndianSlice::new(section, endian))
38    }
39}
40
41impl<T> DebugRanges<T> {
42    /// Create a `DebugRanges` section that references the data in `self`.
43    ///
44    /// This is useful when `R` implements `Reader` but `T` does not.
45    ///
46    /// Used by `DwarfSections::borrow`.
47    pub(crate) fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugRanges<R>
48    where
49        F: FnMut(&'a T) -> R,
50    {
51        borrow(&self.section).into()
52    }
53}
54
55impl<R> Section<R> for DebugRanges<R> {
56    fn id() -> SectionId {
57        SectionId::DebugRanges
58    }
59
60    fn reader(&self) -> &R {
61        &self.section
62    }
63}
64
65impl<R> From<R> for DebugRanges<R> {
66    fn from(section: R) -> Self {
67        DebugRanges { section }
68    }
69}
70
71/// The `DebugRngLists` struct represents the contents of the
72/// `.debug_rnglists` section.
73#[derive(Debug, Default, Clone, Copy)]
74pub struct DebugRngLists<R> {
75    section: R,
76}
77
78impl<'input, Endian> DebugRngLists<EndianSlice<'input, Endian>>
79where
80    Endian: Endianity,
81{
82    /// Construct a new `DebugRngLists` instance from the data in the
83    /// `.debug_rnglists` section.
84    ///
85    /// It is the caller's responsibility to read the `.debug_rnglists`
86    /// section and present it as a `&[u8]` slice. That means using some ELF
87    /// loader on Linux, a Mach-O loader on macOS, etc.
88    ///
89    /// ```
90    /// use gimli::{DebugRngLists, LittleEndian};
91    ///
92    /// # let buf = [0x00, 0x01, 0x02, 0x03];
93    /// # let read_debug_rnglists_section_somehow = || &buf;
94    /// let debug_rnglists =
95    ///     DebugRngLists::new(read_debug_rnglists_section_somehow(), LittleEndian);
96    /// ```
97    pub fn new(section: &'input [u8], endian: Endian) -> Self {
98        Self::from(EndianSlice::new(section, endian))
99    }
100}
101
102impl<T> DebugRngLists<T> {
103    /// Create a `DebugRngLists` section that references the data in `self`.
104    ///
105    /// This is useful when `R` implements `Reader` but `T` does not.
106    ///
107    /// Used by `DwarfSections::borrow`.
108    pub(crate) fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugRngLists<R>
109    where
110        F: FnMut(&'a T) -> R,
111    {
112        borrow(&self.section).into()
113    }
114}
115
116impl<R> Section<R> for DebugRngLists<R> {
117    fn id() -> SectionId {
118        SectionId::DebugRngLists
119    }
120
121    fn reader(&self) -> &R {
122        &self.section
123    }
124}
125
126impl<R> From<R> for DebugRngLists<R> {
127    fn from(section: R) -> Self {
128        DebugRngLists { section }
129    }
130}
131
132#[allow(unused)]
133pub(crate) type RngListsHeader = ListsHeader;
134
135impl<Offset> DebugRngListsBase<Offset>
136where
137    Offset: ReaderOffset,
138{
139    /// Returns a `DebugRngListsBase` with the default value of DW_AT_rnglists_base
140    /// for the given `Encoding` and `DwarfFileType`.
141    pub fn default_for_encoding_and_file(
142        encoding: Encoding,
143        file_type: DwarfFileType,
144    ) -> DebugRngListsBase<Offset> {
145        if encoding.version >= 5 && file_type == DwarfFileType::Dwo {
146            // In .dwo files, the compiler omits the DW_AT_rnglists_base attribute (because there is
147            // only a single unit in the file) but we must skip past the header, which the attribute
148            // would normally do for us.
149            DebugRngListsBase(Offset::from_u8(RngListsHeader::size_for_encoding(encoding)))
150        } else {
151            DebugRngListsBase(Offset::from_u8(0))
152        }
153    }
154}
155
156/// The DWARF data found in `.debug_ranges` and `.debug_rnglists` sections.
157#[derive(Debug, Default, Clone, Copy)]
158pub struct RangeLists<R> {
159    debug_ranges: DebugRanges<R>,
160    debug_rnglists: DebugRngLists<R>,
161}
162
163impl<R> RangeLists<R> {
164    /// Construct a new `RangeLists` instance from the data in the `.debug_ranges` and
165    /// `.debug_rnglists` sections.
166    pub fn new(debug_ranges: DebugRanges<R>, debug_rnglists: DebugRngLists<R>) -> RangeLists<R> {
167        RangeLists {
168            debug_ranges,
169            debug_rnglists,
170        }
171    }
172
173    /// Return the `.debug_ranges` section.
174    pub fn debug_ranges(&self) -> &DebugRanges<R> {
175        &self.debug_ranges
176    }
177
178    /// Replace the `.debug_ranges` section.
179    ///
180    /// This is useful for `.dwo` files when using the GNU split-dwarf extension to DWARF 4.
181    pub fn set_debug_ranges(&mut self, debug_ranges: DebugRanges<R>) {
182        self.debug_ranges = debug_ranges;
183    }
184
185    /// Return the `.debug_rnglists` section.
186    pub fn debug_rnglists(&self) -> &DebugRngLists<R> {
187        &self.debug_rnglists
188    }
189}
190
191impl<T> RangeLists<T> {
192    /// Create a `RangeLists` that references the data in `self`.
193    ///
194    /// This is useful when `R` implements `Reader` but `T` does not.
195    ///
196    /// Used by `Dwarf::borrow`.
197    pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> RangeLists<R>
198    where
199        F: FnMut(&'a T) -> R,
200    {
201        RangeLists {
202            debug_ranges: borrow(&self.debug_ranges.section).into(),
203            debug_rnglists: borrow(&self.debug_rnglists.section).into(),
204        }
205    }
206}
207
208impl<R: Reader> RangeLists<R> {
209    /// Iterate over the `Range` list entries starting at the given offset.
210    ///
211    /// The `unit_version` and `address_size` must match the compilation unit that the
212    /// offset was contained in.
213    ///
214    /// The `base_address` should be obtained from the `DW_AT_low_pc` attribute in the
215    /// `DW_TAG_compile_unit` entry for the compilation unit that contains this range list.
216    ///
217    /// Can be [used with
218    /// `FallibleIterator`](./index.html#using-with-fallibleiterator).
219    pub fn ranges(
220        &self,
221        offset: RangeListsOffset<R::Offset>,
222        unit_encoding: Encoding,
223        base_address: u64,
224        debug_addr: &DebugAddr<R>,
225        debug_addr_base: DebugAddrBase<R::Offset>,
226    ) -> Result<RngListIter<R>> {
227        Ok(RngListIter::new(
228            self.raw_ranges(offset, unit_encoding)?,
229            base_address,
230            debug_addr.clone(),
231            debug_addr_base,
232        ))
233    }
234
235    /// Iterate over the `RawRngListEntry`ies starting at the given offset.
236    ///
237    /// The `unit_encoding` must match the compilation unit that the
238    /// offset was contained in.
239    ///
240    /// This iterator does not perform any processing of the range entries,
241    /// such as handling base addresses.
242    ///
243    /// Can be [used with
244    /// `FallibleIterator`](./index.html#using-with-fallibleiterator).
245    pub fn raw_ranges(
246        &self,
247        offset: RangeListsOffset<R::Offset>,
248        unit_encoding: Encoding,
249    ) -> Result<RawRngListIter<R>> {
250        let (mut input, format) = if unit_encoding.version <= 4 {
251            (self.debug_ranges.section.clone(), RangeListsFormat::Bare)
252        } else {
253            (self.debug_rnglists.section.clone(), RangeListsFormat::Rle)
254        };
255        input.skip(offset.0)?;
256        Ok(RawRngListIter::new(input, unit_encoding, format))
257    }
258
259    /// Returns the `.debug_rnglists` offset at the given `base` and `index`.
260    ///
261    /// The `base` must be the `DW_AT_rnglists_base` value from the compilation unit DIE.
262    /// This is an offset that points to the first entry following the header.
263    ///
264    /// The `index` is the value of a `DW_FORM_rnglistx` attribute.
265    ///
266    /// The `unit_encoding` must match the compilation unit that the
267    /// index was contained in.
268    pub fn get_offset(
269        &self,
270        unit_encoding: Encoding,
271        base: DebugRngListsBase<R::Offset>,
272        index: DebugRngListsIndex<R::Offset>,
273    ) -> Result<RangeListsOffset<R::Offset>> {
274        let format = unit_encoding.format;
275        let input = &mut self.debug_rnglists.section.clone();
276        input.skip(base.0)?;
277        input.skip(R::Offset::from_u64(
278            index.0.into_u64() * u64::from(format.word_size()),
279        )?)?;
280        input
281            .read_offset(format)
282            .map(|x| RangeListsOffset(base.0 + x))
283    }
284
285    /// Call `Reader::lookup_offset_id` for each section, and return the first match.
286    pub fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(SectionId, R::Offset)> {
287        self.debug_ranges
288            .lookup_offset_id(id)
289            .or_else(|| self.debug_rnglists.lookup_offset_id(id))
290    }
291}
292
293#[derive(Debug, Clone, Copy, PartialEq, Eq)]
294enum RangeListsFormat {
295    /// The bare range list format used before DWARF 5.
296    Bare,
297    /// The DW_RLE encoded range list format used in DWARF 5.
298    Rle,
299}
300
301/// A raw iterator over an address range list.
302///
303/// This iterator does not perform any processing of the range entries,
304/// such as handling base addresses.
305#[derive(Debug)]
306pub struct RawRngListIter<R: Reader> {
307    input: R,
308    encoding: Encoding,
309    format: RangeListsFormat,
310}
311
312/// A raw entry in .debug_rnglists
313#[derive(Clone, Debug)]
314pub enum RawRngListEntry<T> {
315    /// A range from DWARF version <= 4.
316    AddressOrOffsetPair {
317        /// Start of range. May be an address or an offset.
318        begin: u64,
319        /// End of range. May be an address or an offset.
320        end: u64,
321    },
322    /// DW_RLE_base_address
323    BaseAddress {
324        /// base address
325        addr: u64,
326    },
327    /// DW_RLE_base_addressx
328    BaseAddressx {
329        /// base address
330        addr: DebugAddrIndex<T>,
331    },
332    /// DW_RLE_startx_endx
333    StartxEndx {
334        /// start of range
335        begin: DebugAddrIndex<T>,
336        /// end of range
337        end: DebugAddrIndex<T>,
338    },
339    /// DW_RLE_startx_length
340    StartxLength {
341        /// start of range
342        begin: DebugAddrIndex<T>,
343        /// length of range
344        length: u64,
345    },
346    /// DW_RLE_offset_pair
347    OffsetPair {
348        /// start of range
349        begin: u64,
350        /// end of range
351        end: u64,
352    },
353    /// DW_RLE_start_end
354    StartEnd {
355        /// start of range
356        begin: u64,
357        /// end of range
358        end: u64,
359    },
360    /// DW_RLE_start_length
361    StartLength {
362        /// start of range
363        begin: u64,
364        /// length of range
365        length: u64,
366    },
367}
368
369impl<T: ReaderOffset> RawRngListEntry<T> {
370    /// Parse a range entry from `.debug_rnglists`
371    fn parse<R: Reader<Offset = T>>(
372        input: &mut R,
373        encoding: Encoding,
374        format: RangeListsFormat,
375    ) -> Result<Option<Self>> {
376        Ok(match format {
377            RangeListsFormat::Bare => {
378                let range = RawRange::parse(input, encoding.address_size)?;
379                if range.is_end() {
380                    None
381                } else if range.is_base_address(encoding.address_size) {
382                    Some(RawRngListEntry::BaseAddress { addr: range.end })
383                } else {
384                    Some(RawRngListEntry::AddressOrOffsetPair {
385                        begin: range.begin,
386                        end: range.end,
387                    })
388                }
389            }
390            RangeListsFormat::Rle => match constants::DwRle(input.read_u8()?) {
391                constants::DW_RLE_end_of_list => None,
392                constants::DW_RLE_base_addressx => Some(RawRngListEntry::BaseAddressx {
393                    addr: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?),
394                }),
395                constants::DW_RLE_startx_endx => Some(RawRngListEntry::StartxEndx {
396                    begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?),
397                    end: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?),
398                }),
399                constants::DW_RLE_startx_length => Some(RawRngListEntry::StartxLength {
400                    begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?),
401                    length: input.read_uleb128()?,
402                }),
403                constants::DW_RLE_offset_pair => Some(RawRngListEntry::OffsetPair {
404                    begin: input.read_uleb128()?,
405                    end: input.read_uleb128()?,
406                }),
407                constants::DW_RLE_base_address => Some(RawRngListEntry::BaseAddress {
408                    addr: input.read_address(encoding.address_size)?,
409                }),
410                constants::DW_RLE_start_end => Some(RawRngListEntry::StartEnd {
411                    begin: input.read_address(encoding.address_size)?,
412                    end: input.read_address(encoding.address_size)?,
413                }),
414                constants::DW_RLE_start_length => Some(RawRngListEntry::StartLength {
415                    begin: input.read_address(encoding.address_size)?,
416                    length: input.read_uleb128()?,
417                }),
418                entry => {
419                    return Err(Error::UnknownRangeListsEntry(entry));
420                }
421            },
422        })
423    }
424}
425
426impl<R: Reader> RawRngListIter<R> {
427    /// Construct a `RawRngListIter`.
428    fn new(input: R, encoding: Encoding, format: RangeListsFormat) -> RawRngListIter<R> {
429        RawRngListIter {
430            input,
431            encoding,
432            format,
433        }
434    }
435
436    /// Advance the iterator to the next range.
437    pub fn next(&mut self) -> Result<Option<RawRngListEntry<R::Offset>>> {
438        if self.input.is_empty() {
439            return Ok(None);
440        }
441
442        match RawRngListEntry::parse(&mut self.input, self.encoding, self.format) {
443            Ok(range) => {
444                if range.is_none() {
445                    self.input.empty();
446                }
447                Ok(range)
448            }
449            Err(e) => {
450                self.input.empty();
451                Err(e)
452            }
453        }
454    }
455}
456
457#[cfg(feature = "fallible-iterator")]
458impl<R: Reader> fallible_iterator::FallibleIterator for RawRngListIter<R> {
459    type Item = RawRngListEntry<R::Offset>;
460    type Error = Error;
461
462    fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
463        RawRngListIter::next(self)
464    }
465}
466
467/// An iterator over an address range list.
468///
469/// This iterator internally handles processing of base addresses and different
470/// entry types.  Thus, it only returns range entries that are valid
471/// and already adjusted for the base address.
472#[derive(Debug)]
473pub struct RngListIter<R: Reader> {
474    raw: RawRngListIter<R>,
475    base_address: u64,
476    debug_addr: DebugAddr<R>,
477    debug_addr_base: DebugAddrBase<R::Offset>,
478}
479
480impl<R: Reader> RngListIter<R> {
481    /// Construct a `RngListIter`.
482    fn new(
483        raw: RawRngListIter<R>,
484        base_address: u64,
485        debug_addr: DebugAddr<R>,
486        debug_addr_base: DebugAddrBase<R::Offset>,
487    ) -> RngListIter<R> {
488        RngListIter {
489            raw,
490            base_address,
491            debug_addr,
492            debug_addr_base,
493        }
494    }
495
496    #[inline]
497    fn get_address(&self, index: DebugAddrIndex<R::Offset>) -> Result<u64> {
498        self.debug_addr
499            .get_address(self.raw.encoding.address_size, self.debug_addr_base, index)
500    }
501
502    /// Advance the iterator to the next range.
503    pub fn next(&mut self) -> Result<Option<Range>> {
504        loop {
505            let raw_range = match self.raw.next()? {
506                Some(range) => range,
507                None => return Ok(None),
508            };
509
510            let range = self.convert_raw(raw_range)?;
511            if range.is_some() {
512                return Ok(range);
513            }
514        }
515    }
516
517    /// Return the next raw range.
518    ///
519    /// The raw range should be passed to `convert_range`.
520    #[doc(hidden)]
521    pub fn next_raw(&mut self) -> Result<Option<RawRngListEntry<R::Offset>>> {
522        self.raw.next()
523    }
524
525    /// Convert a raw range into a range, and update the state of the iterator.
526    ///
527    /// The raw range should have been obtained from `next_raw`.
528    #[doc(hidden)]
529    pub fn convert_raw(&mut self, raw_range: RawRngListEntry<R::Offset>) -> Result<Option<Range>> {
530        let address_size = self.raw.encoding.address_size;
531        let mask = u64::ones_sized(address_size);
532        let tombstone = if self.raw.encoding.version <= 4 {
533            mask - 1
534        } else {
535            mask
536        };
537
538        let range = match raw_range {
539            RawRngListEntry::BaseAddress { addr } => {
540                self.base_address = addr;
541                return Ok(None);
542            }
543            RawRngListEntry::BaseAddressx { addr } => {
544                self.base_address = self.get_address(addr)?;
545                return Ok(None);
546            }
547            RawRngListEntry::StartxEndx { begin, end } => {
548                let begin = self.get_address(begin)?;
549                let end = self.get_address(end)?;
550                Range { begin, end }
551            }
552            RawRngListEntry::StartxLength { begin, length } => {
553                let begin = self.get_address(begin)?;
554                let end = begin.wrapping_add_sized(length, address_size);
555                Range { begin, end }
556            }
557            RawRngListEntry::AddressOrOffsetPair { begin, end }
558            | RawRngListEntry::OffsetPair { begin, end } => {
559                // Skip tombstone entries (see below).
560                if self.base_address == tombstone {
561                    return Ok(None);
562                }
563                let mut range = Range { begin, end };
564                range.add_base_address(self.base_address, self.raw.encoding.address_size);
565                range
566            }
567            RawRngListEntry::StartEnd { begin, end } => Range { begin, end },
568            RawRngListEntry::StartLength { begin, length } => {
569                let end = begin.wrapping_add_sized(length, address_size);
570                Range { begin, end }
571            }
572        };
573
574        // Skip tombstone entries.
575        //
576        // DWARF specifies a tombstone value of -1 or -2, but many linkers use 0 or 1.
577        // However, 0/1 may be a valid address, so we can't always reliably skip them.
578        // One case where we can skip them is for address pairs, where both values are
579        // replaced by tombstones and thus `begin` equals `end`. Since these entries
580        // are empty, it's safe to skip them even if they aren't tombstones.
581        //
582        // In addition to skipping tombstone entries, we also skip invalid entries
583        // where `begin` is greater than `end`. This can occur due to compiler bugs.
584        if range.begin == tombstone || range.begin >= range.end {
585            return Ok(None);
586        }
587
588        Ok(Some(range))
589    }
590}
591
592#[cfg(feature = "fallible-iterator")]
593impl<R: Reader> fallible_iterator::FallibleIterator for RngListIter<R> {
594    type Item = Range;
595    type Error = Error;
596
597    fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
598        RngListIter::next(self)
599    }
600}
601
602/// A raw address range from the `.debug_ranges` section.
603#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
604pub(crate) struct RawRange {
605    /// The beginning address of the range.
606    pub begin: u64,
607
608    /// The first address past the end of the range.
609    pub end: u64,
610}
611
612impl RawRange {
613    /// Check if this is a range end entry.
614    #[inline]
615    pub fn is_end(&self) -> bool {
616        self.begin == 0 && self.end == 0
617    }
618
619    /// Check if this is a base address selection entry.
620    ///
621    /// A base address selection entry changes the base address that subsequent
622    /// range entries are relative to.
623    #[inline]
624    pub fn is_base_address(&self, address_size: u8) -> bool {
625        self.begin == !0 >> (64 - address_size * 8)
626    }
627
628    /// Parse an address range entry from `.debug_ranges` or `.debug_loc`.
629    #[inline]
630    pub fn parse<R: Reader>(input: &mut R, address_size: u8) -> Result<RawRange> {
631        let begin = input.read_address(address_size)?;
632        let end = input.read_address(address_size)?;
633        let range = RawRange { begin, end };
634        Ok(range)
635    }
636}
637
638/// An address range from the `.debug_ranges`, `.debug_rnglists`, or `.debug_aranges` sections.
639#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
640pub struct Range {
641    /// The beginning address of the range.
642    pub begin: u64,
643
644    /// The first address past the end of the range.
645    pub end: u64,
646}
647
648impl Range {
649    /// Add a base address to this range.
650    #[inline]
651    pub(crate) fn add_base_address(&mut self, base_address: u64, address_size: u8) {
652        self.begin = base_address.wrapping_add_sized(self.begin, address_size);
653        self.end = base_address.wrapping_add_sized(self.end, address_size);
654    }
655}
656
657#[cfg(test)]
658mod tests {
659    use super::*;
660    use crate::common::Format;
661    use crate::constants::*;
662    use crate::endianity::LittleEndian;
663    use crate::test_util::GimliSectionMethods;
664    use alloc::vec::Vec;
665    use test_assembler::{Endian, Label, LabelMaker, Section};
666
667    #[test]
668    fn test_rnglists() {
669        let format = Format::Dwarf32;
670        for size in [4, 8] {
671            let tombstone = u64::ones_sized(size);
672            let tombstone_0 = 0;
673            let encoding = Encoding {
674                format,
675                version: 5,
676                address_size: size,
677            };
678            let section = Section::with_endian(Endian::Little)
679                .word(size, 0x0300_0000)
680                .word(size, 0x0301_0300)
681                .word(size, 0x0301_0400)
682                .word(size, 0x0301_0500)
683                .word(size, tombstone)
684                .word(size, 0x0301_0600)
685                .word(size, tombstone_0);
686            let buf = section.get_contents().unwrap();
687            let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian));
688            let debug_addr_base = DebugAddrBase(0);
689
690            let length = Label::new();
691            let start = Label::new();
692            let first = Label::new();
693            let end = Label::new();
694            let mut section = Section::with_endian(Endian::Little)
695                .initial_length(format, &length, &start)
696                .L16(encoding.version)
697                .L8(encoding.address_size)
698                .L8(0)
699                .L32(0)
700                .mark(&first);
701
702            let mut expected_ranges = Vec::new();
703            let mut expect_range = |begin, end| {
704                expected_ranges.push(Range { begin, end });
705            };
706
707            // An offset pair using the unit base address.
708            section = section.L8(DW_RLE_offset_pair.0).uleb(0x10200).uleb(0x10300);
709            expect_range(0x0101_0200, 0x0101_0300);
710
711            section = section.L8(DW_RLE_base_address.0).word(size, 0x0200_0000);
712            section = section.L8(DW_RLE_offset_pair.0).uleb(0x10400).uleb(0x10500);
713            expect_range(0x0201_0400, 0x0201_0500);
714
715            section = section
716                .L8(DW_RLE_start_end.0)
717                .word(size, 0x201_0a00)
718                .word(size, 0x201_0b00);
719            expect_range(0x0201_0a00, 0x0201_0b00);
720
721            section = section
722                .L8(DW_RLE_start_length.0)
723                .word(size, 0x201_0c00)
724                .uleb(0x100);
725            expect_range(0x0201_0c00, 0x0201_0d00);
726
727            // An offset pair that starts at 0.
728            section = section.L8(DW_RLE_base_address.0).word(size, 0);
729            section = section.L8(DW_RLE_offset_pair.0).uleb(0).uleb(1);
730            expect_range(0, 1);
731
732            // An offset pair that ends at -1.
733            section = section.L8(DW_RLE_base_address.0).word(size, 0);
734            section = section.L8(DW_RLE_offset_pair.0).uleb(0).uleb(tombstone);
735            expect_range(0, tombstone);
736
737            section = section.L8(DW_RLE_base_addressx.0).uleb(0);
738            section = section.L8(DW_RLE_offset_pair.0).uleb(0x10100).uleb(0x10200);
739            expect_range(0x0301_0100, 0x0301_0200);
740
741            section = section.L8(DW_RLE_startx_endx.0).uleb(1).uleb(2);
742            expect_range(0x0301_0300, 0x0301_0400);
743
744            section = section.L8(DW_RLE_startx_length.0).uleb(3).uleb(0x100);
745            expect_range(0x0301_0500, 0x0301_0600);
746
747            // Tombstone entries, all of which should be ignored.
748            section = section.L8(DW_RLE_base_addressx.0).uleb(4);
749            section = section.L8(DW_RLE_offset_pair.0).uleb(0x11100).uleb(0x11200);
750
751            section = section.L8(DW_RLE_base_address.0).word(size, tombstone);
752            section = section.L8(DW_RLE_offset_pair.0).uleb(0x11300).uleb(0x11400);
753
754            section = section.L8(DW_RLE_startx_endx.0).uleb(4).uleb(5);
755            section = section.L8(DW_RLE_startx_length.0).uleb(4).uleb(0x100);
756            section = section
757                .L8(DW_RLE_start_end.0)
758                .word(size, tombstone)
759                .word(size, 0x201_1500);
760            section = section
761                .L8(DW_RLE_start_length.0)
762                .word(size, tombstone)
763                .uleb(0x100);
764
765            // Ignore some instances of 0 for tombstone.
766            section = section.L8(DW_RLE_startx_endx.0).uleb(6).uleb(6);
767            section = section
768                .L8(DW_RLE_start_end.0)
769                .word(size, tombstone_0)
770                .word(size, tombstone_0);
771
772            // Ignore empty ranges.
773            section = section.L8(DW_RLE_base_address.0).word(size, 0);
774            section = section.L8(DW_RLE_offset_pair.0).uleb(0).uleb(0);
775            section = section.L8(DW_RLE_base_address.0).word(size, 0x10000);
776            section = section.L8(DW_RLE_offset_pair.0).uleb(0x1234).uleb(0x1234);
777
778            // A valid range after the tombstones.
779            section = section
780                .L8(DW_RLE_start_end.0)
781                .word(size, 0x201_1600)
782                .word(size, 0x201_1700);
783            expect_range(0x0201_1600, 0x0201_1700);
784
785            section = section.L8(DW_RLE_end_of_list.0);
786            section = section.mark(&end);
787            // Some extra data.
788            section = section.word(size, 0x1234_5678);
789            length.set_const((&end - &start) as u64);
790
791            let offset = RangeListsOffset((&first - &section.start()) as usize);
792            let buf = section.get_contents().unwrap();
793            let debug_ranges = DebugRanges::new(&[], LittleEndian);
794            let debug_rnglists = DebugRngLists::new(&buf, LittleEndian);
795            let rnglists = RangeLists::new(debug_ranges, debug_rnglists);
796            let mut ranges = rnglists
797                .ranges(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base)
798                .unwrap();
799
800            for expected_range in expected_ranges {
801                let range = ranges.next();
802                assert_eq!(
803                    range,
804                    Ok(Some(expected_range)),
805                    "read {:x?}, expect {:x?}",
806                    range,
807                    expected_range
808                );
809            }
810            assert_eq!(ranges.next(), Ok(None));
811
812            // An offset at the end of buf.
813            let mut ranges = rnglists
814                .ranges(
815                    RangeListsOffset(buf.len()),
816                    encoding,
817                    0x0100_0000,
818                    debug_addr,
819                    debug_addr_base,
820                )
821                .unwrap();
822            assert_eq!(ranges.next(), Ok(None));
823        }
824    }
825
826    #[test]
827    fn test_raw_range() {
828        let range = RawRange {
829            begin: 0,
830            end: 0xffff_ffff,
831        };
832        assert!(!range.is_end());
833        assert!(!range.is_base_address(4));
834        assert!(!range.is_base_address(8));
835
836        let range = RawRange { begin: 0, end: 0 };
837        assert!(range.is_end());
838        assert!(!range.is_base_address(4));
839        assert!(!range.is_base_address(8));
840
841        let range = RawRange {
842            begin: 0xffff_ffff,
843            end: 0,
844        };
845        assert!(!range.is_end());
846        assert!(range.is_base_address(4));
847        assert!(!range.is_base_address(8));
848
849        let range = RawRange {
850            begin: 0xffff_ffff_ffff_ffff,
851            end: 0,
852        };
853        assert!(!range.is_end());
854        assert!(!range.is_base_address(4));
855        assert!(range.is_base_address(8));
856    }
857
858    #[test]
859    fn test_ranges() {
860        for size in [4, 8] {
861            let base = u64::ones_sized(size);
862            let tombstone = u64::ones_sized(size) - 1;
863            let start = Label::new();
864            let first = Label::new();
865            let mut section = Section::with_endian(Endian::Little)
866                // A range before the offset.
867                .mark(&start)
868                .word(size, 0x10000)
869                .word(size, 0x10100)
870                .mark(&first);
871
872            let mut expected_ranges = Vec::new();
873            let mut expect_range = |begin, end| {
874                expected_ranges.push(Range { begin, end });
875            };
876
877            // A normal range.
878            section = section.word(size, 0x10200).word(size, 0x10300);
879            expect_range(0x0101_0200, 0x0101_0300);
880            // A base address selection followed by a normal range.
881            section = section.word(size, base).word(size, 0x0200_0000);
882            section = section.word(size, 0x10400).word(size, 0x10500);
883            expect_range(0x0201_0400, 0x0201_0500);
884            // An empty range followed by a normal range.
885            section = section.word(size, 0x10600).word(size, 0x10600);
886            section = section.word(size, 0x10800).word(size, 0x10900);
887            expect_range(0x0201_0800, 0x0201_0900);
888            // A range that starts at 0.
889            section = section.word(size, base).word(size, 0);
890            section = section.word(size, 0).word(size, 1);
891            expect_range(0, 1);
892            // A range that ends at -1.
893            section = section.word(size, base).word(size, 0);
894            section = section.word(size, 0).word(size, base);
895            expect_range(0, base);
896            // A normal range with tombstone.
897            section = section.word(size, tombstone).word(size, tombstone);
898            // A base address selection with tombstone followed by a normal range.
899            section = section.word(size, base).word(size, tombstone);
900            section = section.word(size, 0x10a00).word(size, 0x10b00);
901            // A range end.
902            section = section.word(size, 0).word(size, 0);
903            // Some extra data.
904            section = section.word(size, 0x1234_5678);
905
906            let buf = section.get_contents().unwrap();
907            let debug_ranges = DebugRanges::new(&buf, LittleEndian);
908            let debug_rnglists = DebugRngLists::new(&[], LittleEndian);
909            let rnglists = RangeLists::new(debug_ranges, debug_rnglists);
910            let offset = RangeListsOffset((&first - &start) as usize);
911            let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian));
912            let debug_addr_base = DebugAddrBase(0);
913            let encoding = Encoding {
914                format: Format::Dwarf32,
915                version: 4,
916                address_size: size,
917            };
918            let mut ranges = rnglists
919                .ranges(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base)
920                .unwrap();
921
922            for expected_range in expected_ranges {
923                let range = ranges.next();
924                assert_eq!(
925                    range,
926                    Ok(Some(expected_range)),
927                    "read {:x?}, expect {:x?}",
928                    range,
929                    expected_range
930                );
931            }
932            assert_eq!(ranges.next(), Ok(None));
933
934            // An offset at the end of buf.
935            let mut ranges = rnglists
936                .ranges(
937                    RangeListsOffset(buf.len()),
938                    encoding,
939                    0x0100_0000,
940                    debug_addr,
941                    debug_addr_base,
942                )
943                .unwrap();
944            assert_eq!(ranges.next(), Ok(None));
945        }
946    }
947
948    #[test]
949    fn test_ranges_invalid() {
950        #[rustfmt::skip]
951        let section = Section::with_endian(Endian::Little)
952            // An invalid range.
953            .L32(0x20000).L32(0x10000)
954            // An invalid range after wrapping.
955            .L32(0x20000).L32(0xff01_0000);
956
957        let buf = section.get_contents().unwrap();
958        let debug_ranges = DebugRanges::new(&buf, LittleEndian);
959        let debug_rnglists = DebugRngLists::new(&[], LittleEndian);
960        let rnglists = RangeLists::new(debug_ranges, debug_rnglists);
961        let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian));
962        let debug_addr_base = DebugAddrBase(0);
963        let encoding = Encoding {
964            format: Format::Dwarf32,
965            version: 4,
966            address_size: 4,
967        };
968
969        // An invalid range.
970        let mut ranges = rnglists
971            .ranges(
972                RangeListsOffset(0x0),
973                encoding,
974                0x0100_0000,
975                debug_addr,
976                debug_addr_base,
977            )
978            .unwrap();
979        assert_eq!(ranges.next(), Ok(None));
980
981        // An invalid range after wrapping.
982        let mut ranges = rnglists
983            .ranges(
984                RangeListsOffset(0x8),
985                encoding,
986                0x0100_0000,
987                debug_addr,
988                debug_addr_base,
989            )
990            .unwrap();
991        assert_eq!(ranges.next(), Ok(None));
992
993        // An invalid offset.
994        match rnglists.ranges(
995            RangeListsOffset(buf.len() + 1),
996            encoding,
997            0x0100_0000,
998            debug_addr,
999            debug_addr_base,
1000        ) {
1001            Err(Error::UnexpectedEof(_)) => {}
1002            otherwise => panic!("Unexpected result: {:?}", otherwise),
1003        }
1004    }
1005
1006    #[test]
1007    fn test_get_offset() {
1008        for format in [Format::Dwarf32, Format::Dwarf64] {
1009            let encoding = Encoding {
1010                format,
1011                version: 5,
1012                address_size: 4,
1013            };
1014
1015            let zero = Label::new();
1016            let length = Label::new();
1017            let start = Label::new();
1018            let first = Label::new();
1019            let end = Label::new();
1020            let mut section = Section::with_endian(Endian::Little)
1021                .mark(&zero)
1022                .initial_length(format, &length, &start)
1023                .D16(encoding.version)
1024                .D8(encoding.address_size)
1025                .D8(0)
1026                .D32(20)
1027                .mark(&first);
1028            for i in 0..20 {
1029                section = section.word(format.word_size(), 1000 + i);
1030            }
1031            section = section.mark(&end);
1032            length.set_const((&end - &start) as u64);
1033            let section = section.get_contents().unwrap();
1034
1035            let debug_ranges = DebugRanges::from(EndianSlice::new(&[], LittleEndian));
1036            let debug_rnglists = DebugRngLists::from(EndianSlice::new(&section, LittleEndian));
1037            let ranges = RangeLists::new(debug_ranges, debug_rnglists);
1038
1039            let base = DebugRngListsBase((&first - &zero) as usize);
1040            assert_eq!(
1041                ranges.get_offset(encoding, base, DebugRngListsIndex(0)),
1042                Ok(RangeListsOffset(base.0 + 1000))
1043            );
1044            assert_eq!(
1045                ranges.get_offset(encoding, base, DebugRngListsIndex(19)),
1046                Ok(RangeListsOffset(base.0 + 1019))
1047            );
1048        }
1049    }
1050}