aboutsummaryrefslogtreecommitdiff
path: root/vendor/gimli/src/read/lookup.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gimli/src/read/lookup.rs')
-rw-r--r--vendor/gimli/src/read/lookup.rs202
1 files changed, 202 insertions, 0 deletions
diff --git a/vendor/gimli/src/read/lookup.rs b/vendor/gimli/src/read/lookup.rs
new file mode 100644
index 0000000..1d082f2
--- /dev/null
+++ b/vendor/gimli/src/read/lookup.rs
@@ -0,0 +1,202 @@
+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,
+ )))
+ }
+ }
+}