diff --git a/benches/bench.rs b/benches/bench.rs index 7c49e54da..00bf2dbc7 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -195,9 +195,12 @@ fn bench_parsing_debug_aranges(b: &mut test::Bencher) { let debug_aranges = DebugAranges::new(&debug_aranges, LittleEndian); b.iter(|| { - let mut aranges = debug_aranges.items(); - while let Some(arange) = aranges.next().expect("Should parse arange OK") { - test::black_box(arange); + let mut headers = debug_aranges.headers(); + while let Some(header) = headers.next().expect("Should parse arange header OK") { + let mut entries = header.entries(); + while let Some(arange) = entries.next().expect("Should parse arange entry OK") { + test::black_box(arange); + } } }); } diff --git a/examples/dwarfdump.rs b/examples/dwarfdump.rs index 0875c0cb5..d6adcb87b 100644 --- a/examples/dwarfdump.rs +++ b/examples/dwarfdump.rs @@ -615,7 +615,7 @@ where } if flags.aranges { let debug_aranges = &gimli::Section::load(&mut load_section).unwrap(); - dump_aranges(w, debug_aranges, &dwarf.debug_info)?; + dump_aranges(w, debug_aranges)?; } if flags.pubtypes { let debug_pubtypes = &gimli::Section::load(&mut load_section).unwrap(); @@ -2108,36 +2108,33 @@ fn dump_pubtypes( fn dump_aranges( w: &mut W, debug_aranges: &gimli::DebugAranges, - debug_info: &gimli::DebugInfo, ) -> Result<()> { writeln!(w, "\n.debug_aranges")?; - let mut cu_die_offset = gimli::DebugInfoOffset(0); - let mut prev_cu_offset = None; - let mut aranges = debug_aranges.items(); - while let Some(arange) = aranges.next()? { - let cu_offset = arange.debug_info_offset(); - if Some(cu_offset) != prev_cu_offset { - let cu = debug_info.header_from_offset(cu_offset)?; - cu_die_offset = gimli::DebugInfoOffset(cu_offset.0 + cu.header_size()); - prev_cu_offset = Some(cu_offset); - } - if let Some(segment) = arange.segment() { - write!( - w, - "arange starts at seg,off 0x{:08x},0x{:08x}, ", - segment, - arange.address() - )?; - } else { - write!(w, "arange starts at 0x{:08x}, ", arange.address())?; - } + let mut headers = debug_aranges.headers(); + while let Some(header) = headers.next()? { writeln!( w, - "length of 0x{:08x}, cu_die_offset = 0x{:08x}", - arange.length(), - cu_die_offset.0 + "Address Range Header: length = 0x{:08x}, version = 0x{:04x}, cu_offset = 0x{:08x}, addr_size = 0x{:02x}, seg_size = 0x{:02x}", + header.length(), + header.encoding().version, + header.debug_info_offset().0, + header.encoding().address_size, + header.segment_size(), )?; + let mut aranges = header.entries(); + while let Some(arange) = aranges.next()? { + let range = arange.range(); + if let Some(segment) = arange.segment() { + writeln!( + w, + "[0x{:016x}, 0x{:016x}) segment 0x{:x}", + range.begin, range.end, segment + )?; + } else { + writeln!(w, "[0x{:016x}, 0x{:016x})", range.begin, range.end)?; + } + } } Ok(()) } diff --git a/fuzz/fuzz_targets/debug_aranges.rs b/fuzz/fuzz_targets/debug_aranges.rs index a7484af79..26f74ba8b 100755 --- a/fuzz/fuzz_targets/debug_aranges.rs +++ b/fuzz/fuzz_targets/debug_aranges.rs @@ -5,8 +5,11 @@ use libfuzzer_sys::fuzz_target; fuzz_target!(|debug_aranges: &[u8]| { let debug_aranges = DebugAranges::new(&debug_aranges, LittleEndian); - let mut items = debug_aranges.items(); - while let Ok(Some(_entry)) = items.next() { - continue; + let mut headers = debug_aranges.headers(); + while let Ok(Some(header)) = headers.next() { + let mut entries = header.entries(); + while let Ok(Some(_entry)) = entries.next() { + continue; + } } }); diff --git a/src/common.rs b/src/common.rs index 7cd4b5e3f..453311ca4 100644 --- a/src/common.rs +++ b/src/common.rs @@ -99,6 +99,10 @@ pub struct DebugAddrBase(pub T); #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct DebugAddrIndex(pub T); +/// An offset into the `.debug_aranges` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DebugArangesOffset(pub T); + /// An offset into the `.debug_info` section. #[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] pub struct DebugInfoOffset(pub T); diff --git a/src/read/aranges.rs b/src/read/aranges.rs index c03e33804..94d97ad51 100644 --- a/src/read/aranges.rs +++ b/src/read/aranges.rs @@ -1,85 +1,160 @@ -use core::cmp::Ordering; -use core::marker::PhantomData; - -use crate::common::{DebugInfoOffset, Encoding, SectionId}; +use crate::common::{DebugArangesOffset, DebugInfoOffset, Encoding, SectionId}; use crate::endianity::Endianity; -use crate::read::lookup::{DebugLookup, LookupEntryIter, LookupParser}; -use crate::read::{ - parse_debug_info_offset, EndianSlice, Error, Reader, ReaderOffset, Result, Section, -}; +use crate::read::{EndianSlice, Error, Range, Reader, ReaderOffset, Result, Section}; -#[derive(Debug, Clone, PartialEq, Eq)] -struct ArangeHeader { - encoding: Encoding, - length: T, - offset: DebugInfoOffset, - segment_size: u8, +/// The `DebugAranges` struct represents the DWARF address range information +/// found in the `.debug_aranges` section. +#[derive(Debug, Default, Clone, Copy)] +pub struct DebugAranges { + section: R, } -/// A single parsed arange. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ArangeEntry { - segment: Option, - address: u64, - length: u64, - unit_header_offset: DebugInfoOffset, +impl<'input, Endian> DebugAranges> +where + Endian: Endianity, +{ + /// Construct a new `DebugAranges` instance from the data in the `.debug_aranges` + /// section. + /// + /// It is the caller's responsibility to read the `.debug_aranges` section and + /// present it as a `&[u8]` slice. That means using some ELF loader on + /// Linux, a Mach-O loader on OSX, etc. + /// + /// ``` + /// use gimli::{DebugAranges, LittleEndian}; + /// + /// # let buf = []; + /// # let read_debug_aranges_section = || &buf; + /// let debug_aranges = + /// DebugAranges::new(read_debug_aranges_section(), LittleEndian); + /// ``` + pub fn new(section: &'input [u8], endian: Endian) -> Self { + DebugAranges { + section: EndianSlice::new(section, endian), + } + } } -impl ArangeEntry { - /// Return the segment selector of this arange. - #[inline] - pub fn segment(&self) -> Option { - self.segment +impl DebugAranges { + /// Iterate the sets of entries in the `.debug_aranges` section. + /// + /// Each set of entries belongs to a single unit. + pub fn headers(&self) -> ArangeHeaderIter { + ArangeHeaderIter { + input: self.section.clone(), + offset: DebugArangesOffset(R::Offset::from_u8(0)), + } } - /// Return the beginning address of this arange. - #[inline] - pub fn address(&self) -> u64 { - self.address + /// Get the header at the given offset. + pub fn header(&self, offset: DebugArangesOffset) -> Result> { + let mut input = self.section.clone(); + input.skip(offset.0)?; + ArangeHeader::parse(&mut input, offset) } +} - /// Return the length of this arange. - #[inline] - pub fn length(&self) -> u64 { - self.length +impl DebugAranges { + /// Create a `DebugAranges` section that references the data in `self`. + /// + /// This is useful when `R` implements `Reader` but `T` does not. + /// + /// ## Example Usage + /// + /// ```rust,no_run + /// # let load_section = || unimplemented!(); + /// // Read the DWARF section into a `Vec` with whatever object loader you're using. + /// let owned_section: gimli::DebugAranges> = load_section(); + /// // Create a reference to the DWARF section. + /// let section = owned_section.borrow(|section| { + /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) + /// }); + /// ``` + pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugAranges + where + F: FnMut(&'a T) -> R, + { + borrow(&self.section).into() } +} - /// Return the offset into the .debug_info section for this arange. - #[inline] - pub fn debug_info_offset(&self) -> DebugInfoOffset { - self.unit_header_offset +impl Section for DebugAranges { + fn id() -> SectionId { + SectionId::DebugAranges } -} -impl PartialOrd for ArangeEntry { - fn partial_cmp(&self, other: &ArangeEntry) -> Option { - Some(self.cmp(other)) + fn reader(&self) -> &R { + &self.section } } -impl Ord for ArangeEntry { - fn cmp(&self, other: &ArangeEntry) -> Ordering { - // The expected comparison, but ignore header. - self.segment - .cmp(&other.segment) - .then(self.address.cmp(&other.address)) - .then(self.length.cmp(&other.length)) +impl From for DebugAranges { + fn from(section: R) -> Self { + DebugAranges { section } } } +/// An iterator over the headers of a `.debug_aranges` section. #[derive(Clone, Debug)] -struct ArangeParser { - // This struct is never instantiated. - phantom: PhantomData, +pub struct ArangeHeaderIter { + input: R, + offset: DebugArangesOffset, +} + +impl ArangeHeaderIter { + /// Advance the iterator to the next header. + pub fn next(&mut self) -> Result>> { + if self.input.is_empty() { + return Ok(None); + } + + let len = self.input.len(); + match ArangeHeader::parse(&mut self.input, self.offset) { + Ok(header) => { + self.offset.0 += len - self.input.len(); + Ok(Some(header)) + } + Err(e) => { + self.input.empty(); + Err(e) + } + } + } } -impl LookupParser for ArangeParser { - type Header = ArangeHeader; - type Entry = ArangeEntry; +#[cfg(feature = "fallible-iterator")] +impl fallible_iterator::FallibleIterator for ArangeHeaderIter { + type Item = ArangeHeader; + type Error = Error; + + fn next(&mut self) -> ::core::result::Result, Self::Error> { + ArangeHeaderIter::next(self) + } +} + +/// A header for a set of entries in the `.debug_arange` section. +/// +/// These entries all belong to a single unit. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ArangeHeader::Offset> +where + R: Reader, + Offset: ReaderOffset, +{ + offset: DebugArangesOffset, + encoding: Encoding, + length: Offset, + debug_info_offset: DebugInfoOffset, + segment_size: u8, + entries: R, +} - /// Parse an arange set header. Returns a tuple of the aranges to be - /// parsed for this set, and the newly created ArangeHeader struct. - fn parse_header(input: &mut R) -> Result<(R, Self::Header)> { +impl ArangeHeader +where + R: Reader, + Offset: ReaderOffset, +{ + fn parse(input: &mut R, offset: DebugArangesOffset) -> Result { let (length, format) = input.read_initial_length()?; let mut rest = input.split(length)?; @@ -88,7 +163,7 @@ impl LookupParser for ArangeParser { return Err(Error::UnknownVersion(u64::from(version))); } - let offset = parse_debug_info_offset(&mut rest, format)?; + let debug_info_offset = rest.read_offset(format).map(DebugInfoOffset)?; let address_size = rest.read_u8()?; let segment_size = rest.read_u8()?; @@ -118,21 +193,120 @@ impl LookupParser for ArangeParser { address_size, // TODO: segment_size }; - Ok(( - rest, - ArangeHeader { - encoding, - length, - offset, - segment_size, - }, - )) + Ok(ArangeHeader { + offset, + encoding, + length, + debug_info_offset, + segment_size, + entries: rest, + }) + } + + /// Return the offset of this header within the `.debug_aranges` section. + #[inline] + pub fn offset(&self) -> DebugArangesOffset { + self.offset + } + + /// Return the length of this set of entries, including the header. + #[inline] + pub fn length(&self) -> Offset { + self.length + } + + /// Return the encoding parameters for this set of entries. + #[inline] + pub fn encoding(&self) -> Encoding { + self.encoding } + /// Return the segment size for this set of entries. + #[inline] + pub fn segment_size(&self) -> u8 { + self.segment_size + } + + /// Return the offset into the .debug_info section for this set of arange entries. + #[inline] + pub fn debug_info_offset(&self) -> DebugInfoOffset { + self.debug_info_offset + } + + /// Return the arange entries in this set. + #[inline] + pub fn entries(&self) -> ArangeEntryIter { + ArangeEntryIter { + input: self.entries.clone(), + encoding: self.encoding, + segment_size: self.segment_size, + } + } +} + +/// An iterator over the aranges from a `.debug_aranges` section. +/// +/// Can be [used with +/// `FallibleIterator`](./index.html#using-with-fallibleiterator). +#[derive(Debug, Clone)] +pub struct ArangeEntryIter { + input: R, + encoding: Encoding, + segment_size: u8, +} + +impl ArangeEntryIter { + /// Advance the iterator and return the next arange. + /// + /// Returns the newly parsed arange as `Ok(Some(arange))`. Returns `Ok(None)` + /// when iteration is complete and all aranges have already been parsed and + /// yielded. If an error occurs while parsing the next arange, then this error + /// is returned as `Err(e)`, and all subsequent calls return `Ok(None)`. + pub fn next(&mut self) -> Result> { + if self.input.is_empty() { + return Ok(None); + } + + match ArangeEntry::parse(&mut self.input, self.encoding, self.segment_size) { + Ok(Some(entry)) => Ok(Some(entry)), + Ok(None) => { + self.input.empty(); + Ok(None) + } + Err(e) => { + self.input.empty(); + Err(e) + } + } + } +} + +#[cfg(feature = "fallible-iterator")] +impl fallible_iterator::FallibleIterator for ArangeEntryIter { + type Item = ArangeEntry; + type Error = Error; + + fn next(&mut self) -> ::core::result::Result, Self::Error> { + ArangeEntryIter::next(self) + } +} + +/// A single parsed arange. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct ArangeEntry { + segment: Option, + address: u64, + length: u64, +} + +impl ArangeEntry { /// Parse a single arange. Return `None` for the null arange, `Some` for an actual arange. - fn parse_entry(input: &mut R, header: &Self::Header) -> Result> { - let address_size = header.encoding.address_size; - let segment_size = header.segment_size; // May be zero! + fn parse( + input: &mut R, + encoding: Encoding, + segment_size: u8, + ) -> Result> { + let address_size = encoding.address_size; let tuple_length = R::Offset::from_u8(2 * address_size + segment_size); if tuple_length > input.len() { @@ -149,10 +323,10 @@ impl LookupParser for ArangeParser { let length = input.read_address(address_size)?; match (segment, address, length) { - // There may be multiple sets of tuples, each terminated by a zero tuple. - // It's not clear what purpose these zero tuples serve. For now, we - // simply skip them. - (0, 0, 0) => Self::parse_entry(input, header), + // This is meant to be a null terminator, but in practice it can occur + // before the end, possibly due to a linker omitting a function and + // leaving an unrelocated entry. + (0, 0, 0) => Self::parse(input, encoding, segment_size), _ => Ok(Some(ArangeEntry { segment: if segment_size != 0 { Some(segment) @@ -161,103 +335,35 @@ impl LookupParser for ArangeParser { }, address, length, - unit_header_offset: header.offset, })), } } -} -/// The `DebugAranges` struct represents the DWARF address range information -/// found in the `.debug_aranges` section. -#[derive(Debug, Clone)] -pub struct DebugAranges(DebugLookup>); - -impl<'input, Endian> DebugAranges> -where - Endian: Endianity, -{ - /// Construct a new `DebugAranges` instance from the data in the `.debug_aranges` - /// section. - /// - /// It is the caller's responsibility to read the `.debug_aranges` section and - /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on OSX, etc. - /// - /// ``` - /// use gimli::{DebugAranges, LittleEndian}; - /// - /// # let buf = []; - /// # let read_debug_aranges_section = || &buf; - /// let debug_aranges = - /// DebugAranges::new(read_debug_aranges_section(), LittleEndian); - /// ``` - pub fn new(debug_aranges_section: &'input [u8], endian: Endian) -> Self { - Self::from(EndianSlice::new(debug_aranges_section, endian)) - } -} - -impl DebugAranges { - /// Iterate the aranges in the `.debug_aranges` section. - /// - /// ``` - /// use gimli::{DebugAranges, EndianSlice, LittleEndian}; - /// - /// # let buf = []; - /// # let read_debug_aranges_section = || &buf; - /// let debug_aranges = DebugAranges::new(read_debug_aranges_section(), LittleEndian); - /// - /// let mut iter = debug_aranges.items(); - /// while let Some(arange) = iter.next().unwrap() { - /// println!("arange starts at {}, has length {}", arange.address(), arange.length()); - /// } - /// ``` - pub fn items(&self) -> ArangeEntryIter { - ArangeEntryIter(self.0.items()) - } -} - -impl Section for DebugAranges { - fn id() -> SectionId { - SectionId::DebugAranges - } - - fn reader(&self) -> &R { - self.0.reader() + /// Return the segment selector of this arange. + #[inline] + pub fn segment(&self) -> Option { + self.segment } -} -impl From for DebugAranges { - fn from(debug_aranges_section: R) -> Self { - DebugAranges(DebugLookup::from(debug_aranges_section)) + /// Return the beginning address of this arange. + #[inline] + pub fn address(&self) -> u64 { + self.address } -} - -/// An iterator over the aranges from a `.debug_aranges` section. -/// -/// Can be [used with -/// `FallibleIterator`](./index.html#using-with-fallibleiterator). -#[derive(Debug, Clone)] -pub struct ArangeEntryIter(LookupEntryIter>); -impl ArangeEntryIter { - /// Advance the iterator and return the next arange. - /// - /// Returns the newly parsed arange as `Ok(Some(arange))`. Returns `Ok(None)` - /// when iteration is complete and all aranges have already been parsed and - /// yielded. If an error occurs while parsing the next arange, then this error - /// is returned as `Err(e)`, and all subsequent calls return `Ok(None)`. - pub fn next(&mut self) -> Result>> { - self.0.next() + /// Return the length of this arange. + #[inline] + pub fn length(&self) -> u64 { + self.length } -} - -#[cfg(feature = "fallible-iterator")] -impl fallible_iterator::FallibleIterator for ArangeEntryIter { - type Item = ArangeEntry; - type Error = Error; - fn next(&mut self) -> ::core::result::Result, Self::Error> { - self.0.next() + /// Return the range. + #[inline] + pub fn range(&self) -> Range { + Range { + begin: self.address, + end: self.address.wrapping_add(self.length), + } } } @@ -266,9 +372,62 @@ mod tests { use super::*; use crate::common::{DebugInfoOffset, Format}; use crate::endianity::LittleEndian; - use crate::read::lookup::LookupParser; use crate::read::EndianSlice; + #[test] + fn test_iterate_headers() { + #[rustfmt::skip] + let buf = [ + // 32-bit length = 28. + 0x1c, 0x00, 0x00, 0x00, + // Version. + 0x02, 0x00, + // Offset. + 0x01, 0x02, 0x03, 0x04, + // Address size. + 0x04, + // Segment size. + 0x00, + // Dummy padding and arange tuples. + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + // 32-bit length = 36. + 0x24, 0x00, 0x00, 0x00, + // Version. + 0x02, 0x00, + // Offset. + 0x11, 0x12, 0x13, 0x14, + // Address size. + 0x04, + // Segment size. + 0x00, + // Dummy padding and arange tuples. + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]; + + let debug_aranges = DebugAranges::new(&buf, LittleEndian); + let mut headers = debug_aranges.headers(); + + let header = headers + .next() + .expect("should parse header ok") + .expect("should have a header"); + assert_eq!(header.offset(), DebugArangesOffset(0)); + assert_eq!(header.debug_info_offset(), DebugInfoOffset(0x0403_0201)); + + let header = headers + .next() + .expect("should parse header ok") + .expect("should have a header"); + assert_eq!(header.offset(), DebugArangesOffset(0x20)); + assert_eq!(header.debug_info_offset(), DebugInfoOffset(0x1413_1211)); + } + #[test] fn test_parse_header_ok() { #[rustfmt::skip] @@ -303,27 +462,26 @@ mod tests { let rest = &mut EndianSlice::new(&buf, LittleEndian); - let (tuples, header) = ArangeParser::parse_header(rest).expect("should parse header ok"); + let header = + ArangeHeader::parse(rest, DebugArangesOffset(0x10)).expect("should parse header ok"); assert_eq!( *rest, EndianSlice::new(&buf[buf.len() - 16..], LittleEndian) ); - assert_eq!( - tuples, - EndianSlice::new(&buf[buf.len() - 32..buf.len() - 16], LittleEndian) - ); assert_eq!( header, ArangeHeader { + offset: DebugArangesOffset(0x10), encoding: Encoding { format: Format::Dwarf32, version: 2, address_size: 8, }, length: 0x20, - offset: DebugInfoOffset(0x0403_0201), + debug_info_offset: DebugInfoOffset(0x0403_0201), segment_size: 4, + entries: EndianSlice::new(&buf[buf.len() - 32..buf.len() - 16], LittleEndian), } ); } @@ -362,7 +520,8 @@ mod tests { let rest = &mut EndianSlice::new(&buf, LittleEndian); - let error = ArangeParser::parse_header(rest).expect_err("should fail to parse header"); + let error = ArangeHeader::parse(rest, DebugArangesOffset(0x10)) + .expect_err("should fail to parse header"); assert_eq!(error, Error::InvalidAddressRange); } @@ -401,25 +560,23 @@ mod tests { let rest = &mut EndianSlice::new(&buf, LittleEndian); - let error = ArangeParser::parse_header(rest).expect_err("should fail to parse header"); + let error = ArangeHeader::parse(rest, DebugArangesOffset(0x10)) + .expect_err("should fail to parse header"); assert_eq!(error, Error::InvalidAddressRange); } #[test] fn test_parse_entry_ok() { - let header = ArangeHeader { - encoding: Encoding { - format: Format::Dwarf32, - version: 2, - address_size: 4, - }, - length: 0, - offset: DebugInfoOffset(0), - segment_size: 0, + let encoding = Encoding { + format: Format::Dwarf32, + version: 2, + address_size: 4, }; + let segment_size = 0; let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09]; let rest = &mut EndianSlice::new(&buf, LittleEndian); - let entry = ArangeParser::parse_entry(rest, &header).expect("should parse entry ok"); + let entry = + ArangeEntry::parse(rest, encoding, segment_size).expect("should parse entry ok"); assert_eq!(*rest, EndianSlice::new(&buf[buf.len() - 1..], LittleEndian)); assert_eq!( entry, @@ -427,23 +584,18 @@ mod tests { segment: None, address: 0x0403_0201, length: 0x0807_0605, - unit_header_offset: header.offset, }) ); } #[test] fn test_parse_entry_segment() { - let header = ArangeHeader { - encoding: Encoding { - format: Format::Dwarf32, - version: 2, - address_size: 4, - }, - length: 0, - offset: DebugInfoOffset(0), - segment_size: 8, + let encoding = Encoding { + format: Format::Dwarf32, + version: 2, + address_size: 4, }; + let segment_size = 8; #[rustfmt::skip] let buf = [ // Segment. @@ -456,7 +608,8 @@ mod tests { 0x09 ]; let rest = &mut EndianSlice::new(&buf, LittleEndian); - let entry = ArangeParser::parse_entry(rest, &header).expect("should parse entry ok"); + let entry = + ArangeEntry::parse(rest, encoding, segment_size).expect("should parse entry ok"); assert_eq!(*rest, EndianSlice::new(&buf[buf.len() - 1..], LittleEndian)); assert_eq!( entry, @@ -464,23 +617,18 @@ mod tests { segment: Some(0x1817_1615_1413_1211), address: 0x0403_0201, length: 0x0807_0605, - unit_header_offset: header.offset, }) ); } #[test] fn test_parse_entry_zero() { - let header = ArangeHeader { - encoding: Encoding { - format: Format::Dwarf32, - version: 2, - address_size: 4, - }, - length: 0, - offset: DebugInfoOffset(0), - segment_size: 0, + let encoding = Encoding { + format: Format::Dwarf32, + version: 2, + address_size: 4, }; + let segment_size = 0; #[rustfmt::skip] let buf = [ // Zero tuple. @@ -493,7 +641,8 @@ mod tests { 0x09 ]; let rest = &mut EndianSlice::new(&buf, LittleEndian); - let entry = ArangeParser::parse_entry(rest, &header).expect("should parse entry ok"); + let entry = + ArangeEntry::parse(rest, encoding, segment_size).expect("should parse entry ok"); assert_eq!(*rest, EndianSlice::new(&buf[buf.len() - 1..], LittleEndian)); assert_eq!( entry, @@ -501,7 +650,6 @@ mod tests { segment: None, address: 0x0403_0201, length: 0x0807_0605, - unit_header_offset: header.offset, }) ); } diff --git a/src/read/dwarf.rs b/src/read/dwarf.rs index 10636c231..9002a7e2f 100644 --- a/src/read/dwarf.rs +++ b/src/read/dwarf.rs @@ -8,11 +8,11 @@ use crate::common::{ }; use crate::constants; use crate::read::{ - Abbreviations, AttributeValue, DebugAbbrev, DebugAddr, DebugInfo, DebugInfoUnitHeadersIter, - DebugLine, DebugLineStr, DebugStr, DebugStrOffsets, DebugTypes, DebugTypesUnitHeadersIter, - DebuggingInformationEntry, EntriesCursor, EntriesRaw, EntriesTree, Error, - IncompleteLineProgram, LocListIter, LocationLists, Range, RangeLists, Reader, ReaderOffset, - ReaderOffsetId, Result, RngListIter, Section, UnitHeader, UnitOffset, + Abbreviations, AttributeValue, DebugAbbrev, DebugAddr, DebugAranges, DebugInfo, + DebugInfoUnitHeadersIter, DebugLine, DebugLineStr, DebugStr, DebugStrOffsets, DebugTypes, + DebugTypesUnitHeadersIter, DebuggingInformationEntry, EntriesCursor, EntriesRaw, EntriesTree, + Error, IncompleteLineProgram, LocListIter, LocationLists, Range, RangeLists, Reader, + ReaderOffset, ReaderOffsetId, Result, RngListIter, Section, UnitHeader, UnitOffset, }; /// All of the commonly used DWARF sections, and other common information. @@ -24,6 +24,9 @@ pub struct Dwarf { /// The `.debug_addr` section. pub debug_addr: DebugAddr, + /// The `.debug_aranges` section. + pub debug_aranges: DebugAranges, + /// The `.debug_info` section. pub debug_info: DebugInfo, @@ -78,6 +81,7 @@ impl Dwarf { Ok(Dwarf { debug_abbrev: Section::load(&mut section)?, debug_addr: Section::load(&mut section)?, + debug_aranges: Section::load(&mut section)?, debug_info: Section::load(&mut section)?, debug_line: Section::load(&mut section)?, debug_line_str: Section::load(&mut section)?, @@ -124,6 +128,7 @@ impl Dwarf { Dwarf { debug_abbrev: self.debug_abbrev.borrow(&mut borrow), debug_addr: self.debug_addr.borrow(&mut borrow), + debug_aranges: self.debug_aranges.borrow(&mut borrow), debug_info: self.debug_info.borrow(&mut borrow), debug_line: self.debug_line.borrow(&mut borrow), debug_line_str: self.debug_line_str.borrow(&mut borrow), @@ -448,6 +453,7 @@ impl Dwarf { pub fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(bool, SectionId, R::Offset)> { None.or_else(|| self.debug_abbrev.lookup_offset_id(id)) .or_else(|| self.debug_addr.lookup_offset_id(id)) + .or_else(|| self.debug_aranges.lookup_offset_id(id)) .or_else(|| self.debug_info.lookup_offset_id(id)) .or_else(|| self.debug_line.lookup_offset_id(id)) .or_else(|| self.debug_line_str.lookup_offset_id(id)) diff --git a/src/read/mod.rs b/src/read/mod.rs index c5da32552..a9629b227 100644 --- a/src/read/mod.rs +++ b/src/read/mod.rs @@ -151,8 +151,10 @@ //! fn find_sum_of_address_range_lengths(aranges: DebugAranges>) //! -> gimli::Result //! { -//! // `DebugAranges::items` returns a `FallibleIterator`! -//! aranges.items() +//! // `DebugAranges::headers` returns a `FallibleIterator`! +//! aranges.headers() +//! // `flat_map` is provided by `FallibleIterator`! +//! .flat_map(|header| Ok(header.entries())) //! // `map` is provided by `FallibleIterator`! //! .map(|arange| Ok(arange.length())) //! // `fold` is provided by `FallibleIterator`! diff --git a/src/read/rnglists.rs b/src/read/rnglists.rs index 7f9b1961d..b60ef8b5a 100644 --- a/src/read/rnglists.rs +++ b/src/read/rnglists.rs @@ -563,7 +563,7 @@ impl RawRange { } } -/// An address range from the `.debug_ranges` or `.debug_rnglists` sections. +/// An address range from the `.debug_ranges`, `.debug_rnglists`, or `.debug_aranges` sections. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Range { /// The beginning address of the range. diff --git a/tests/parse_self.rs b/tests/parse_self.rs index 524998368..7d9764d6a 100755 --- a/tests/parse_self.rs +++ b/tests/parse_self.rs @@ -295,9 +295,12 @@ fn test_parse_self_debug_aranges() { let debug_aranges = read_section("debug_aranges"); let debug_aranges = DebugAranges::new(&debug_aranges, LittleEndian); - let mut aranges = debug_aranges.items(); - while let Some(_) = aranges.next().expect("Should parse arange OK") { - // Not really anything else we can check right now. + let mut headers = debug_aranges.headers(); + while let Some(header) = headers.next().expect("Should parse arange header OK") { + let mut entries = header.entries(); + while let Some(_) = entries.next().expect("Should parse arange entry OK") { + // Not really anything else we can check right now. + } } }