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