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 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)]
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(slice:section, endian))
38 }
39}
40
41impl<R> Section<R> for DebugLoc<R> {
42 fn id() -> SectionId {
43 SectionId::DebugLoc
44 }
45
46 fn reader(&self) -> &R {
47 &self.section
48 }
49}
50
51impl<R> From<R> for DebugLoc<R> {
52 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)]
60pub struct DebugLocLists<R> {
61 section: R,
62}
63
64impl<'input, Endian> DebugLocLists<EndianSlice<'input, Endian>>
65where
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 macOS, 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 /// ```
82 pub fn new(section: &'input [u8], endian: Endian) -> Self {
83 Self::from(EndianSlice::new(slice:section, endian))
84 }
85}
86
87impl<R> Section<R> for DebugLocLists<R> {
88 fn id() -> SectionId {
89 SectionId::DebugLocLists
90 }
91
92 fn reader(&self) -> &R {
93 &self.section
94 }
95}
96
97impl<R> From<R> for DebugLocLists<R> {
98 fn from(section: R) -> Self {
99 DebugLocLists { section }
100 }
101}
102
103pub(crate) type LocListsHeader = ListsHeader;
104
105impl<Offset> DebugLocListsBase<Offset>
106where
107 Offset: ReaderOffset,
108{
109 /// Returns a `DebugLocListsBase` with the default value of DW_AT_loclists_base
110 /// for the given `Encoding` and `DwarfFileType`.
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(offset:LocListsHeader::size_for_encoding(encoding)))
120 } else {
121 DebugLocListsBase(Offset::from_u8(offset:0))
122 }
123 }
124}
125
126/// The DWARF data found in `.debug_loc` and `.debug_loclists` sections.
127#[derive(Debug, Default, Clone, Copy)]
128pub struct LocationLists<R> {
129 debug_loc: DebugLoc<R>,
130 debug_loclists: DebugLocLists<R>,
131}
132
133impl<R> LocationLists<R> {
134 /// Construct a new `LocationLists` instance from the data in the `.debug_loc` and
135 /// `.debug_loclists` sections.
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
144impl<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 /// ```
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
171impl<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).
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.
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).
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.
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.
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.
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)]
298enum 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)]
311pub 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)]
319pub 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
391fn parse_data<R: Reader>(input: &mut R, encoding: Encoding) -> Result<Expression<R>> {
392 if encoding.version >= 5 {
393 let len: ::Offset = R::Offset::from_u64(offset: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: ::Offset = R::Offset::from_u16(offset:input.read_u16()?);
398 Ok(Expression(input.split(len)?))
399 }
400}
401
402impl<R: Reader> RawLocListEntry<R> {
403 /// Parse a location list entry from `.debug_loclists`
404 fn parse(input: &mut R, encoding: Encoding, format: LocListsFormat) -> Result<Option<Self>> {
405 Ok(match format {
406 LocListsFormat::Bare => {
407 let range = RawRange::parse(input, encoding.address_size)?;
408 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 => 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
471impl<R: Reader> RawLocListIter<R> {
472 /// Construct a `RawLocListIter`.
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.
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")]
503impl<R: Reader> fallible_iterator::FallibleIterator for RawLocListIter<R> {
504 type Item = RawLocListEntry<R>;
505 type Error = Error;
506
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)]
518pub 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
525impl<R: Reader> LocListIter<R> {
526 /// Construct a `LocListIter`.
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]
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.
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 loc = self.convert_raw(raw_loc)?;
556 if loc.is_some() {
557 return Ok(loc);
558 }
559 }
560 }
561
562 /// Return the next raw location.
563 ///
564 /// The raw location should be passed to `convert_raw`.
565 #[doc(hidden)]
566 pub fn next_raw(&mut self) -> Result<Option<RawLocListEntry<R>>> {
567 self.raw.next()
568 }
569
570 /// Convert a raw location into a location, and update the state of the iterator.
571 ///
572 /// The raw location should have been obtained from `next_raw`.
573 #[doc(hidden)]
574 pub fn convert_raw(
575 &mut self,
576 raw_loc: RawLocListEntry<R>,
577 ) -> Result<Option<LocationListEntry<R>>> {
578 let mask = !0 >> (64 - self.raw.encoding.address_size * 8);
579 let tombstone = if self.raw.encoding.version <= 4 {
580 mask - 1
581 } else {
582 mask
583 };
584
585 let (range, data) = match raw_loc {
586 RawLocListEntry::BaseAddress { addr } => {
587 self.base_address = addr;
588 return Ok(None);
589 }
590 RawLocListEntry::BaseAddressx { addr } => {
591 self.base_address = self.get_address(addr)?;
592 return Ok(None);
593 }
594 RawLocListEntry::StartxEndx { begin, end, data } => {
595 let begin = self.get_address(begin)?;
596 let end = self.get_address(end)?;
597 (Range { begin, end }, data)
598 }
599 RawLocListEntry::StartxLength {
600 begin,
601 length,
602 data,
603 } => {
604 let begin = self.get_address(begin)?;
605 let end = begin.wrapping_add(length) & mask;
606 (Range { begin, end }, data)
607 }
608 RawLocListEntry::DefaultLocation { data } => (
609 Range {
610 begin: 0,
611 end: u64::max_value(),
612 },
613 data,
614 ),
615 RawLocListEntry::AddressOrOffsetPair { begin, end, data }
616 | RawLocListEntry::OffsetPair { begin, end, data } => {
617 if self.base_address == tombstone {
618 return Ok(None);
619 }
620 let mut range = Range { begin, end };
621 range.add_base_address(self.base_address, self.raw.encoding.address_size);
622 (range, data)
623 }
624 RawLocListEntry::StartEnd { begin, end, data } => (Range { begin, end }, data),
625 RawLocListEntry::StartLength {
626 begin,
627 length,
628 data,
629 } => {
630 let end = begin.wrapping_add(length) & mask;
631 (Range { begin, end }, data)
632 }
633 };
634
635 if range.begin == tombstone {
636 return Ok(None);
637 }
638
639 if range.begin > range.end {
640 self.raw.input.empty();
641 return Err(Error::InvalidLocationAddressRange);
642 }
643
644 Ok(Some(LocationListEntry { range, data }))
645 }
646}
647
648#[cfg(feature = "fallible-iterator")]
649impl<R: Reader> fallible_iterator::FallibleIterator for LocListIter<R> {
650 type Item = LocationListEntry<R>;
651 type Error = Error;
652
653 fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
654 LocListIter::next(self)
655 }
656}
657
658/// A location list entry from the `.debug_loc` or `.debug_loclists` sections.
659#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
660pub struct LocationListEntry<R: Reader> {
661 /// The address range that this location is valid for.
662 pub range: Range,
663
664 /// The data containing a single location description.
665 pub data: Expression<R>,
666}
667
668#[cfg(test)]
669mod tests {
670 use super::*;
671 use crate::common::Format;
672 use crate::endianity::LittleEndian;
673 use crate::read::{EndianSlice, Range};
674 use crate::test_util::GimliSectionMethods;
675 use test_assembler::{Endian, Label, LabelMaker, Section};
676
677 #[test]
678 fn test_loclists_32() {
679 let tombstone = !0u32;
680 let encoding = Encoding {
681 format: Format::Dwarf32,
682 version: 5,
683 address_size: 4,
684 };
685
686 let section = Section::with_endian(Endian::Little)
687 .L32(0x0300_0000)
688 .L32(0x0301_0300)
689 .L32(0x0301_0400)
690 .L32(0x0301_0500)
691 .L32(tombstone)
692 .L32(0x0301_0600);
693 let buf = section.get_contents().unwrap();
694 let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian));
695 let debug_addr_base = DebugAddrBase(0);
696
697 let start = Label::new();
698 let first = Label::new();
699 let size = Label::new();
700 #[rustfmt::skip]
701 let section = Section::with_endian(Endian::Little)
702 // Header
703 .mark(&start)
704 .L32(&size)
705 .L16(encoding.version)
706 .L8(encoding.address_size)
707 .L8(0)
708 .L32(0)
709 .mark(&first)
710 // OffsetPair
711 .L8(4).uleb(0x10200).uleb(0x10300).uleb(4).L32(2)
712 // A base address selection followed by an OffsetPair.
713 .L8(6).L32(0x0200_0000)
714 .L8(4).uleb(0x10400).uleb(0x10500).uleb(4).L32(3)
715 // An empty OffsetPair followed by a normal OffsetPair.
716 .L8(4).uleb(0x10600).uleb(0x10600).uleb(4).L32(4)
717 .L8(4).uleb(0x10800).uleb(0x10900).uleb(4).L32(5)
718 // A StartEnd
719 .L8(7).L32(0x201_0a00).L32(0x201_0b00).uleb(4).L32(6)
720 // A StartLength
721 .L8(8).L32(0x201_0c00).uleb(0x100).uleb(4).L32(7)
722 // An OffsetPair that starts at 0.
723 .L8(4).uleb(0).uleb(1).uleb(4).L32(8)
724 // An OffsetPair that ends at -1.
725 .L8(6).L32(0)
726 .L8(4).uleb(0).uleb(0xffff_ffff).uleb(4).L32(9)
727 // A DefaultLocation
728 .L8(5).uleb(4).L32(10)
729 // A BaseAddressx + OffsetPair
730 .L8(1).uleb(0)
731 .L8(4).uleb(0x10100).uleb(0x10200).uleb(4).L32(11)
732 // A StartxEndx
733 .L8(2).uleb(1).uleb(2).uleb(4).L32(12)
734 // A StartxLength
735 .L8(3).uleb(3).uleb(0x100).uleb(4).L32(13)
736
737 // Tombstone entries, all of which should be ignored.
738 // A BaseAddressx that is a tombstone.
739 .L8(1).uleb(4)
740 .L8(4).uleb(0x11100).uleb(0x11200).uleb(4).L32(20)
741 // A BaseAddress that is a tombstone.
742 .L8(6).L32(tombstone)
743 .L8(4).uleb(0x11300).uleb(0x11400).uleb(4).L32(21)
744 // A StartxEndx that is a tombstone.
745 .L8(2).uleb(4).uleb(5).uleb(4).L32(22)
746 // A StartxLength that is a tombstone.
747 .L8(3).uleb(4).uleb(0x100).uleb(4).L32(23)
748 // A StartEnd that is a tombstone.
749 .L8(7).L32(tombstone).L32(0x201_1500).uleb(4).L32(24)
750 // A StartLength that is a tombstone.
751 .L8(8).L32(tombstone).uleb(0x100).uleb(4).L32(25)
752 // A StartEnd (not ignored)
753 .L8(7).L32(0x201_1600).L32(0x201_1700).uleb(4).L32(26)
754
755 // A range end.
756 .L8(0)
757 // Some extra data.
758 .L32(0xffff_ffff);
759 size.set_const((&section.here() - &start - 4) as u64);
760
761 let buf = section.get_contents().unwrap();
762 let debug_loc = DebugLoc::new(&[], LittleEndian);
763 let debug_loclists = DebugLocLists::new(&buf, LittleEndian);
764 let loclists = LocationLists::new(debug_loc, debug_loclists);
765 let offset = LocationListsOffset((&first - &start) as usize);
766 let mut locations = loclists
767 .locations(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base)
768 .unwrap();
769
770 // A normal location.
771 assert_eq!(
772 locations.next(),
773 Ok(Some(LocationListEntry {
774 range: Range {
775 begin: 0x0101_0200,
776 end: 0x0101_0300,
777 },
778 data: Expression(EndianSlice::new(&[2, 0, 0, 0], LittleEndian)),
779 }))
780 );
781
782 // A base address selection followed by a normal location.
783 assert_eq!(
784 locations.next(),
785 Ok(Some(LocationListEntry {
786 range: Range {
787 begin: 0x0201_0400,
788 end: 0x0201_0500,
789 },
790 data: Expression(EndianSlice::new(&[3, 0, 0, 0], LittleEndian)),
791 }))
792 );
793
794 // An empty location range followed by a normal location.
795 assert_eq!(
796 locations.next(),
797 Ok(Some(LocationListEntry {
798 range: Range {
799 begin: 0x0201_0600,
800 end: 0x0201_0600,
801 },
802 data: Expression(EndianSlice::new(&[4, 0, 0, 0], LittleEndian)),
803 }))
804 );
805 assert_eq!(
806 locations.next(),
807 Ok(Some(LocationListEntry {
808 range: Range {
809 begin: 0x0201_0800,
810 end: 0x0201_0900,
811 },
812 data: Expression(EndianSlice::new(&[5, 0, 0, 0], LittleEndian)),
813 }))
814 );
815
816 // A normal location.
817 assert_eq!(
818 locations.next(),
819 Ok(Some(LocationListEntry {
820 range: Range {
821 begin: 0x0201_0a00,
822 end: 0x0201_0b00,
823 },
824 data: Expression(EndianSlice::new(&[6, 0, 0, 0], LittleEndian)),
825 }))
826 );
827
828 // A normal location.
829 assert_eq!(
830 locations.next(),
831 Ok(Some(LocationListEntry {
832 range: Range {
833 begin: 0x0201_0c00,
834 end: 0x0201_0d00,
835 },
836 data: Expression(EndianSlice::new(&[7, 0, 0, 0], LittleEndian)),
837 }))
838 );
839
840 // A location range that starts at 0.
841 assert_eq!(
842 locations.next(),
843 Ok(Some(LocationListEntry {
844 range: Range {
845 begin: 0x0200_0000,
846 end: 0x0200_0001,
847 },
848 data: Expression(EndianSlice::new(&[8, 0, 0, 0], LittleEndian)),
849 }))
850 );
851
852 // A location range that ends at -1.
853 assert_eq!(
854 locations.next(),
855 Ok(Some(LocationListEntry {
856 range: Range {
857 begin: 0x0000_0000,
858 end: 0xffff_ffff,
859 },
860 data: Expression(EndianSlice::new(&[9, 0, 0, 0], LittleEndian)),
861 }))
862 );
863
864 // A DefaultLocation.
865 assert_eq!(
866 locations.next(),
867 Ok(Some(LocationListEntry {
868 range: Range {
869 begin: 0,
870 end: u64::max_value(),
871 },
872 data: Expression(EndianSlice::new(&[10, 0, 0, 0], LittleEndian)),
873 }))
874 );
875
876 // A BaseAddressx + OffsetPair
877 assert_eq!(
878 locations.next(),
879 Ok(Some(LocationListEntry {
880 range: Range {
881 begin: 0x0301_0100,
882 end: 0x0301_0200,
883 },
884 data: Expression(EndianSlice::new(&[11, 0, 0, 0], LittleEndian)),
885 }))
886 );
887
888 // A StartxEndx
889 assert_eq!(
890 locations.next(),
891 Ok(Some(LocationListEntry {
892 range: Range {
893 begin: 0x0301_0300,
894 end: 0x0301_0400,
895 },
896 data: Expression(EndianSlice::new(&[12, 0, 0, 0], LittleEndian)),
897 }))
898 );
899
900 // A StartxLength
901 assert_eq!(
902 locations.next(),
903 Ok(Some(LocationListEntry {
904 range: Range {
905 begin: 0x0301_0500,
906 end: 0x0301_0600,
907 },
908 data: Expression(EndianSlice::new(&[13, 0, 0, 0], LittleEndian)),
909 }))
910 );
911
912 // A StartEnd location following the tombstones
913 assert_eq!(
914 locations.next(),
915 Ok(Some(LocationListEntry {
916 range: Range {
917 begin: 0x0201_1600,
918 end: 0x0201_1700,
919 },
920 data: Expression(EndianSlice::new(&[26, 0, 0, 0], LittleEndian)),
921 }))
922 );
923
924 // A location list end.
925 assert_eq!(locations.next(), Ok(None));
926
927 // An offset at the end of buf.
928 let mut locations = loclists
929 .locations(
930 LocationListsOffset(buf.len()),
931 encoding,
932 0x0100_0000,
933 debug_addr,
934 debug_addr_base,
935 )
936 .unwrap();
937 assert_eq!(locations.next(), Ok(None));
938 }
939
940 #[test]
941 fn test_loclists_64() {
942 let tombstone = !0u64;
943 let encoding = Encoding {
944 format: Format::Dwarf64,
945 version: 5,
946 address_size: 8,
947 };
948
949 let section = Section::with_endian(Endian::Little)
950 .L64(0x0300_0000)
951 .L64(0x0301_0300)
952 .L64(0x0301_0400)
953 .L64(0x0301_0500)
954 .L64(tombstone)
955 .L64(0x0301_0600);
956 let buf = section.get_contents().unwrap();
957 let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian));
958 let debug_addr_base = DebugAddrBase(0);
959
960 let start = Label::new();
961 let first = Label::new();
962 let size = Label::new();
963 #[rustfmt::skip]
964 let section = Section::with_endian(Endian::Little)
965 // Header
966 .mark(&start)
967 .L32(0xffff_ffff)
968 .L64(&size)
969 .L16(encoding.version)
970 .L8(encoding.address_size)
971 .L8(0)
972 .L32(0)
973 .mark(&first)
974 // OffsetPair
975 .L8(4).uleb(0x10200).uleb(0x10300).uleb(4).L32(2)
976 // A base address selection followed by an OffsetPair.
977 .L8(6).L64(0x0200_0000)
978 .L8(4).uleb(0x10400).uleb(0x10500).uleb(4).L32(3)
979 // An empty OffsetPair followed by a normal OffsetPair.
980 .L8(4).uleb(0x10600).uleb(0x10600).uleb(4).L32(4)
981 .L8(4).uleb(0x10800).uleb(0x10900).uleb(4).L32(5)
982 // A StartEnd
983 .L8(7).L64(0x201_0a00).L64(0x201_0b00).uleb(4).L32(6)
984 // A StartLength
985 .L8(8).L64(0x201_0c00).uleb(0x100).uleb(4).L32(7)
986 // An OffsetPair that starts at 0.
987 .L8(4).uleb(0).uleb(1).uleb(4).L32(8)
988 // An OffsetPair that ends at -1.
989 .L8(6).L64(0)
990 .L8(4).uleb(0).uleb(0xffff_ffff).uleb(4).L32(9)
991 // A DefaultLocation
992 .L8(5).uleb(4).L32(10)
993 // A BaseAddressx + OffsetPair
994 .L8(1).uleb(0)
995 .L8(4).uleb(0x10100).uleb(0x10200).uleb(4).L32(11)
996 // A StartxEndx
997 .L8(2).uleb(1).uleb(2).uleb(4).L32(12)
998 // A StartxLength
999 .L8(3).uleb(3).uleb(0x100).uleb(4).L32(13)
1000
1001 // Tombstone entries, all of which should be ignored.
1002 // A BaseAddressx that is a tombstone.
1003 .L8(1).uleb(4)
1004 .L8(4).uleb(0x11100).uleb(0x11200).uleb(4).L32(20)
1005 // A BaseAddress that is a tombstone.
1006 .L8(6).L64(tombstone)
1007 .L8(4).uleb(0x11300).uleb(0x11400).uleb(4).L32(21)
1008 // A StartxEndx that is a tombstone.
1009 .L8(2).uleb(4).uleb(5).uleb(4).L32(22)
1010 // A StartxLength that is a tombstone.
1011 .L8(3).uleb(4).uleb(0x100).uleb(4).L32(23)
1012 // A StartEnd that is a tombstone.
1013 .L8(7).L64(tombstone).L64(0x201_1500).uleb(4).L32(24)
1014 // A StartLength that is a tombstone.
1015 .L8(8).L64(tombstone).uleb(0x100).uleb(4).L32(25)
1016 // A StartEnd (not ignored)
1017 .L8(7).L64(0x201_1600).L64(0x201_1700).uleb(4).L32(26)
1018
1019 // A range end.
1020 .L8(0)
1021 // Some extra data.
1022 .L32(0xffff_ffff);
1023 size.set_const((&section.here() - &start - 12) as u64);
1024
1025 let buf = section.get_contents().unwrap();
1026 let debug_loc = DebugLoc::new(&[], LittleEndian);
1027 let debug_loclists = DebugLocLists::new(&buf, LittleEndian);
1028 let loclists = LocationLists::new(debug_loc, debug_loclists);
1029 let offset = LocationListsOffset((&first - &start) as usize);
1030 let mut locations = loclists
1031 .locations(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base)
1032 .unwrap();
1033
1034 // A normal location.
1035 assert_eq!(
1036 locations.next(),
1037 Ok(Some(LocationListEntry {
1038 range: Range {
1039 begin: 0x0101_0200,
1040 end: 0x0101_0300,
1041 },
1042 data: Expression(EndianSlice::new(&[2, 0, 0, 0], LittleEndian)),
1043 }))
1044 );
1045
1046 // A base address selection followed by a normal location.
1047 assert_eq!(
1048 locations.next(),
1049 Ok(Some(LocationListEntry {
1050 range: Range {
1051 begin: 0x0201_0400,
1052 end: 0x0201_0500,
1053 },
1054 data: Expression(EndianSlice::new(&[3, 0, 0, 0], LittleEndian)),
1055 }))
1056 );
1057
1058 // An empty location range followed by a normal location.
1059 assert_eq!(
1060 locations.next(),
1061 Ok(Some(LocationListEntry {
1062 range: Range {
1063 begin: 0x0201_0600,
1064 end: 0x0201_0600,
1065 },
1066 data: Expression(EndianSlice::new(&[4, 0, 0, 0], LittleEndian)),
1067 }))
1068 );
1069 assert_eq!(
1070 locations.next(),
1071 Ok(Some(LocationListEntry {
1072 range: Range {
1073 begin: 0x0201_0800,
1074 end: 0x0201_0900,
1075 },
1076 data: Expression(EndianSlice::new(&[5, 0, 0, 0], LittleEndian)),
1077 }))
1078 );
1079
1080 // A normal location.
1081 assert_eq!(
1082 locations.next(),
1083 Ok(Some(LocationListEntry {
1084 range: Range {
1085 begin: 0x0201_0a00,
1086 end: 0x0201_0b00,
1087 },
1088 data: Expression(EndianSlice::new(&[6, 0, 0, 0], LittleEndian)),
1089 }))
1090 );
1091
1092 // A normal location.
1093 assert_eq!(
1094 locations.next(),
1095 Ok(Some(LocationListEntry {
1096 range: Range {
1097 begin: 0x0201_0c00,
1098 end: 0x0201_0d00,
1099 },
1100 data: Expression(EndianSlice::new(&[7, 0, 0, 0], LittleEndian)),
1101 }))
1102 );
1103
1104 // A location range that starts at 0.
1105 assert_eq!(
1106 locations.next(),
1107 Ok(Some(LocationListEntry {
1108 range: Range {
1109 begin: 0x0200_0000,
1110 end: 0x0200_0001,
1111 },
1112 data: Expression(EndianSlice::new(&[8, 0, 0, 0], LittleEndian)),
1113 }))
1114 );
1115
1116 // A location range that ends at -1.
1117 assert_eq!(
1118 locations.next(),
1119 Ok(Some(LocationListEntry {
1120 range: Range {
1121 begin: 0x0000_0000,
1122 end: 0xffff_ffff,
1123 },
1124 data: Expression(EndianSlice::new(&[9, 0, 0, 0], LittleEndian)),
1125 }))
1126 );
1127
1128 // A DefaultLocation.
1129 assert_eq!(
1130 locations.next(),
1131 Ok(Some(LocationListEntry {
1132 range: Range {
1133 begin: 0,
1134 end: u64::max_value(),
1135 },
1136 data: Expression(EndianSlice::new(&[10, 0, 0, 0], LittleEndian)),
1137 }))
1138 );
1139
1140 // A BaseAddressx + OffsetPair
1141 assert_eq!(
1142 locations.next(),
1143 Ok(Some(LocationListEntry {
1144 range: Range {
1145 begin: 0x0301_0100,
1146 end: 0x0301_0200,
1147 },
1148 data: Expression(EndianSlice::new(&[11, 0, 0, 0], LittleEndian)),
1149 }))
1150 );
1151
1152 // A StartxEndx
1153 assert_eq!(
1154 locations.next(),
1155 Ok(Some(LocationListEntry {
1156 range: Range {
1157 begin: 0x0301_0300,
1158 end: 0x0301_0400,
1159 },
1160 data: Expression(EndianSlice::new(&[12, 0, 0, 0], LittleEndian)),
1161 }))
1162 );
1163
1164 // A StartxLength
1165 assert_eq!(
1166 locations.next(),
1167 Ok(Some(LocationListEntry {
1168 range: Range {
1169 begin: 0x0301_0500,
1170 end: 0x0301_0600,
1171 },
1172 data: Expression(EndianSlice::new(&[13, 0, 0, 0], LittleEndian)),
1173 }))
1174 );
1175
1176 // A StartEnd location following the tombstones
1177 assert_eq!(
1178 locations.next(),
1179 Ok(Some(LocationListEntry {
1180 range: Range {
1181 begin: 0x0201_1600,
1182 end: 0x0201_1700,
1183 },
1184 data: Expression(EndianSlice::new(&[26, 0, 0, 0], LittleEndian)),
1185 }))
1186 );
1187
1188 // A location list end.
1189 assert_eq!(locations.next(), Ok(None));
1190
1191 // An offset at the end of buf.
1192 let mut locations = loclists
1193 .locations(
1194 LocationListsOffset(buf.len()),
1195 encoding,
1196 0x0100_0000,
1197 debug_addr,
1198 debug_addr_base,
1199 )
1200 .unwrap();
1201 assert_eq!(locations.next(), Ok(None));
1202 }
1203
1204 #[test]
1205 fn test_location_list_32() {
1206 let tombstone = !0u32 - 1;
1207 let start = Label::new();
1208 let first = Label::new();
1209 #[rustfmt::skip]
1210 let section = Section::with_endian(Endian::Little)
1211 // A location before the offset.
1212 .mark(&start)
1213 .L32(0x10000).L32(0x10100).L16(4).L32(1)
1214 .mark(&first)
1215 // A normal location.
1216 .L32(0x10200).L32(0x10300).L16(4).L32(2)
1217 // A base address selection followed by a normal location.
1218 .L32(0xffff_ffff).L32(0x0200_0000)
1219 .L32(0x10400).L32(0x10500).L16(4).L32(3)
1220 // An empty location range followed by a normal location.
1221 .L32(0x10600).L32(0x10600).L16(4).L32(4)
1222 .L32(0x10800).L32(0x10900).L16(4).L32(5)
1223 // A location range that starts at 0.
1224 .L32(0).L32(1).L16(4).L32(6)
1225 // A location range that ends at -1.
1226 .L32(0xffff_ffff).L32(0x0000_0000)
1227 .L32(0).L32(0xffff_ffff).L16(4).L32(7)
1228 // A normal location with tombstone.
1229 .L32(tombstone).L32(tombstone).L16(4).L32(8)
1230 // A base address selection with tombstone followed by a normal location.
1231 .L32(0xffff_ffff).L32(tombstone)
1232 .L32(0x10a00).L32(0x10b00).L16(4).L32(9)
1233 // A location list end.
1234 .L32(0).L32(0)
1235 // Some extra data.
1236 .L32(0);
1237
1238 let buf = section.get_contents().unwrap();
1239 let debug_loc = DebugLoc::new(&buf, LittleEndian);
1240 let debug_loclists = DebugLocLists::new(&[], LittleEndian);
1241 let loclists = LocationLists::new(debug_loc, debug_loclists);
1242 let offset = LocationListsOffset((&first - &start) as usize);
1243 let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian));
1244 let debug_addr_base = DebugAddrBase(0);
1245 let encoding = Encoding {
1246 format: Format::Dwarf32,
1247 version: 4,
1248 address_size: 4,
1249 };
1250 let mut locations = loclists
1251 .locations(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base)
1252 .unwrap();
1253
1254 // A normal location.
1255 assert_eq!(
1256 locations.next(),
1257 Ok(Some(LocationListEntry {
1258 range: Range {
1259 begin: 0x0101_0200,
1260 end: 0x0101_0300,
1261 },
1262 data: Expression(EndianSlice::new(&[2, 0, 0, 0], LittleEndian)),
1263 }))
1264 );
1265
1266 // A base address selection followed by a normal location.
1267 assert_eq!(
1268 locations.next(),
1269 Ok(Some(LocationListEntry {
1270 range: Range {
1271 begin: 0x0201_0400,
1272 end: 0x0201_0500,
1273 },
1274 data: Expression(EndianSlice::new(&[3, 0, 0, 0], LittleEndian)),
1275 }))
1276 );
1277
1278 // An empty location range followed by a normal location.
1279 assert_eq!(
1280 locations.next(),
1281 Ok(Some(LocationListEntry {
1282 range: Range {
1283 begin: 0x0201_0600,
1284 end: 0x0201_0600,
1285 },
1286 data: Expression(EndianSlice::new(&[4, 0, 0, 0], LittleEndian)),
1287 }))
1288 );
1289 assert_eq!(
1290 locations.next(),
1291 Ok(Some(LocationListEntry {
1292 range: Range {
1293 begin: 0x0201_0800,
1294 end: 0x0201_0900,
1295 },
1296 data: Expression(EndianSlice::new(&[5, 0, 0, 0], LittleEndian)),
1297 }))
1298 );
1299
1300 // A location range that starts at 0.
1301 assert_eq!(
1302 locations.next(),
1303 Ok(Some(LocationListEntry {
1304 range: Range {
1305 begin: 0x0200_0000,
1306 end: 0x0200_0001,
1307 },
1308 data: Expression(EndianSlice::new(&[6, 0, 0, 0], LittleEndian)),
1309 }))
1310 );
1311
1312 // A location range that ends at -1.
1313 assert_eq!(
1314 locations.next(),
1315 Ok(Some(LocationListEntry {
1316 range: Range {
1317 begin: 0x0000_0000,
1318 end: 0xffff_ffff,
1319 },
1320 data: Expression(EndianSlice::new(&[7, 0, 0, 0], LittleEndian)),
1321 }))
1322 );
1323
1324 // A location list end.
1325 assert_eq!(locations.next(), Ok(None));
1326
1327 // An offset at the end of buf.
1328 let mut locations = loclists
1329 .locations(
1330 LocationListsOffset(buf.len()),
1331 encoding,
1332 0x0100_0000,
1333 debug_addr,
1334 debug_addr_base,
1335 )
1336 .unwrap();
1337 assert_eq!(locations.next(), Ok(None));
1338 }
1339
1340 #[test]
1341 fn test_location_list_64() {
1342 let tombstone = !0u64 - 1;
1343 let start = Label::new();
1344 let first = Label::new();
1345 #[rustfmt::skip]
1346 let section = Section::with_endian(Endian::Little)
1347 // A location before the offset.
1348 .mark(&start)
1349 .L64(0x10000).L64(0x10100).L16(4).L32(1)
1350 .mark(&first)
1351 // A normal location.
1352 .L64(0x10200).L64(0x10300).L16(4).L32(2)
1353 // A base address selection followed by a normal location.
1354 .L64(0xffff_ffff_ffff_ffff).L64(0x0200_0000)
1355 .L64(0x10400).L64(0x10500).L16(4).L32(3)
1356 // An empty location range followed by a normal location.
1357 .L64(0x10600).L64(0x10600).L16(4).L32(4)
1358 .L64(0x10800).L64(0x10900).L16(4).L32(5)
1359 // A location range that starts at 0.
1360 .L64(0).L64(1).L16(4).L32(6)
1361 // A location range that ends at -1.
1362 .L64(0xffff_ffff_ffff_ffff).L64(0x0000_0000)
1363 .L64(0).L64(0xffff_ffff_ffff_ffff).L16(4).L32(7)
1364 // A normal location with tombstone.
1365 .L64(tombstone).L64(tombstone).L16(4).L32(8)
1366 // A base address selection with tombstone followed by a normal location.
1367 .L64(0xffff_ffff_ffff_ffff).L64(tombstone)
1368 .L64(0x10a00).L64(0x10b00).L16(4).L32(9)
1369 // A location list end.
1370 .L64(0).L64(0)
1371 // Some extra data.
1372 .L64(0);
1373
1374 let buf = section.get_contents().unwrap();
1375 let debug_loc = DebugLoc::new(&buf, LittleEndian);
1376 let debug_loclists = DebugLocLists::new(&[], LittleEndian);
1377 let loclists = LocationLists::new(debug_loc, debug_loclists);
1378 let offset = LocationListsOffset((&first - &start) as usize);
1379 let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian));
1380 let debug_addr_base = DebugAddrBase(0);
1381 let encoding = Encoding {
1382 format: Format::Dwarf64,
1383 version: 4,
1384 address_size: 8,
1385 };
1386 let mut locations = loclists
1387 .locations(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base)
1388 .unwrap();
1389
1390 // A normal location.
1391 assert_eq!(
1392 locations.next(),
1393 Ok(Some(LocationListEntry {
1394 range: Range {
1395 begin: 0x0101_0200,
1396 end: 0x0101_0300,
1397 },
1398 data: Expression(EndianSlice::new(&[2, 0, 0, 0], LittleEndian)),
1399 }))
1400 );
1401
1402 // A base address selection followed by a normal location.
1403 assert_eq!(
1404 locations.next(),
1405 Ok(Some(LocationListEntry {
1406 range: Range {
1407 begin: 0x0201_0400,
1408 end: 0x0201_0500,
1409 },
1410 data: Expression(EndianSlice::new(&[3, 0, 0, 0], LittleEndian)),
1411 }))
1412 );
1413
1414 // An empty location range followed by a normal location.
1415 assert_eq!(
1416 locations.next(),
1417 Ok(Some(LocationListEntry {
1418 range: Range {
1419 begin: 0x0201_0600,
1420 end: 0x0201_0600,
1421 },
1422 data: Expression(EndianSlice::new(&[4, 0, 0, 0], LittleEndian)),
1423 }))
1424 );
1425 assert_eq!(
1426 locations.next(),
1427 Ok(Some(LocationListEntry {
1428 range: Range {
1429 begin: 0x0201_0800,
1430 end: 0x0201_0900,
1431 },
1432 data: Expression(EndianSlice::new(&[5, 0, 0, 0], LittleEndian)),
1433 }))
1434 );
1435
1436 // A location range that starts at 0.
1437 assert_eq!(
1438 locations.next(),
1439 Ok(Some(LocationListEntry {
1440 range: Range {
1441 begin: 0x0200_0000,
1442 end: 0x0200_0001,
1443 },
1444 data: Expression(EndianSlice::new(&[6, 0, 0, 0], LittleEndian)),
1445 }))
1446 );
1447
1448 // A location range that ends at -1.
1449 assert_eq!(
1450 locations.next(),
1451 Ok(Some(LocationListEntry {
1452 range: Range {
1453 begin: 0x0,
1454 end: 0xffff_ffff_ffff_ffff,
1455 },
1456 data: Expression(EndianSlice::new(&[7, 0, 0, 0], LittleEndian)),
1457 }))
1458 );
1459
1460 // A location list end.
1461 assert_eq!(locations.next(), Ok(None));
1462
1463 // An offset at the end of buf.
1464 let mut locations = loclists
1465 .locations(
1466 LocationListsOffset(buf.len()),
1467 encoding,
1468 0x0100_0000,
1469 debug_addr,
1470 debug_addr_base,
1471 )
1472 .unwrap();
1473 assert_eq!(locations.next(), Ok(None));
1474 }
1475
1476 #[test]
1477 fn test_locations_invalid() {
1478 #[rustfmt::skip]
1479 let section = Section::with_endian(Endian::Little)
1480 // An invalid location range.
1481 .L32(0x20000).L32(0x10000).L16(4).L32(1)
1482 // An invalid range after wrapping.
1483 .L32(0x20000).L32(0xff01_0000).L16(4).L32(2);
1484
1485 let buf = section.get_contents().unwrap();
1486 let debug_loc = DebugLoc::new(&buf, LittleEndian);
1487 let debug_loclists = DebugLocLists::new(&[], LittleEndian);
1488 let loclists = LocationLists::new(debug_loc, debug_loclists);
1489 let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian));
1490 let debug_addr_base = DebugAddrBase(0);
1491 let encoding = Encoding {
1492 format: Format::Dwarf32,
1493 version: 4,
1494 address_size: 4,
1495 };
1496
1497 // An invalid location range.
1498 let mut locations = loclists
1499 .locations(
1500 LocationListsOffset(0x0),
1501 encoding,
1502 0x0100_0000,
1503 debug_addr,
1504 debug_addr_base,
1505 )
1506 .unwrap();
1507 assert_eq!(locations.next(), Err(Error::InvalidLocationAddressRange));
1508
1509 // An invalid location range after wrapping.
1510 let mut locations = loclists
1511 .locations(
1512 LocationListsOffset(14),
1513 encoding,
1514 0x0100_0000,
1515 debug_addr,
1516 debug_addr_base,
1517 )
1518 .unwrap();
1519 assert_eq!(locations.next(), Err(Error::InvalidLocationAddressRange));
1520
1521 // An invalid offset.
1522 match loclists.locations(
1523 LocationListsOffset(buf.len() + 1),
1524 encoding,
1525 0x0100_0000,
1526 debug_addr,
1527 debug_addr_base,
1528 ) {
1529 Err(Error::UnexpectedEof(_)) => {}
1530 otherwise => panic!("Unexpected result: {:?}", otherwise),
1531 }
1532 }
1533
1534 #[test]
1535 fn test_get_offset() {
1536 for format in vec![Format::Dwarf32, Format::Dwarf64] {
1537 let encoding = Encoding {
1538 format,
1539 version: 5,
1540 address_size: 4,
1541 };
1542
1543 let zero = Label::new();
1544 let length = Label::new();
1545 let start = Label::new();
1546 let first = Label::new();
1547 let end = Label::new();
1548 let mut section = Section::with_endian(Endian::Little)
1549 .mark(&zero)
1550 .initial_length(format, &length, &start)
1551 .D16(encoding.version)
1552 .D8(encoding.address_size)
1553 .D8(0)
1554 .D32(20)
1555 .mark(&first);
1556 for i in 0..20 {
1557 section = section.word(format.word_size(), 1000 + i);
1558 }
1559 section = section.mark(&end);
1560 length.set_const((&end - &start) as u64);
1561 let section = section.get_contents().unwrap();
1562
1563 let debug_loc = DebugLoc::from(EndianSlice::new(&[], LittleEndian));
1564 let debug_loclists = DebugLocLists::from(EndianSlice::new(&section, LittleEndian));
1565 let locations = LocationLists::new(debug_loc, debug_loclists);
1566
1567 let base = DebugLocListsBase((&first - &zero) as usize);
1568 assert_eq!(
1569 locations.get_offset(encoding, base, DebugLocListsIndex(0)),
1570 Ok(LocationListsOffset(base.0 + 1000))
1571 );
1572 assert_eq!(
1573 locations.get_offset(encoding, base, DebugLocListsIndex(19)),
1574 Ok(LocationListsOffset(base.0 + 1019))
1575 );
1576 }
1577 }
1578
1579 #[test]
1580 fn test_loclists_gnu_v4_split_dwarf() {
1581 #[rustfmt::skip]
1582 let buf = [
1583 0x03, // DW_LLE_startx_length
1584 0x00, // ULEB encoded b7
1585 0x08, 0x00, 0x00, 0x00, // Fixed 4 byte length of 8
1586 0x03, 0x00, // Fixed two byte length of the location
1587 0x11, 0x00, // DW_OP_constu 0
1588 0x9f, // DW_OP_stack_value
1589 // Padding data
1590 //0x99, 0x99, 0x99, 0x99
1591 ];
1592 let data_buf = [0x11, 0x00, 0x9f];
1593 let expected_data = EndianSlice::new(&data_buf, LittleEndian);
1594 let debug_loc = DebugLoc::new(&buf, LittleEndian);
1595 let debug_loclists = DebugLocLists::new(&[], LittleEndian);
1596 let loclists = LocationLists::new(debug_loc, debug_loclists);
1597 let debug_addr =
1598 &DebugAddr::from(EndianSlice::new(&[0x01, 0x02, 0x03, 0x04], LittleEndian));
1599 let debug_addr_base = DebugAddrBase(0);
1600 let encoding = Encoding {
1601 format: Format::Dwarf32,
1602 version: 4,
1603 address_size: 4,
1604 };
1605
1606 // An invalid location range.
1607 let mut locations = loclists
1608 .locations_dwo(
1609 LocationListsOffset(0x0),
1610 encoding,
1611 0,
1612 debug_addr,
1613 debug_addr_base,
1614 )
1615 .unwrap();
1616 assert_eq!(
1617 locations.next(),
1618 Ok(Some(LocationListEntry {
1619 range: Range {
1620 begin: 0x0403_0201,
1621 end: 0x0403_0209
1622 },
1623 data: Expression(expected_data),
1624 }))
1625 );
1626 }
1627}
1628