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(§ion, 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((§ion.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((§ion.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(§ion, 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