1 use crate::common::{
2     DebugAddrBase, DebugAddrIndex, DebugLocListsBase, DebugLocListsIndex, DwarfFileType, Encoding,
3     LocationListsOffset, SectionId,
4 };
5 use crate::constants;
6 use crate::endianity::Endianity;
7 use crate::read::{
8     lists::ListsHeader, DebugAddr, EndianSlice, Error, Expression, Range, RawRange, Reader,
9     ReaderOffset, ReaderOffsetId, Result, Section,
10 };
11 
12 /// The raw contents of the `.debug_loc` section.
13 #[derive(Debug, Default, Clone, Copy)]
14 pub struct DebugLoc<R> {
15     pub(crate) section: R,
16 }
17 
18 impl<'input, Endian> DebugLoc<EndianSlice<'input, Endian>>
19 where
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 OSX, 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     /// ```
new(section: &'input [u8], endian: Endian) -> Self36     pub fn new(section: &'input [u8], endian: Endian) -> Self {
37         Self::from(EndianSlice::new(section, endian))
38     }
39 }
40 
41 impl<R> Section<R> for DebugLoc<R> {
id() -> SectionId42     fn id() -> SectionId {
43         SectionId::DebugLoc
44     }
45 
reader(&self) -> &R46     fn reader(&self) -> &R {
47         &self.section
48     }
49 }
50 
51 impl<R> From<R> for DebugLoc<R> {
from(section: R) -> Self52     fn from(section: R) -> Self {
53         DebugLoc { section }
54     }
55 }
56 
57 /// The `DebugLocLists` struct represents the DWARF data
58 /// found in the `.debug_loclists` section.
59 #[derive(Debug, Default, Clone, Copy)]
60 pub struct DebugLocLists<R> {
61     section: R,
62 }
63 
64 impl<'input, Endian> DebugLocLists<EndianSlice<'input, Endian>>
65 where
66     Endian: Endianity,
67 {
68     /// Construct a new `DebugLocLists` instance from the data in the `.debug_loclists`
69     /// section.
70     ///
71     /// It is the caller's responsibility to read the `.debug_loclists` section and
72     /// present it as a `&[u8]` slice. That means using some ELF loader on
73     /// Linux, a Mach-O loader on OSX, etc.
74     ///
75     /// ```
76     /// use gimli::{DebugLocLists, LittleEndian};
77     ///
78     /// # let buf = [0x00, 0x01, 0x02, 0x03];
79     /// # let read_debug_loclists_section_somehow = || &buf;
80     /// let debug_loclists = DebugLocLists::new(read_debug_loclists_section_somehow(), LittleEndian);
81     /// ```
new(section: &'input [u8], endian: Endian) -> Self82     pub fn new(section: &'input [u8], endian: Endian) -> Self {
83         Self::from(EndianSlice::new(section, endian))
84     }
85 }
86 
87 impl<R> Section<R> for DebugLocLists<R> {
id() -> SectionId88     fn id() -> SectionId {
89         SectionId::DebugLocLists
90     }
91 
reader(&self) -> &R92     fn reader(&self) -> &R {
93         &self.section
94     }
95 }
96 
97 impl<R> From<R> for DebugLocLists<R> {
from(section: R) -> Self98     fn from(section: R) -> Self {
99         DebugLocLists { section }
100     }
101 }
102 
103 pub(crate) type LocListsHeader = ListsHeader;
104 
105 impl<Offset> DebugLocListsBase<Offset>
106 where
107     Offset: ReaderOffset,
108 {
109     /// Returns a `DebugLocListsBase` with the default value of DW_AT_loclists_base
110     /// for the given `Encoding` and `DwarfFileType`.
default_for_encoding_and_file( encoding: Encoding, file_type: DwarfFileType, ) -> DebugLocListsBase<Offset>111     pub fn default_for_encoding_and_file(
112         encoding: Encoding,
113         file_type: DwarfFileType,
114     ) -> DebugLocListsBase<Offset> {
115         if encoding.version >= 5 && file_type == DwarfFileType::Dwo {
116             // In .dwo files, the compiler omits the DW_AT_loclists_base attribute (because there is
117             // only a single unit in the file) but we must skip past the header, which the attribute
118             // would normally do for us.
119             DebugLocListsBase(Offset::from_u8(LocListsHeader::size_for_encoding(encoding)))
120         } else {
121             DebugLocListsBase(Offset::from_u8(0))
122         }
123     }
124 }
125 
126 /// The DWARF data found in `.debug_loc` and `.debug_loclists` sections.
127 #[derive(Debug, Default, Clone, Copy)]
128 pub struct LocationLists<R> {
129     debug_loc: DebugLoc<R>,
130     debug_loclists: DebugLocLists<R>,
131 }
132 
133 impl<R> LocationLists<R> {
134     /// Construct a new `LocationLists` instance from the data in the `.debug_loc` and
135     /// `.debug_loclists` sections.
new(debug_loc: DebugLoc<R>, debug_loclists: DebugLocLists<R>) -> LocationLists<R>136     pub fn new(debug_loc: DebugLoc<R>, debug_loclists: DebugLocLists<R>) -> LocationLists<R> {
137         LocationLists {
138             debug_loc,
139             debug_loclists,
140         }
141     }
142 }
143 
144 impl<T> LocationLists<T> {
145     /// Create a `LocationLists` that references the data in `self`.
146     ///
147     /// This is useful when `R` implements `Reader` but `T` does not.
148     ///
149     /// ## Example Usage
150     ///
151     /// ```rust,no_run
152     /// # let load_section = || unimplemented!();
153     /// // Read the DWARF section into a `Vec` with whatever object loader you're using.
154     /// let owned_section: gimli::LocationLists<Vec<u8>> = load_section();
155     /// // Create a reference to the DWARF section.
156     /// let section = owned_section.borrow(|section| {
157     ///     gimli::EndianSlice::new(&section, gimli::LittleEndian)
158     /// });
159     /// ```
borrow<'a, F, R>(&'a self, mut borrow: F) -> LocationLists<R> where F: FnMut(&'a T) -> R,160     pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> LocationLists<R>
161     where
162         F: FnMut(&'a T) -> R,
163     {
164         LocationLists {
165             debug_loc: borrow(&self.debug_loc.section).into(),
166             debug_loclists: borrow(&self.debug_loclists.section).into(),
167         }
168     }
169 }
170 
171 impl<R: Reader> LocationLists<R> {
172     /// Iterate over the `LocationListEntry`s starting at the given offset.
173     ///
174     /// The `unit_encoding` must match the compilation unit that the
175     /// offset was contained in.
176     ///
177     /// The `base_address` should be obtained from the `DW_AT_low_pc` attribute in the
178     /// `DW_TAG_compile_unit` entry for the compilation unit that contains this location
179     /// list.
180     ///
181     /// Can be [used with
182     /// `FallibleIterator`](./index.html#using-with-fallibleiterator).
locations( &self, offset: LocationListsOffset<R::Offset>, unit_encoding: Encoding, base_address: u64, debug_addr: &DebugAddr<R>, debug_addr_base: DebugAddrBase<R::Offset>, ) -> Result<LocListIter<R>>183     pub fn locations(
184         &self,
185         offset: LocationListsOffset<R::Offset>,
186         unit_encoding: Encoding,
187         base_address: u64,
188         debug_addr: &DebugAddr<R>,
189         debug_addr_base: DebugAddrBase<R::Offset>,
190     ) -> Result<LocListIter<R>> {
191         Ok(LocListIter::new(
192             self.raw_locations(offset, unit_encoding)?,
193             base_address,
194             debug_addr.clone(),
195             debug_addr_base,
196         ))
197     }
198 
199     /// Similar to `locations`, but with special handling for .dwo files.
200     /// This should only been used when this `LocationLists` was loaded from a
201     /// .dwo file.
locations_dwo( &self, offset: LocationListsOffset<R::Offset>, unit_encoding: Encoding, base_address: u64, debug_addr: &DebugAddr<R>, debug_addr_base: DebugAddrBase<R::Offset>, ) -> Result<LocListIter<R>>202     pub fn locations_dwo(
203         &self,
204         offset: LocationListsOffset<R::Offset>,
205         unit_encoding: Encoding,
206         base_address: u64,
207         debug_addr: &DebugAddr<R>,
208         debug_addr_base: DebugAddrBase<R::Offset>,
209     ) -> Result<LocListIter<R>> {
210         Ok(LocListIter::new(
211             self.raw_locations_dwo(offset, unit_encoding)?,
212             base_address,
213             debug_addr.clone(),
214             debug_addr_base,
215         ))
216     }
217 
218     /// Iterate over the raw `LocationListEntry`s starting at the given offset.
219     ///
220     /// The `unit_encoding` must match the compilation unit that the
221     /// offset was contained in.
222     ///
223     /// This iterator does not perform any processing of the location entries,
224     /// such as handling base addresses.
225     ///
226     /// Can be [used with
227     /// `FallibleIterator`](./index.html#using-with-fallibleiterator).
raw_locations( &self, offset: LocationListsOffset<R::Offset>, unit_encoding: Encoding, ) -> Result<RawLocListIter<R>>228     pub fn raw_locations(
229         &self,
230         offset: LocationListsOffset<R::Offset>,
231         unit_encoding: Encoding,
232     ) -> Result<RawLocListIter<R>> {
233         let (mut input, format) = if unit_encoding.version <= 4 {
234             (self.debug_loc.section.clone(), LocListsFormat::Bare)
235         } else {
236             (self.debug_loclists.section.clone(), LocListsFormat::LLE)
237         };
238         input.skip(offset.0)?;
239         Ok(RawLocListIter::new(input, unit_encoding, format))
240     }
241 
242     /// Similar to `raw_locations`, but with special handling for .dwo files.
243     /// This should only been used when this `LocationLists` was loaded from a
244     /// .dwo file.
raw_locations_dwo( &self, offset: LocationListsOffset<R::Offset>, unit_encoding: Encoding, ) -> Result<RawLocListIter<R>>245     pub fn raw_locations_dwo(
246         &self,
247         offset: LocationListsOffset<R::Offset>,
248         unit_encoding: Encoding,
249     ) -> Result<RawLocListIter<R>> {
250         let mut input = if unit_encoding.version <= 4 {
251             // In the GNU split dwarf extension the locations are present in the
252             // .debug_loc section but are encoded with the DW_LLE values used
253             // for the DWARF 5 .debug_loclists section.
254             self.debug_loc.section.clone()
255         } else {
256             self.debug_loclists.section.clone()
257         };
258         input.skip(offset.0)?;
259         Ok(RawLocListIter::new(
260             input,
261             unit_encoding,
262             LocListsFormat::LLE,
263         ))
264     }
265 
266     /// Returns the `.debug_loclists` offset at the given `base` and `index`.
267     ///
268     /// The `base` must be the `DW_AT_loclists_base` value from the compilation unit DIE.
269     /// This is an offset that points to the first entry following the header.
270     ///
271     /// The `index` is the value of a `DW_FORM_loclistx` attribute.
get_offset( &self, unit_encoding: Encoding, base: DebugLocListsBase<R::Offset>, index: DebugLocListsIndex<R::Offset>, ) -> Result<LocationListsOffset<R::Offset>>272     pub fn get_offset(
273         &self,
274         unit_encoding: Encoding,
275         base: DebugLocListsBase<R::Offset>,
276         index: DebugLocListsIndex<R::Offset>,
277     ) -> Result<LocationListsOffset<R::Offset>> {
278         let format = unit_encoding.format;
279         let input = &mut self.debug_loclists.section.clone();
280         input.skip(base.0)?;
281         input.skip(R::Offset::from_u64(
282             index.0.into_u64() * u64::from(format.word_size()),
283         )?)?;
284         input
285             .read_offset(format)
286             .map(|x| LocationListsOffset(base.0 + x))
287     }
288 
289     /// Call `Reader::lookup_offset_id` for each section, and return the first match.
lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(SectionId, R::Offset)>290     pub fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(SectionId, R::Offset)> {
291         self.debug_loc
292             .lookup_offset_id(id)
293             .or_else(|| self.debug_loclists.lookup_offset_id(id))
294     }
295 }
296 
297 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
298 enum LocListsFormat {
299     /// The bare location list format used before DWARF 5.
300     Bare,
301     /// The DW_LLE encoded range list format used in DWARF 5 and the non-standard GNU
302     /// split dwarf extension.
303     LLE,
304 }
305 
306 /// A raw iterator over a location list.
307 ///
308 /// This iterator does not perform any processing of the location entries,
309 /// such as handling base addresses.
310 #[derive(Debug)]
311 pub struct RawLocListIter<R: Reader> {
312     input: R,
313     encoding: Encoding,
314     format: LocListsFormat,
315 }
316 
317 /// A raw entry in .debug_loclists.
318 #[derive(Clone, Debug)]
319 pub enum RawLocListEntry<R: Reader> {
320     /// A location from DWARF version <= 4.
321     AddressOrOffsetPair {
322         /// Start of range. May be an address or an offset.
323         begin: u64,
324         /// End of range. May be an address or an offset.
325         end: u64,
326         /// expression
327         data: Expression<R>,
328     },
329     /// DW_LLE_base_address
330     BaseAddress {
331         /// base address
332         addr: u64,
333     },
334     /// DW_LLE_base_addressx
335     BaseAddressx {
336         /// base address
337         addr: DebugAddrIndex<R::Offset>,
338     },
339     /// DW_LLE_startx_endx
340     StartxEndx {
341         /// start of range
342         begin: DebugAddrIndex<R::Offset>,
343         /// end of range
344         end: DebugAddrIndex<R::Offset>,
345         /// expression
346         data: Expression<R>,
347     },
348     /// DW_LLE_startx_length
349     StartxLength {
350         /// start of range
351         begin: DebugAddrIndex<R::Offset>,
352         /// length of range
353         length: u64,
354         /// expression
355         data: Expression<R>,
356     },
357     /// DW_LLE_offset_pair
358     OffsetPair {
359         /// start of range
360         begin: u64,
361         /// end of range
362         end: u64,
363         /// expression
364         data: Expression<R>,
365     },
366     /// DW_LLE_default_location
367     DefaultLocation {
368         /// expression
369         data: Expression<R>,
370     },
371     /// DW_LLE_start_end
372     StartEnd {
373         /// start of range
374         begin: u64,
375         /// end of range
376         end: u64,
377         /// expression
378         data: Expression<R>,
379     },
380     /// DW_LLE_start_length
381     StartLength {
382         /// start of range
383         begin: u64,
384         /// length of range
385         length: u64,
386         /// expression
387         data: Expression<R>,
388     },
389 }
390 
parse_data<R: Reader>(input: &mut R, encoding: Encoding) -> Result<Expression<R>>391 fn parse_data<R: Reader>(input: &mut R, encoding: Encoding) -> Result<Expression<R>> {
392     if encoding.version >= 5 {
393         let len = R::Offset::from_u64(input.read_uleb128()?)?;
394         Ok(Expression(input.split(len)?))
395     } else {
396         // In the GNU split-dwarf extension this is a fixed 2 byte value.
397         let len = R::Offset::from_u16(input.read_u16()?);
398         Ok(Expression(input.split(len)?))
399     }
400 }
401 
402 impl<R: Reader> RawLocListEntry<R> {
403     /// Parse a location list entry from `.debug_loclists`
parse(input: &mut R, encoding: Encoding, format: LocListsFormat) -> Result<Option<Self>>404     fn parse(input: &mut R, encoding: Encoding, format: LocListsFormat) -> Result<Option<Self>> {
405         match format {
406             LocListsFormat::Bare => {
407                 let range = RawRange::parse(input, encoding.address_size)?;
408                 return Ok(if range.is_end() {
409                     None
410                 } else if range.is_base_address(encoding.address_size) {
411                     Some(RawLocListEntry::BaseAddress { addr: range.end })
412                 } else {
413                     let len = R::Offset::from_u16(input.read_u16()?);
414                     let data = Expression(input.split(len)?);
415                     Some(RawLocListEntry::AddressOrOffsetPair {
416                         begin: range.begin,
417                         end: range.end,
418                         data,
419                     })
420                 });
421             }
422             LocListsFormat::LLE => Ok(match constants::DwLle(input.read_u8()?) {
423                 constants::DW_LLE_end_of_list => None,
424                 constants::DW_LLE_base_addressx => Some(RawLocListEntry::BaseAddressx {
425                     addr: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?),
426                 }),
427                 constants::DW_LLE_startx_endx => Some(RawLocListEntry::StartxEndx {
428                     begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?),
429                     end: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?),
430                     data: parse_data(input, encoding)?,
431                 }),
432                 constants::DW_LLE_startx_length => Some(RawLocListEntry::StartxLength {
433                     begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?),
434                     length: if encoding.version >= 5 {
435                         input.read_uleb128()?
436                     } else {
437                         // In the GNU split-dwarf extension this is a fixed 4 byte value.
438                         input.read_u32()? as u64
439                     },
440                     data: parse_data(input, encoding)?,
441                 }),
442                 constants::DW_LLE_offset_pair => Some(RawLocListEntry::OffsetPair {
443                     begin: input.read_uleb128()?,
444                     end: input.read_uleb128()?,
445                     data: parse_data(input, encoding)?,
446                 }),
447                 constants::DW_LLE_default_location => Some(RawLocListEntry::DefaultLocation {
448                     data: parse_data(input, encoding)?,
449                 }),
450                 constants::DW_LLE_base_address => Some(RawLocListEntry::BaseAddress {
451                     addr: input.read_address(encoding.address_size)?,
452                 }),
453                 constants::DW_LLE_start_end => Some(RawLocListEntry::StartEnd {
454                     begin: input.read_address(encoding.address_size)?,
455                     end: input.read_address(encoding.address_size)?,
456                     data: parse_data(input, encoding)?,
457                 }),
458                 constants::DW_LLE_start_length => Some(RawLocListEntry::StartLength {
459                     begin: input.read_address(encoding.address_size)?,
460                     length: input.read_uleb128()?,
461                     data: parse_data(input, encoding)?,
462                 }),
463                 _ => {
464                     return Err(Error::InvalidAddressRange);
465                 }
466             }),
467         }
468     }
469 }
470 
471 impl<R: Reader> RawLocListIter<R> {
472     /// Construct a `RawLocListIter`.
new(input: R, encoding: Encoding, format: LocListsFormat) -> RawLocListIter<R>473     fn new(input: R, encoding: Encoding, format: LocListsFormat) -> RawLocListIter<R> {
474         RawLocListIter {
475             input,
476             encoding,
477             format,
478         }
479     }
480 
481     /// Advance the iterator to the next location.
next(&mut self) -> Result<Option<RawLocListEntry<R>>>482     pub fn next(&mut self) -> Result<Option<RawLocListEntry<R>>> {
483         if self.input.is_empty() {
484             return Ok(None);
485         }
486 
487         match RawLocListEntry::parse(&mut self.input, self.encoding, self.format) {
488             Ok(entry) => {
489                 if entry.is_none() {
490                     self.input.empty();
491                 }
492                 Ok(entry)
493             }
494             Err(e) => {
495                 self.input.empty();
496                 Err(e)
497             }
498         }
499     }
500 }
501 
502 #[cfg(feature = "fallible-iterator")]
503 impl<R: Reader> fallible_iterator::FallibleIterator for RawLocListIter<R> {
504     type Item = RawLocListEntry<R>;
505     type Error = Error;
506 
next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error>507     fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
508         RawLocListIter::next(self)
509     }
510 }
511 
512 /// An iterator over a location list.
513 ///
514 /// This iterator internally handles processing of base address selection entries
515 /// and list end entries.  Thus, it only returns location entries that are valid
516 /// and already adjusted for the base address.
517 #[derive(Debug)]
518 pub struct LocListIter<R: Reader> {
519     raw: RawLocListIter<R>,
520     base_address: u64,
521     debug_addr: DebugAddr<R>,
522     debug_addr_base: DebugAddrBase<R::Offset>,
523 }
524 
525 impl<R: Reader> LocListIter<R> {
526     /// Construct a `LocListIter`.
new( raw: RawLocListIter<R>, base_address: u64, debug_addr: DebugAddr<R>, debug_addr_base: DebugAddrBase<R::Offset>, ) -> LocListIter<R>527     fn new(
528         raw: RawLocListIter<R>,
529         base_address: u64,
530         debug_addr: DebugAddr<R>,
531         debug_addr_base: DebugAddrBase<R::Offset>,
532     ) -> LocListIter<R> {
533         LocListIter {
534             raw,
535             base_address,
536             debug_addr,
537             debug_addr_base,
538         }
539     }
540 
541     #[inline]
get_address(&self, index: DebugAddrIndex<R::Offset>) -> Result<u64>542     fn get_address(&self, index: DebugAddrIndex<R::Offset>) -> Result<u64> {
543         self.debug_addr
544             .get_address(self.raw.encoding.address_size, self.debug_addr_base, index)
545     }
546 
547     /// Advance the iterator to the next location.
next(&mut self) -> Result<Option<LocationListEntry<R>>>548     pub fn next(&mut self) -> Result<Option<LocationListEntry<R>>> {
549         loop {
550             let raw_loc = match self.raw.next()? {
551                 Some(loc) => loc,
552                 None => return Ok(None),
553             };
554 
555             let (range, data) = match raw_loc {
556                 RawLocListEntry::BaseAddress { addr } => {
557                     self.base_address = addr;
558                     continue;
559                 }
560                 RawLocListEntry::BaseAddressx { addr } => {
561                     self.base_address = self.get_address(addr)?;
562                     continue;
563                 }
564                 RawLocListEntry::StartxEndx { begin, end, data } => {
565                     let begin = self.get_address(begin)?;
566                     let end = self.get_address(end)?;
567                     (Range { begin, end }, data)
568                 }
569                 RawLocListEntry::StartxLength {
570                     begin,
571                     length,
572                     data,
573                 } => {
574                     let begin = self.get_address(begin)?;
575                     let end = begin + length;
576                     (Range { begin, end }, data)
577                 }
578                 RawLocListEntry::DefaultLocation { data } => (
579                     Range {
580                         begin: 0,
581                         end: u64::max_value(),
582                     },
583                     data,
584                 ),
585                 RawLocListEntry::AddressOrOffsetPair { begin, end, data }
586                 | RawLocListEntry::OffsetPair { begin, end, data } => {
587                     let mut range = Range { begin, end };
588                     range.add_base_address(self.base_address, self.raw.encoding.address_size);
589                     (range, data)
590                 }
591                 RawLocListEntry::StartEnd { begin, end, data } => (Range { begin, end }, data),
592                 RawLocListEntry::StartLength {
593                     begin,
594                     length,
595                     data,
596                 } => (
597                     Range {
598                         begin,
599                         end: begin + length,
600                     },
601                     data,
602                 ),
603             };
604 
605             if range.begin > range.end {
606                 self.raw.input.empty();
607                 return Err(Error::InvalidLocationAddressRange);
608             }
609 
610             return Ok(Some(LocationListEntry { range, data }));
611         }
612     }
613 }
614 
615 #[cfg(feature = "fallible-iterator")]
616 impl<R: Reader> fallible_iterator::FallibleIterator for LocListIter<R> {
617     type Item = LocationListEntry<R>;
618     type Error = Error;
619 
next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error>620     fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
621         LocListIter::next(self)
622     }
623 }
624 
625 /// A location list entry from the `.debug_loc` or `.debug_loclists` sections.
626 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
627 pub struct LocationListEntry<R: Reader> {
628     /// The address range that this location is valid for.
629     pub range: Range,
630 
631     /// The data containing a single location description.
632     pub data: Expression<R>,
633 }
634 
635 #[cfg(test)]
636 mod tests {
637     use super::*;
638     use crate::common::Format;
639     use crate::endianity::LittleEndian;
640     use crate::read::{EndianSlice, Range};
641     use crate::test_util::GimliSectionMethods;
642     use test_assembler::{Endian, Label, LabelMaker, Section};
643 
644     #[test]
test_loclists_32()645     fn test_loclists_32() {
646         let encoding = Encoding {
647             format: Format::Dwarf32,
648             version: 5,
649             address_size: 4,
650         };
651 
652         let section = Section::with_endian(Endian::Little)
653             .L32(0x0300_0000)
654             .L32(0x0301_0300)
655             .L32(0x0301_0400)
656             .L32(0x0301_0500);
657         let buf = section.get_contents().unwrap();
658         let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian));
659         let debug_addr_base = DebugAddrBase(0);
660 
661         let start = Label::new();
662         let first = Label::new();
663         let size = Label::new();
664         #[rustfmt::skip]
665         let section = Section::with_endian(Endian::Little)
666             // Header
667             .mark(&start)
668             .L32(&size)
669             .L16(encoding.version)
670             .L8(encoding.address_size)
671             .L8(0)
672             .L32(0)
673             .mark(&first)
674             // OffsetPair
675             .L8(4).uleb(0x10200).uleb(0x10300).uleb(4).L32(2)
676             // A base address selection followed by an OffsetPair.
677             .L8(6).L32(0x0200_0000)
678             .L8(4).uleb(0x10400).uleb(0x10500).uleb(4).L32(3)
679             // An empty OffsetPair followed by a normal OffsetPair.
680             .L8(4).uleb(0x10600).uleb(0x10600).uleb(4).L32(4)
681             .L8(4).uleb(0x10800).uleb(0x10900).uleb(4).L32(5)
682             // A StartEnd
683             .L8(7).L32(0x201_0a00).L32(0x201_0b00).uleb(4).L32(6)
684             // A StartLength
685             .L8(8).L32(0x201_0c00).uleb(0x100).uleb(4).L32(7)
686             // An OffsetPair that starts at 0.
687             .L8(4).uleb(0).uleb(1).uleb(4).L32(8)
688             // An OffsetPair that ends at -1.
689             .L8(6).L32(0)
690             .L8(4).uleb(0).uleb(0xffff_ffff).uleb(4).L32(9)
691             // A DefaultLocation
692             .L8(5).uleb(4).L32(10)
693             // A BaseAddressx + OffsetPair
694             .L8(1).uleb(0)
695             .L8(4).uleb(0x10100).uleb(0x10200).uleb(4).L32(11)
696             // A StartxEndx
697             .L8(2).uleb(1).uleb(2).uleb(4).L32(12)
698             // A StartxLength
699             .L8(3).uleb(3).uleb(0x100).uleb(4).L32(13)
700             // A range end.
701             .L8(0)
702             // Some extra data.
703             .L32(0xffff_ffff);
704         size.set_const((&section.here() - &start - 4) as u64);
705 
706         let buf = section.get_contents().unwrap();
707         let debug_loc = DebugLoc::new(&[], LittleEndian);
708         let debug_loclists = DebugLocLists::new(&buf, LittleEndian);
709         let loclists = LocationLists::new(debug_loc, debug_loclists);
710         let offset = LocationListsOffset((&first - &start) as usize);
711         let mut locations = loclists
712             .locations(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base)
713             .unwrap();
714 
715         // A normal location.
716         assert_eq!(
717             locations.next(),
718             Ok(Some(LocationListEntry {
719                 range: Range {
720                     begin: 0x0101_0200,
721                     end: 0x0101_0300,
722                 },
723                 data: Expression(EndianSlice::new(&[2, 0, 0, 0], LittleEndian)),
724             }))
725         );
726 
727         // A base address selection followed by a normal location.
728         assert_eq!(
729             locations.next(),
730             Ok(Some(LocationListEntry {
731                 range: Range {
732                     begin: 0x0201_0400,
733                     end: 0x0201_0500,
734                 },
735                 data: Expression(EndianSlice::new(&[3, 0, 0, 0], LittleEndian)),
736             }))
737         );
738 
739         // An empty location range followed by a normal location.
740         assert_eq!(
741             locations.next(),
742             Ok(Some(LocationListEntry {
743                 range: Range {
744                     begin: 0x0201_0600,
745                     end: 0x0201_0600,
746                 },
747                 data: Expression(EndianSlice::new(&[4, 0, 0, 0], LittleEndian)),
748             }))
749         );
750         assert_eq!(
751             locations.next(),
752             Ok(Some(LocationListEntry {
753                 range: Range {
754                     begin: 0x0201_0800,
755                     end: 0x0201_0900,
756                 },
757                 data: Expression(EndianSlice::new(&[5, 0, 0, 0], LittleEndian)),
758             }))
759         );
760 
761         // A normal location.
762         assert_eq!(
763             locations.next(),
764             Ok(Some(LocationListEntry {
765                 range: Range {
766                     begin: 0x0201_0a00,
767                     end: 0x0201_0b00,
768                 },
769                 data: Expression(EndianSlice::new(&[6, 0, 0, 0], LittleEndian)),
770             }))
771         );
772 
773         // A normal location.
774         assert_eq!(
775             locations.next(),
776             Ok(Some(LocationListEntry {
777                 range: Range {
778                     begin: 0x0201_0c00,
779                     end: 0x0201_0d00,
780                 },
781                 data: Expression(EndianSlice::new(&[7, 0, 0, 0], LittleEndian)),
782             }))
783         );
784 
785         // A location range that starts at 0.
786         assert_eq!(
787             locations.next(),
788             Ok(Some(LocationListEntry {
789                 range: Range {
790                     begin: 0x0200_0000,
791                     end: 0x0200_0001,
792                 },
793                 data: Expression(EndianSlice::new(&[8, 0, 0, 0], LittleEndian)),
794             }))
795         );
796 
797         // A location range that ends at -1.
798         assert_eq!(
799             locations.next(),
800             Ok(Some(LocationListEntry {
801                 range: Range {
802                     begin: 0x0000_0000,
803                     end: 0xffff_ffff,
804                 },
805                 data: Expression(EndianSlice::new(&[9, 0, 0, 0], LittleEndian)),
806             }))
807         );
808 
809         // A DefaultLocation.
810         assert_eq!(
811             locations.next(),
812             Ok(Some(LocationListEntry {
813                 range: Range {
814                     begin: 0,
815                     end: u64::max_value(),
816                 },
817                 data: Expression(EndianSlice::new(&[10, 0, 0, 0], LittleEndian)),
818             }))
819         );
820 
821         // A BaseAddressx + OffsetPair
822         assert_eq!(
823             locations.next(),
824             Ok(Some(LocationListEntry {
825                 range: Range {
826                     begin: 0x0301_0100,
827                     end: 0x0301_0200,
828                 },
829                 data: Expression(EndianSlice::new(&[11, 0, 0, 0], LittleEndian)),
830             }))
831         );
832 
833         // A StartxEndx
834         assert_eq!(
835             locations.next(),
836             Ok(Some(LocationListEntry {
837                 range: Range {
838                     begin: 0x0301_0300,
839                     end: 0x0301_0400,
840                 },
841                 data: Expression(EndianSlice::new(&[12, 0, 0, 0], LittleEndian)),
842             }))
843         );
844 
845         // A StartxLength
846         assert_eq!(
847             locations.next(),
848             Ok(Some(LocationListEntry {
849                 range: Range {
850                     begin: 0x0301_0500,
851                     end: 0x0301_0600,
852                 },
853                 data: Expression(EndianSlice::new(&[13, 0, 0, 0], LittleEndian)),
854             }))
855         );
856 
857         // A location list end.
858         assert_eq!(locations.next(), Ok(None));
859 
860         // An offset at the end of buf.
861         let mut locations = loclists
862             .locations(
863                 LocationListsOffset(buf.len()),
864                 encoding,
865                 0x0100_0000,
866                 debug_addr,
867                 debug_addr_base,
868             )
869             .unwrap();
870         assert_eq!(locations.next(), Ok(None));
871     }
872 
873     #[test]
test_loclists_64()874     fn test_loclists_64() {
875         let encoding = Encoding {
876             format: Format::Dwarf64,
877             version: 5,
878             address_size: 8,
879         };
880 
881         let section = Section::with_endian(Endian::Little)
882             .L64(0x0300_0000)
883             .L64(0x0301_0300)
884             .L64(0x0301_0400)
885             .L64(0x0301_0500);
886         let buf = section.get_contents().unwrap();
887         let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian));
888         let debug_addr_base = DebugAddrBase(0);
889 
890         let start = Label::new();
891         let first = Label::new();
892         let size = Label::new();
893         #[rustfmt::skip]
894         let section = Section::with_endian(Endian::Little)
895             // Header
896             .mark(&start)
897             .L32(0xffff_ffff)
898             .L64(&size)
899             .L16(encoding.version)
900             .L8(encoding.address_size)
901             .L8(0)
902             .L32(0)
903             .mark(&first)
904             // OffsetPair
905             .L8(4).uleb(0x10200).uleb(0x10300).uleb(4).L32(2)
906             // A base address selection followed by an OffsetPair.
907             .L8(6).L64(0x0200_0000)
908             .L8(4).uleb(0x10400).uleb(0x10500).uleb(4).L32(3)
909             // An empty OffsetPair followed by a normal OffsetPair.
910             .L8(4).uleb(0x10600).uleb(0x10600).uleb(4).L32(4)
911             .L8(4).uleb(0x10800).uleb(0x10900).uleb(4).L32(5)
912             // A StartEnd
913             .L8(7).L64(0x201_0a00).L64(0x201_0b00).uleb(4).L32(6)
914             // A StartLength
915             .L8(8).L64(0x201_0c00).uleb(0x100).uleb(4).L32(7)
916             // An OffsetPair that starts at 0.
917             .L8(4).uleb(0).uleb(1).uleb(4).L32(8)
918             // An OffsetPair that ends at -1.
919             .L8(6).L64(0)
920             .L8(4).uleb(0).uleb(0xffff_ffff).uleb(4).L32(9)
921             // A DefaultLocation
922             .L8(5).uleb(4).L32(10)
923             // A BaseAddressx + OffsetPair
924             .L8(1).uleb(0)
925             .L8(4).uleb(0x10100).uleb(0x10200).uleb(4).L32(11)
926             // A StartxEndx
927             .L8(2).uleb(1).uleb(2).uleb(4).L32(12)
928             // A StartxLength
929             .L8(3).uleb(3).uleb(0x100).uleb(4).L32(13)
930             // A range end.
931             .L8(0)
932             // Some extra data.
933             .L32(0xffff_ffff);
934         size.set_const((&section.here() - &start - 12) as u64);
935 
936         let buf = section.get_contents().unwrap();
937         let debug_loc = DebugLoc::new(&[], LittleEndian);
938         let debug_loclists = DebugLocLists::new(&buf, LittleEndian);
939         let loclists = LocationLists::new(debug_loc, debug_loclists);
940         let offset = LocationListsOffset((&first - &start) as usize);
941         let mut locations = loclists
942             .locations(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base)
943             .unwrap();
944 
945         // A normal location.
946         assert_eq!(
947             locations.next(),
948             Ok(Some(LocationListEntry {
949                 range: Range {
950                     begin: 0x0101_0200,
951                     end: 0x0101_0300,
952                 },
953                 data: Expression(EndianSlice::new(&[2, 0, 0, 0], LittleEndian)),
954             }))
955         );
956 
957         // A base address selection followed by a normal location.
958         assert_eq!(
959             locations.next(),
960             Ok(Some(LocationListEntry {
961                 range: Range {
962                     begin: 0x0201_0400,
963                     end: 0x0201_0500,
964                 },
965                 data: Expression(EndianSlice::new(&[3, 0, 0, 0], LittleEndian)),
966             }))
967         );
968 
969         // An empty location range followed by a normal location.
970         assert_eq!(
971             locations.next(),
972             Ok(Some(LocationListEntry {
973                 range: Range {
974                     begin: 0x0201_0600,
975                     end: 0x0201_0600,
976                 },
977                 data: Expression(EndianSlice::new(&[4, 0, 0, 0], LittleEndian)),
978             }))
979         );
980         assert_eq!(
981             locations.next(),
982             Ok(Some(LocationListEntry {
983                 range: Range {
984                     begin: 0x0201_0800,
985                     end: 0x0201_0900,
986                 },
987                 data: Expression(EndianSlice::new(&[5, 0, 0, 0], LittleEndian)),
988             }))
989         );
990 
991         // A normal location.
992         assert_eq!(
993             locations.next(),
994             Ok(Some(LocationListEntry {
995                 range: Range {
996                     begin: 0x0201_0a00,
997                     end: 0x0201_0b00,
998                 },
999                 data: Expression(EndianSlice::new(&[6, 0, 0, 0], LittleEndian)),
1000             }))
1001         );
1002 
1003         // A normal location.
1004         assert_eq!(
1005             locations.next(),
1006             Ok(Some(LocationListEntry {
1007                 range: Range {
1008                     begin: 0x0201_0c00,
1009                     end: 0x0201_0d00,
1010                 },
1011                 data: Expression(EndianSlice::new(&[7, 0, 0, 0], LittleEndian)),
1012             }))
1013         );
1014 
1015         // A location range that starts at 0.
1016         assert_eq!(
1017             locations.next(),
1018             Ok(Some(LocationListEntry {
1019                 range: Range {
1020                     begin: 0x0200_0000,
1021                     end: 0x0200_0001,
1022                 },
1023                 data: Expression(EndianSlice::new(&[8, 0, 0, 0], LittleEndian)),
1024             }))
1025         );
1026 
1027         // A location range that ends at -1.
1028         assert_eq!(
1029             locations.next(),
1030             Ok(Some(LocationListEntry {
1031                 range: Range {
1032                     begin: 0x0000_0000,
1033                     end: 0xffff_ffff,
1034                 },
1035                 data: Expression(EndianSlice::new(&[9, 0, 0, 0], LittleEndian)),
1036             }))
1037         );
1038 
1039         // A DefaultLocation.
1040         assert_eq!(
1041             locations.next(),
1042             Ok(Some(LocationListEntry {
1043                 range: Range {
1044                     begin: 0,
1045                     end: u64::max_value(),
1046                 },
1047                 data: Expression(EndianSlice::new(&[10, 0, 0, 0], LittleEndian)),
1048             }))
1049         );
1050 
1051         // A BaseAddressx + OffsetPair
1052         assert_eq!(
1053             locations.next(),
1054             Ok(Some(LocationListEntry {
1055                 range: Range {
1056                     begin: 0x0301_0100,
1057                     end: 0x0301_0200,
1058                 },
1059                 data: Expression(EndianSlice::new(&[11, 0, 0, 0], LittleEndian)),
1060             }))
1061         );
1062 
1063         // A StartxEndx
1064         assert_eq!(
1065             locations.next(),
1066             Ok(Some(LocationListEntry {
1067                 range: Range {
1068                     begin: 0x0301_0300,
1069                     end: 0x0301_0400,
1070                 },
1071                 data: Expression(EndianSlice::new(&[12, 0, 0, 0], LittleEndian)),
1072             }))
1073         );
1074 
1075         // A StartxLength
1076         assert_eq!(
1077             locations.next(),
1078             Ok(Some(LocationListEntry {
1079                 range: Range {
1080                     begin: 0x0301_0500,
1081                     end: 0x0301_0600,
1082                 },
1083                 data: Expression(EndianSlice::new(&[13, 0, 0, 0], LittleEndian)),
1084             }))
1085         );
1086 
1087         // A location list end.
1088         assert_eq!(locations.next(), Ok(None));
1089 
1090         // An offset at the end of buf.
1091         let mut locations = loclists
1092             .locations(
1093                 LocationListsOffset(buf.len()),
1094                 encoding,
1095                 0x0100_0000,
1096                 debug_addr,
1097                 debug_addr_base,
1098             )
1099             .unwrap();
1100         assert_eq!(locations.next(), Ok(None));
1101     }
1102 
1103     #[test]
test_location_list_32()1104     fn test_location_list_32() {
1105         let start = Label::new();
1106         let first = Label::new();
1107         #[rustfmt::skip]
1108         let section = Section::with_endian(Endian::Little)
1109             // A location before the offset.
1110             .mark(&start)
1111             .L32(0x10000).L32(0x10100).L16(4).L32(1)
1112             .mark(&first)
1113             // A normal location.
1114             .L32(0x10200).L32(0x10300).L16(4).L32(2)
1115             // A base address selection followed by a normal location.
1116             .L32(0xffff_ffff).L32(0x0200_0000)
1117             .L32(0x10400).L32(0x10500).L16(4).L32(3)
1118             // An empty location range followed by a normal location.
1119             .L32(0x10600).L32(0x10600).L16(4).L32(4)
1120             .L32(0x10800).L32(0x10900).L16(4).L32(5)
1121             // A location range that starts at 0.
1122             .L32(0).L32(1).L16(4).L32(6)
1123             // A location range that ends at -1.
1124             .L32(0xffff_ffff).L32(0x0000_0000)
1125             .L32(0).L32(0xffff_ffff).L16(4).L32(7)
1126             // A location list end.
1127             .L32(0).L32(0)
1128             // Some extra data.
1129             .L32(0);
1130 
1131         let buf = section.get_contents().unwrap();
1132         let debug_loc = DebugLoc::new(&buf, LittleEndian);
1133         let debug_loclists = DebugLocLists::new(&[], LittleEndian);
1134         let loclists = LocationLists::new(debug_loc, debug_loclists);
1135         let offset = LocationListsOffset((&first - &start) as usize);
1136         let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian));
1137         let debug_addr_base = DebugAddrBase(0);
1138         let encoding = Encoding {
1139             format: Format::Dwarf32,
1140             version: 4,
1141             address_size: 4,
1142         };
1143         let mut locations = loclists
1144             .locations(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base)
1145             .unwrap();
1146 
1147         // A normal location.
1148         assert_eq!(
1149             locations.next(),
1150             Ok(Some(LocationListEntry {
1151                 range: Range {
1152                     begin: 0x0101_0200,
1153                     end: 0x0101_0300,
1154                 },
1155                 data: Expression(EndianSlice::new(&[2, 0, 0, 0], LittleEndian)),
1156             }))
1157         );
1158 
1159         // A base address selection followed by a normal location.
1160         assert_eq!(
1161             locations.next(),
1162             Ok(Some(LocationListEntry {
1163                 range: Range {
1164                     begin: 0x0201_0400,
1165                     end: 0x0201_0500,
1166                 },
1167                 data: Expression(EndianSlice::new(&[3, 0, 0, 0], LittleEndian)),
1168             }))
1169         );
1170 
1171         // An empty location range followed by a normal location.
1172         assert_eq!(
1173             locations.next(),
1174             Ok(Some(LocationListEntry {
1175                 range: Range {
1176                     begin: 0x0201_0600,
1177                     end: 0x0201_0600,
1178                 },
1179                 data: Expression(EndianSlice::new(&[4, 0, 0, 0], LittleEndian)),
1180             }))
1181         );
1182         assert_eq!(
1183             locations.next(),
1184             Ok(Some(LocationListEntry {
1185                 range: Range {
1186                     begin: 0x0201_0800,
1187                     end: 0x0201_0900,
1188                 },
1189                 data: Expression(EndianSlice::new(&[5, 0, 0, 0], LittleEndian)),
1190             }))
1191         );
1192 
1193         // A location range that starts at 0.
1194         assert_eq!(
1195             locations.next(),
1196             Ok(Some(LocationListEntry {
1197                 range: Range {
1198                     begin: 0x0200_0000,
1199                     end: 0x0200_0001,
1200                 },
1201                 data: Expression(EndianSlice::new(&[6, 0, 0, 0], LittleEndian)),
1202             }))
1203         );
1204 
1205         // A location range that ends at -1.
1206         assert_eq!(
1207             locations.next(),
1208             Ok(Some(LocationListEntry {
1209                 range: Range {
1210                     begin: 0x0000_0000,
1211                     end: 0xffff_ffff,
1212                 },
1213                 data: Expression(EndianSlice::new(&[7, 0, 0, 0], LittleEndian)),
1214             }))
1215         );
1216 
1217         // A location list end.
1218         assert_eq!(locations.next(), Ok(None));
1219 
1220         // An offset at the end of buf.
1221         let mut locations = loclists
1222             .locations(
1223                 LocationListsOffset(buf.len()),
1224                 encoding,
1225                 0x0100_0000,
1226                 debug_addr,
1227                 debug_addr_base,
1228             )
1229             .unwrap();
1230         assert_eq!(locations.next(), Ok(None));
1231     }
1232 
1233     #[test]
test_location_list_64()1234     fn test_location_list_64() {
1235         let start = Label::new();
1236         let first = Label::new();
1237         #[rustfmt::skip]
1238         let section = Section::with_endian(Endian::Little)
1239             // A location before the offset.
1240             .mark(&start)
1241             .L64(0x10000).L64(0x10100).L16(4).L32(1)
1242             .mark(&first)
1243             // A normal location.
1244             .L64(0x10200).L64(0x10300).L16(4).L32(2)
1245             // A base address selection followed by a normal location.
1246             .L64(0xffff_ffff_ffff_ffff).L64(0x0200_0000)
1247             .L64(0x10400).L64(0x10500).L16(4).L32(3)
1248             // An empty location range followed by a normal location.
1249             .L64(0x10600).L64(0x10600).L16(4).L32(4)
1250             .L64(0x10800).L64(0x10900).L16(4).L32(5)
1251             // A location range that starts at 0.
1252             .L64(0).L64(1).L16(4).L32(6)
1253             // A location range that ends at -1.
1254             .L64(0xffff_ffff_ffff_ffff).L64(0x0000_0000)
1255             .L64(0).L64(0xffff_ffff_ffff_ffff).L16(4).L32(7)
1256             // A location list end.
1257             .L64(0).L64(0)
1258             // Some extra data.
1259             .L64(0);
1260 
1261         let buf = section.get_contents().unwrap();
1262         let debug_loc = DebugLoc::new(&buf, LittleEndian);
1263         let debug_loclists = DebugLocLists::new(&[], LittleEndian);
1264         let loclists = LocationLists::new(debug_loc, debug_loclists);
1265         let offset = LocationListsOffset((&first - &start) as usize);
1266         let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian));
1267         let debug_addr_base = DebugAddrBase(0);
1268         let encoding = Encoding {
1269             format: Format::Dwarf64,
1270             version: 4,
1271             address_size: 8,
1272         };
1273         let mut locations = loclists
1274             .locations(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base)
1275             .unwrap();
1276 
1277         // A normal location.
1278         assert_eq!(
1279             locations.next(),
1280             Ok(Some(LocationListEntry {
1281                 range: Range {
1282                     begin: 0x0101_0200,
1283                     end: 0x0101_0300,
1284                 },
1285                 data: Expression(EndianSlice::new(&[2, 0, 0, 0], LittleEndian)),
1286             }))
1287         );
1288 
1289         // A base address selection followed by a normal location.
1290         assert_eq!(
1291             locations.next(),
1292             Ok(Some(LocationListEntry {
1293                 range: Range {
1294                     begin: 0x0201_0400,
1295                     end: 0x0201_0500,
1296                 },
1297                 data: Expression(EndianSlice::new(&[3, 0, 0, 0], LittleEndian)),
1298             }))
1299         );
1300 
1301         // An empty location range followed by a normal location.
1302         assert_eq!(
1303             locations.next(),
1304             Ok(Some(LocationListEntry {
1305                 range: Range {
1306                     begin: 0x0201_0600,
1307                     end: 0x0201_0600,
1308                 },
1309                 data: Expression(EndianSlice::new(&[4, 0, 0, 0], LittleEndian)),
1310             }))
1311         );
1312         assert_eq!(
1313             locations.next(),
1314             Ok(Some(LocationListEntry {
1315                 range: Range {
1316                     begin: 0x0201_0800,
1317                     end: 0x0201_0900,
1318                 },
1319                 data: Expression(EndianSlice::new(&[5, 0, 0, 0], LittleEndian)),
1320             }))
1321         );
1322 
1323         // A location range that starts at 0.
1324         assert_eq!(
1325             locations.next(),
1326             Ok(Some(LocationListEntry {
1327                 range: Range {
1328                     begin: 0x0200_0000,
1329                     end: 0x0200_0001,
1330                 },
1331                 data: Expression(EndianSlice::new(&[6, 0, 0, 0], LittleEndian)),
1332             }))
1333         );
1334 
1335         // A location range that ends at -1.
1336         assert_eq!(
1337             locations.next(),
1338             Ok(Some(LocationListEntry {
1339                 range: Range {
1340                     begin: 0x0,
1341                     end: 0xffff_ffff_ffff_ffff,
1342                 },
1343                 data: Expression(EndianSlice::new(&[7, 0, 0, 0], LittleEndian)),
1344             }))
1345         );
1346 
1347         // A location list end.
1348         assert_eq!(locations.next(), Ok(None));
1349 
1350         // An offset at the end of buf.
1351         let mut locations = loclists
1352             .locations(
1353                 LocationListsOffset(buf.len()),
1354                 encoding,
1355                 0x0100_0000,
1356                 debug_addr,
1357                 debug_addr_base,
1358             )
1359             .unwrap();
1360         assert_eq!(locations.next(), Ok(None));
1361     }
1362 
1363     #[test]
test_locations_invalid()1364     fn test_locations_invalid() {
1365         #[rustfmt::skip]
1366         let section = Section::with_endian(Endian::Little)
1367             // An invalid location range.
1368             .L32(0x20000).L32(0x10000).L16(4).L32(1)
1369             // An invalid range after wrapping.
1370             .L32(0x20000).L32(0xff01_0000).L16(4).L32(2);
1371 
1372         let buf = section.get_contents().unwrap();
1373         let debug_loc = DebugLoc::new(&buf, LittleEndian);
1374         let debug_loclists = DebugLocLists::new(&[], LittleEndian);
1375         let loclists = LocationLists::new(debug_loc, debug_loclists);
1376         let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian));
1377         let debug_addr_base = DebugAddrBase(0);
1378         let encoding = Encoding {
1379             format: Format::Dwarf32,
1380             version: 4,
1381             address_size: 4,
1382         };
1383 
1384         // An invalid location range.
1385         let mut locations = loclists
1386             .locations(
1387                 LocationListsOffset(0x0),
1388                 encoding,
1389                 0x0100_0000,
1390                 debug_addr,
1391                 debug_addr_base,
1392             )
1393             .unwrap();
1394         assert_eq!(locations.next(), Err(Error::InvalidLocationAddressRange));
1395 
1396         // An invalid location range after wrapping.
1397         let mut locations = loclists
1398             .locations(
1399                 LocationListsOffset(14),
1400                 encoding,
1401                 0x0100_0000,
1402                 debug_addr,
1403                 debug_addr_base,
1404             )
1405             .unwrap();
1406         assert_eq!(locations.next(), Err(Error::InvalidLocationAddressRange));
1407 
1408         // An invalid offset.
1409         match loclists.locations(
1410             LocationListsOffset(buf.len() + 1),
1411             encoding,
1412             0x0100_0000,
1413             debug_addr,
1414             debug_addr_base,
1415         ) {
1416             Err(Error::UnexpectedEof(_)) => {}
1417             otherwise => panic!("Unexpected result: {:?}", otherwise),
1418         }
1419     }
1420 
1421     #[test]
test_get_offset()1422     fn test_get_offset() {
1423         for format in vec![Format::Dwarf32, Format::Dwarf64] {
1424             let encoding = Encoding {
1425                 format,
1426                 version: 5,
1427                 address_size: 4,
1428             };
1429 
1430             let zero = Label::new();
1431             let length = Label::new();
1432             let start = Label::new();
1433             let first = Label::new();
1434             let end = Label::new();
1435             let mut section = Section::with_endian(Endian::Little)
1436                 .mark(&zero)
1437                 .initial_length(format, &length, &start)
1438                 .D16(encoding.version)
1439                 .D8(encoding.address_size)
1440                 .D8(0)
1441                 .D32(20)
1442                 .mark(&first);
1443             for i in 0..20 {
1444                 section = section.word(format.word_size(), 1000 + i);
1445             }
1446             section = section.mark(&end);
1447             length.set_const((&end - &start) as u64);
1448             let section = section.get_contents().unwrap();
1449 
1450             let debug_loc = DebugLoc::from(EndianSlice::new(&[], LittleEndian));
1451             let debug_loclists = DebugLocLists::from(EndianSlice::new(&section, LittleEndian));
1452             let locations = LocationLists::new(debug_loc, debug_loclists);
1453 
1454             let base = DebugLocListsBase((&first - &zero) as usize);
1455             assert_eq!(
1456                 locations.get_offset(encoding, base, DebugLocListsIndex(0)),
1457                 Ok(LocationListsOffset(base.0 + 1000))
1458             );
1459             assert_eq!(
1460                 locations.get_offset(encoding, base, DebugLocListsIndex(19)),
1461                 Ok(LocationListsOffset(base.0 + 1019))
1462             );
1463         }
1464     }
1465 
1466     #[test]
test_loclists_gnu_v4_split_dwarf()1467     fn test_loclists_gnu_v4_split_dwarf() {
1468         #[rustfmt::skip]
1469         let buf = [
1470             0x03, // DW_LLE_startx_length
1471             0x00, // ULEB encoded b7
1472             0x08, 0x00, 0x00, 0x00, // Fixed 4 byte length of 8
1473             0x03, 0x00, // Fixed two byte length of the location
1474             0x11, 0x00, // DW_OP_constu 0
1475             0x9f, // DW_OP_stack_value
1476             // Padding data
1477             //0x99, 0x99, 0x99, 0x99
1478         ];
1479         let data_buf = [0x11, 0x00, 0x9f];
1480         let expected_data = EndianSlice::new(&data_buf, LittleEndian);
1481         let debug_loc = DebugLoc::new(&buf, LittleEndian);
1482         let debug_loclists = DebugLocLists::new(&[], LittleEndian);
1483         let loclists = LocationLists::new(debug_loc, debug_loclists);
1484         let debug_addr =
1485             &DebugAddr::from(EndianSlice::new(&[0x01, 0x02, 0x03, 0x04], LittleEndian));
1486         let debug_addr_base = DebugAddrBase(0);
1487         let encoding = Encoding {
1488             format: Format::Dwarf32,
1489             version: 4,
1490             address_size: 4,
1491         };
1492 
1493         // An invalid location range.
1494         let mut locations = loclists
1495             .locations_dwo(
1496                 LocationListsOffset(0x0),
1497                 encoding,
1498                 0,
1499                 debug_addr,
1500                 debug_addr_base,
1501             )
1502             .unwrap();
1503         assert_eq!(
1504             locations.next(),
1505             Ok(Some(LocationListEntry {
1506                 range: Range {
1507                     begin: 0x0403_0201,
1508                     end: 0x0403_0209
1509                 },
1510                 data: Expression(expected_data),
1511             }))
1512         );
1513     }
1514 }
1515