Skip to main content

gimli/read/
loclists.rs

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