| use core::marker::PhantomData; |
| |
| use crate::common::{DebugInfoOffset, Format}; |
| use crate::read::{parse_debug_info_offset, Error, Reader, ReaderOffset, Result, UnitOffset}; |
| |
| // The various "Accelerated Access" sections (DWARF standard v4 Section 6.1) all have |
| // similar structures. They consist of a header with metadata and an offset into the |
| // .debug_info section for the entire compilation unit, and a series |
| // of following entries that list addresses (for .debug_aranges) or names |
| // (for .debug_pubnames and .debug_pubtypes) that are covered. |
| // |
| // Because these three tables all have similar structures, we abstract out some of |
| // the parsing mechanics. |
| |
| pub trait LookupParser<R: Reader> { |
| /// The type of the produced header. |
| type Header; |
| /// The type of the produced entry. |
| type Entry; |
| |
| /// Parse a header from `input`. Returns a tuple of `input` sliced to contain just the entries |
| /// corresponding to this header (without the header itself), and the parsed representation of |
| /// the header itself. |
| fn parse_header(input: &mut R) -> Result<(R, Self::Header)>; |
| |
| /// Parse a single entry from `input`. Returns either a parsed representation of the entry |
| /// or None if `input` is exhausted. |
| fn parse_entry(input: &mut R, header: &Self::Header) -> Result<Option<Self::Entry>>; |
| } |
| |
| #[derive(Clone, Debug)] |
| pub struct DebugLookup<R, Parser> |
| where |
| R: Reader, |
| Parser: LookupParser<R>, |
| { |
| input_buffer: R, |
| phantom: PhantomData<Parser>, |
| } |
| |
| impl<R, Parser> From<R> for DebugLookup<R, Parser> |
| where |
| R: Reader, |
| Parser: LookupParser<R>, |
| { |
| fn from(input_buffer: R) -> Self { |
| DebugLookup { |
| input_buffer, |
| phantom: PhantomData, |
| } |
| } |
| } |
| |
| impl<R, Parser> DebugLookup<R, Parser> |
| where |
| R: Reader, |
| Parser: LookupParser<R>, |
| { |
| pub fn items(&self) -> LookupEntryIter<R, Parser> { |
| LookupEntryIter { |
| current_set: None, |
| remaining_input: self.input_buffer.clone(), |
| } |
| } |
| |
| pub fn reader(&self) -> &R { |
| &self.input_buffer |
| } |
| } |
| |
| #[derive(Clone, Debug)] |
| pub struct LookupEntryIter<R, Parser> |
| where |
| R: Reader, |
| Parser: LookupParser<R>, |
| { |
| current_set: Option<(R, Parser::Header)>, // Only none at the very beginning and end. |
| remaining_input: R, |
| } |
| |
| impl<R, Parser> LookupEntryIter<R, Parser> |
| where |
| R: Reader, |
| Parser: LookupParser<R>, |
| { |
| /// Advance the iterator and return the next entry. |
| /// |
| /// Returns the newly parsed entry as `Ok(Some(Parser::Entry))`. Returns |
| /// `Ok(None)` when iteration is complete and all entries have already been |
| /// parsed and yielded. If an error occurs while parsing the next entry, |
| /// then this error is returned as `Err(e)`, and all subsequent calls return |
| /// `Ok(None)`. |
| /// |
| /// Can be [used with `FallibleIterator`](./index.html#using-with-fallibleiterator). |
| pub fn next(&mut self) -> Result<Option<Parser::Entry>> { |
| loop { |
| if let Some((ref mut input, ref header)) = self.current_set { |
| if !input.is_empty() { |
| match Parser::parse_entry(input, header) { |
| Ok(Some(entry)) => return Ok(Some(entry)), |
| Ok(None) => {} |
| Err(e) => { |
| input.empty(); |
| self.remaining_input.empty(); |
| return Err(e); |
| } |
| } |
| } |
| } |
| if self.remaining_input.is_empty() { |
| self.current_set = None; |
| return Ok(None); |
| } |
| match Parser::parse_header(&mut self.remaining_input) { |
| Ok(set) => { |
| self.current_set = Some(set); |
| } |
| Err(e) => { |
| self.current_set = None; |
| self.remaining_input.empty(); |
| return Err(e); |
| } |
| } |
| } |
| } |
| } |
| |
| #[derive(Debug, Clone, PartialEq, Eq)] |
| pub struct PubStuffHeader<T = usize> { |
| format: Format, |
| length: T, |
| version: u16, |
| unit_offset: DebugInfoOffset<T>, |
| unit_length: T, |
| } |
| |
| pub trait PubStuffEntry<R: Reader> { |
| fn new( |
| die_offset: UnitOffset<R::Offset>, |
| name: R, |
| unit_header_offset: DebugInfoOffset<R::Offset>, |
| ) -> Self; |
| } |
| |
| #[derive(Clone, Debug)] |
| pub struct PubStuffParser<R, Entry> |
| where |
| R: Reader, |
| Entry: PubStuffEntry<R>, |
| { |
| // This struct is never instantiated. |
| phantom: PhantomData<(R, Entry)>, |
| } |
| |
| impl<R, Entry> LookupParser<R> for PubStuffParser<R, Entry> |
| where |
| R: Reader, |
| Entry: PubStuffEntry<R>, |
| { |
| type Header = PubStuffHeader<R::Offset>; |
| type Entry = Entry; |
| |
| /// Parse an pubthings set header. Returns a tuple of the |
| /// pubthings to be parsed for this set, and the newly created PubThingHeader struct. |
| fn parse_header(input: &mut R) -> Result<(R, Self::Header)> { |
| let (length, format) = input.read_initial_length()?; |
| let mut rest = input.split(length)?; |
| |
| let version = rest.read_u16()?; |
| if version != 2 { |
| return Err(Error::UnknownVersion(u64::from(version))); |
| } |
| |
| let unit_offset = parse_debug_info_offset(&mut rest, format)?; |
| let unit_length = rest.read_length(format)?; |
| |
| let header = PubStuffHeader { |
| format, |
| length, |
| version, |
| unit_offset, |
| unit_length, |
| }; |
| Ok((rest, header)) |
| } |
| |
| /// Parse a single pubthing. Return `None` for the null pubthing, `Some` for an actual pubthing. |
| fn parse_entry(input: &mut R, header: &Self::Header) -> Result<Option<Self::Entry>> { |
| let offset = input.read_offset(header.format)?; |
| if offset.into_u64() == 0 { |
| input.empty(); |
| Ok(None) |
| } else { |
| let name = input.read_null_terminated_slice()?; |
| Ok(Some(Self::Entry::new( |
| UnitOffset(offset), |
| name, |
| header.unit_offset, |
| ))) |
| } |
| } |
| } |