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
532        let range = match raw_range {
533            RawRngListEntry::BaseAddress { addr } => {
534                self.base_address = addr;
535                return Ok(None);
536            }
537            RawRngListEntry::BaseAddressx { addr } => {
538                self.base_address = self.get_address(addr)?;
539                return Ok(None);
540            }
541            RawRngListEntry::StartxEndx { begin, end } => {
542                let begin = self.get_address(begin)?;
543                let end = self.get_address(end)?;
544                Range { begin, end }
545            }
546            RawRngListEntry::StartxLength { begin, length } => {
547                let begin = self.get_address(begin)?;
548                let end = begin.wrapping_add_sized(length, address_size);
549                Range { begin, end }
550            }
551            RawRngListEntry::AddressOrOffsetPair { begin, end }
552            | RawRngListEntry::OffsetPair { begin, end } => {
553                // Skip tombstone entries (see below).
554                if self.base_address >= u64::min_tombstone(address_size) {
555                    return Ok(None);
556                }
557                let mut range = Range { begin, end };
558                range.add_base_address(self.base_address, address_size);
559                range
560            }
561            RawRngListEntry::StartEnd { begin, end } => Range { begin, end },
562            RawRngListEntry::StartLength { begin, length } => {
563                let end = begin.wrapping_add_sized(length, address_size);
564                Range { begin, end }
565            }
566        };
567
568        // Skip tombstone entries.
569        //
570        // DWARF specifies a tombstone value of -1 or -2, but many linkers use 0 or 1.
571        // However, 0/1 may be a valid address, so we can't always reliably skip them.
572        // One case where we can skip them is for address pairs, where both values are
573        // replaced by tombstones and thus `begin` equals `end`. Since these entries
574        // are empty, it's safe to skip them even if they aren't tombstones.
575        //
576        // In addition to skipping tombstone entries, we also skip invalid entries
577        // where `begin` is greater than `end`. This can occur due to compiler bugs.
578        if range.begin >= u64::min_tombstone(address_size) || range.begin >= range.end {
579            return Ok(None);
580        }
581
582        Ok(Some(range))
583    }
584}
585
586#[cfg(feature = "fallible-iterator")]
587impl<R: Reader> fallible_iterator::FallibleIterator for RngListIter<R> {
588    type Item = Range;
589    type Error = Error;
590
591    fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
592        RngListIter::next(self)
593    }
594}
595
596/// A raw address range from the `.debug_ranges` section.
597#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
598pub(crate) struct RawRange {
599    /// The beginning address of the range.
600    pub begin: u64,
601
602    /// The first address past the end of the range.
603    pub end: u64,
604}
605
606impl RawRange {
607    /// Check if this is a range end entry.
608    #[inline]
609    pub fn is_end(&self) -> bool {
610        self.begin == 0 && self.end == 0
611    }
612
613    /// Check if this is a base address selection entry.
614    ///
615    /// A base address selection entry changes the base address that subsequent
616    /// range entries are relative to.
617    #[inline]
618    pub fn is_base_address(&self, address_size: u8) -> bool {
619        self.begin == !0 >> (64 - address_size * 8)
620    }
621
622    /// Parse an address range entry from `.debug_ranges` or `.debug_loc`.
623    #[inline]
624    pub fn parse<R: Reader>(input: &mut R, address_size: u8) -> Result<RawRange> {
625        let begin = input.read_address(address_size)?;
626        let end = input.read_address(address_size)?;
627        let range = RawRange { begin, end };
628        Ok(range)
629    }
630}
631
632/// An address range from the `.debug_ranges`, `.debug_rnglists`, or `.debug_aranges` sections.
633#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
634pub struct Range {
635    /// The beginning address of the range.
636    pub begin: u64,
637
638    /// The first address past the end of the range.
639    pub end: u64,
640}
641
642impl Range {
643    /// Add a base address to this range.
644    #[inline]
645    pub(crate) fn add_base_address(&mut self, base_address: u64, address_size: u8) {
646        self.begin = base_address.wrapping_add_sized(self.begin, address_size);
647        self.end = base_address.wrapping_add_sized(self.end, address_size);
648    }
649}
650
651#[cfg(test)]
652mod tests {
653    use super::*;
654    use crate::common::Format;
655    use crate::constants::*;
656    use crate::endianity::LittleEndian;
657    use crate::test_util::GimliSectionMethods;
658    use alloc::vec::Vec;
659    use test_assembler::{Endian, Label, LabelMaker, Section};
660
661    #[test]
662    fn test_rnglists() {
663        let format = Format::Dwarf32;
664        for size in [4, 8] {
665            let tombstone = u64::ones_sized(size);
666            let tombstone_0 = 0;
667            let encoding = Encoding {
668                format,
669                version: 5,
670                address_size: size,
671            };
672            let section = Section::with_endian(Endian::Little)
673                .word(size, 0x0300_0000)
674                .word(size, 0x0301_0300)
675                .word(size, 0x0301_0400)
676                .word(size, 0x0301_0500)
677                .word(size, tombstone)
678                .word(size, 0x0301_0600)
679                .word(size, tombstone_0);
680            let buf = section.get_contents().unwrap();
681            let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian));
682            let debug_addr_base = DebugAddrBase(0);
683
684            let length = Label::new();
685            let start = Label::new();
686            let first = Label::new();
687            let end = Label::new();
688            let mut section = Section::with_endian(Endian::Little)
689                .initial_length(format, &length, &start)
690                .L16(encoding.version)
691                .L8(encoding.address_size)
692                .L8(0)
693                .L32(0)
694                .mark(&first);
695
696            let mut expected_ranges = Vec::new();
697            let mut expect_range = |begin, end| {
698                expected_ranges.push(Range { begin, end });
699            };
700
701            // An offset pair using the unit base address.
702            section = section.L8(DW_RLE_offset_pair.0).uleb(0x10200).uleb(0x10300);
703            expect_range(0x0101_0200, 0x0101_0300);
704
705            section = section.L8(DW_RLE_base_address.0).word(size, 0x0200_0000);
706            section = section.L8(DW_RLE_offset_pair.0).uleb(0x10400).uleb(0x10500);
707            expect_range(0x0201_0400, 0x0201_0500);
708
709            section = section
710                .L8(DW_RLE_start_end.0)
711                .word(size, 0x201_0a00)
712                .word(size, 0x201_0b00);
713            expect_range(0x0201_0a00, 0x0201_0b00);
714
715            section = section
716                .L8(DW_RLE_start_length.0)
717                .word(size, 0x201_0c00)
718                .uleb(0x100);
719            expect_range(0x0201_0c00, 0x0201_0d00);
720
721            // An offset pair that starts at 0.
722            section = section.L8(DW_RLE_base_address.0).word(size, 0);
723            section = section.L8(DW_RLE_offset_pair.0).uleb(0).uleb(1);
724            expect_range(0, 1);
725
726            // An offset pair that ends at -1.
727            section = section.L8(DW_RLE_base_address.0).word(size, 0);
728            section = section.L8(DW_RLE_offset_pair.0).uleb(0).uleb(tombstone);
729            expect_range(0, tombstone);
730
731            section = section.L8(DW_RLE_base_addressx.0).uleb(0);
732            section = section.L8(DW_RLE_offset_pair.0).uleb(0x10100).uleb(0x10200);
733            expect_range(0x0301_0100, 0x0301_0200);
734
735            section = section.L8(DW_RLE_startx_endx.0).uleb(1).uleb(2);
736            expect_range(0x0301_0300, 0x0301_0400);
737
738            section = section.L8(DW_RLE_startx_length.0).uleb(3).uleb(0x100);
739            expect_range(0x0301_0500, 0x0301_0600);
740
741            // Tombstone entries, all of which should be ignored.
742            section = section.L8(DW_RLE_base_addressx.0).uleb(4);
743            section = section.L8(DW_RLE_offset_pair.0).uleb(0x11100).uleb(0x11200);
744
745            section = section.L8(DW_RLE_base_address.0).word(size, tombstone);
746            section = section.L8(DW_RLE_offset_pair.0).uleb(0x11300).uleb(0x11400);
747
748            section = section.L8(DW_RLE_startx_endx.0).uleb(4).uleb(5);
749            section = section.L8(DW_RLE_startx_length.0).uleb(4).uleb(0x100);
750            section = section
751                .L8(DW_RLE_start_end.0)
752                .word(size, tombstone)
753                .word(size, 0x201_1500);
754            section = section
755                .L8(DW_RLE_start_length.0)
756                .word(size, tombstone)
757                .uleb(0x100);
758
759            // Ignore some instances of 0 for tombstone.
760            section = section.L8(DW_RLE_startx_endx.0).uleb(6).uleb(6);
761            section = section
762                .L8(DW_RLE_start_end.0)
763                .word(size, tombstone_0)
764                .word(size, tombstone_0);
765
766            // Ignore empty ranges.
767            section = section.L8(DW_RLE_base_address.0).word(size, 0);
768            section = section.L8(DW_RLE_offset_pair.0).uleb(0).uleb(0);
769            section = section.L8(DW_RLE_base_address.0).word(size, 0x10000);
770            section = section.L8(DW_RLE_offset_pair.0).uleb(0x1234).uleb(0x1234);
771
772            // A valid range after the tombstones.
773            section = section
774                .L8(DW_RLE_start_end.0)
775                .word(size, 0x201_1600)
776                .word(size, 0x201_1700);
777            expect_range(0x0201_1600, 0x0201_1700);
778
779            section = section.L8(DW_RLE_end_of_list.0);
780            section = section.mark(&end);
781            // Some extra data.
782            section = section.word(size, 0x1234_5678);
783            length.set_const((&end - &start) as u64);
784
785            let offset = RangeListsOffset((&first - &section.start()) as usize);
786            let buf = section.get_contents().unwrap();
787            let debug_ranges = DebugRanges::new(&[], LittleEndian);
788            let debug_rnglists = DebugRngLists::new(&buf, LittleEndian);
789            let rnglists = RangeLists::new(debug_ranges, debug_rnglists);
790            let mut ranges = rnglists
791                .ranges(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base)
792                .unwrap();
793
794            for expected_range in expected_ranges {
795                let range = ranges.next();
796                assert_eq!(
797                    range,
798                    Ok(Some(expected_range)),
799                    "read {:x?}, expect {:x?}",
800                    range,
801                    expected_range
802                );
803            }
804            assert_eq!(ranges.next(), Ok(None));
805
806            // An offset at the end of buf.
807            let mut ranges = rnglists
808                .ranges(
809                    RangeListsOffset(buf.len()),
810                    encoding,
811                    0x0100_0000,
812                    debug_addr,
813                    debug_addr_base,
814                )
815                .unwrap();
816            assert_eq!(ranges.next(), Ok(None));
817        }
818    }
819
820    #[test]
821    fn test_raw_range() {
822        let range = RawRange {
823            begin: 0,
824            end: 0xffff_ffff,
825        };
826        assert!(!range.is_end());
827        assert!(!range.is_base_address(4));
828        assert!(!range.is_base_address(8));
829
830        let range = RawRange { begin: 0, end: 0 };
831        assert!(range.is_end());
832        assert!(!range.is_base_address(4));
833        assert!(!range.is_base_address(8));
834
835        let range = RawRange {
836            begin: 0xffff_ffff,
837            end: 0,
838        };
839        assert!(!range.is_end());
840        assert!(range.is_base_address(4));
841        assert!(!range.is_base_address(8));
842
843        let range = RawRange {
844            begin: 0xffff_ffff_ffff_ffff,
845            end: 0,
846        };
847        assert!(!range.is_end());
848        assert!(!range.is_base_address(4));
849        assert!(range.is_base_address(8));
850    }
851
852    #[test]
853    fn test_ranges() {
854        for size in [4, 8] {
855            let base = u64::ones_sized(size);
856            let tombstone = u64::ones_sized(size) - 1;
857            let start = Label::new();
858            let first = Label::new();
859            let mut section = Section::with_endian(Endian::Little)
860                // A range before the offset.
861                .mark(&start)
862                .word(size, 0x10000)
863                .word(size, 0x10100)
864                .mark(&first);
865
866            let mut expected_ranges = Vec::new();
867            let mut expect_range = |begin, end| {
868                expected_ranges.push(Range { begin, end });
869            };
870
871            // A normal range.
872            section = section.word(size, 0x10200).word(size, 0x10300);
873            expect_range(0x0101_0200, 0x0101_0300);
874            // A base address selection followed by a normal range.
875            section = section.word(size, base).word(size, 0x0200_0000);
876            section = section.word(size, 0x10400).word(size, 0x10500);
877            expect_range(0x0201_0400, 0x0201_0500);
878            // An empty range followed by a normal range.
879            section = section.word(size, 0x10600).word(size, 0x10600);
880            section = section.word(size, 0x10800).word(size, 0x10900);
881            expect_range(0x0201_0800, 0x0201_0900);
882            // A range that starts at 0.
883            section = section.word(size, base).word(size, 0);
884            section = section.word(size, 0).word(size, 1);
885            expect_range(0, 1);
886            // A range that ends at -1.
887            section = section.word(size, base).word(size, 0);
888            section = section.word(size, 0).word(size, base);
889            expect_range(0, base);
890            // A normal range with tombstone.
891            section = section.word(size, tombstone).word(size, tombstone);
892            // A base address selection with tombstone followed by a normal range.
893            section = section.word(size, base).word(size, tombstone);
894            section = section.word(size, 0x10a00).word(size, 0x10b00);
895            // A range end.
896            section = section.word(size, 0).word(size, 0);
897            // Some extra data.
898            section = section.word(size, 0x1234_5678);
899
900            let buf = section.get_contents().unwrap();
901            let debug_ranges = DebugRanges::new(&buf, LittleEndian);
902            let debug_rnglists = DebugRngLists::new(&[], LittleEndian);
903            let rnglists = RangeLists::new(debug_ranges, debug_rnglists);
904            let offset = RangeListsOffset((&first - &start) as usize);
905            let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian));
906            let debug_addr_base = DebugAddrBase(0);
907            let encoding = Encoding {
908                format: Format::Dwarf32,
909                version: 4,
910                address_size: size,
911            };
912            let mut ranges = rnglists
913                .ranges(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base)
914                .unwrap();
915
916            for expected_range in expected_ranges {
917                let range = ranges.next();
918                assert_eq!(
919                    range,
920                    Ok(Some(expected_range)),
921                    "read {:x?}, expect {:x?}",
922                    range,
923                    expected_range
924                );
925            }
926            assert_eq!(ranges.next(), Ok(None));
927
928            // An offset at the end of buf.
929            let mut ranges = rnglists
930                .ranges(
931                    RangeListsOffset(buf.len()),
932                    encoding,
933                    0x0100_0000,
934                    debug_addr,
935                    debug_addr_base,
936                )
937                .unwrap();
938            assert_eq!(ranges.next(), Ok(None));
939        }
940    }
941
942    #[test]
943    fn test_ranges_invalid() {
944        #[rustfmt::skip]
945        let section = Section::with_endian(Endian::Little)
946            // An invalid range.
947            .L32(0x20000).L32(0x10000)
948            // An invalid range after wrapping.
949            .L32(0x20000).L32(0xff01_0000);
950
951        let buf = section.get_contents().unwrap();
952        let debug_ranges = DebugRanges::new(&buf, LittleEndian);
953        let debug_rnglists = DebugRngLists::new(&[], LittleEndian);
954        let rnglists = RangeLists::new(debug_ranges, debug_rnglists);
955        let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian));
956        let debug_addr_base = DebugAddrBase(0);
957        let encoding = Encoding {
958            format: Format::Dwarf32,
959            version: 4,
960            address_size: 4,
961        };
962
963        // An invalid range.
964        let mut ranges = rnglists
965            .ranges(
966                RangeListsOffset(0x0),
967                encoding,
968                0x0100_0000,
969                debug_addr,
970                debug_addr_base,
971            )
972            .unwrap();
973        assert_eq!(ranges.next(), Ok(None));
974
975        // An invalid range after wrapping.
976        let mut ranges = rnglists
977            .ranges(
978                RangeListsOffset(0x8),
979                encoding,
980                0x0100_0000,
981                debug_addr,
982                debug_addr_base,
983            )
984            .unwrap();
985        assert_eq!(ranges.next(), Ok(None));
986
987        // An invalid offset.
988        match rnglists.ranges(
989            RangeListsOffset(buf.len() + 1),
990            encoding,
991            0x0100_0000,
992            debug_addr,
993            debug_addr_base,
994        ) {
995            Err(Error::UnexpectedEof(_)) => {}
996            otherwise => panic!("Unexpected result: {:?}", otherwise),
997        }
998    }
999
1000    #[test]
1001    fn test_get_offset() {
1002        for format in [Format::Dwarf32, Format::Dwarf64] {
1003            let encoding = Encoding {
1004                format,
1005                version: 5,
1006                address_size: 4,
1007            };
1008
1009            let zero = Label::new();
1010            let length = Label::new();
1011            let start = Label::new();
1012            let first = Label::new();
1013            let end = Label::new();
1014            let mut section = Section::with_endian(Endian::Little)
1015                .mark(&zero)
1016                .initial_length(format, &length, &start)
1017                .D16(encoding.version)
1018                .D8(encoding.address_size)
1019                .D8(0)
1020                .D32(20)
1021                .mark(&first);
1022            for i in 0..20 {
1023                section = section.word(format.word_size(), 1000 + i);
1024            }
1025            section = section.mark(&end);
1026            length.set_const((&end - &start) as u64);
1027            let section = section.get_contents().unwrap();
1028
1029            let debug_ranges = DebugRanges::from(EndianSlice::new(&[], LittleEndian));
1030            let debug_rnglists = DebugRngLists::from(EndianSlice::new(&section, LittleEndian));
1031            let ranges = RangeLists::new(debug_ranges, debug_rnglists);
1032
1033            let base = DebugRngListsBase((&first - &zero) as usize);
1034            assert_eq!(
1035                ranges.get_offset(encoding, base, DebugRngListsIndex(0)),
1036                Ok(RangeListsOffset(base.0 + 1000))
1037            );
1038            assert_eq!(
1039                ranges.get_offset(encoding, base, DebugRngListsIndex(19)),
1040                Ok(RangeListsOffset(base.0 + 1019))
1041            );
1042        }
1043    }
1044}