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