| 1 | use core::marker::PhantomData; |
| 2 | |
| 3 | use crate::common::{DebugInfoOffset, Format}; |
| 4 | use crate::read::{parse_debug_info_offset, Error, Reader, ReaderOffset, Result, UnitOffset}; |
| 5 | |
| 6 | // The various "Accelerated Access" sections (DWARF standard v4 Section 6.1) all have |
| 7 | // similar structures. They consist of a header with metadata and an offset into the |
| 8 | // .debug_info section for the entire compilation unit, and a series |
| 9 | // of following entries that list addresses (for .debug_aranges) or names |
| 10 | // (for .debug_pubnames and .debug_pubtypes) that are covered. |
| 11 | // |
| 12 | // Because these three tables all have similar structures, we abstract out some of |
| 13 | // the parsing mechanics. |
| 14 | |
| 15 | pub trait LookupParser<R: Reader> { |
| 16 | /// The type of the produced header. |
| 17 | type Header; |
| 18 | /// The type of the produced entry. |
| 19 | type Entry; |
| 20 | |
| 21 | /// Parse a header from `input`. Returns a tuple of `input` sliced to contain just the entries |
| 22 | /// corresponding to this header (without the header itself), and the parsed representation of |
| 23 | /// the header itself. |
| 24 | fn parse_header(input: &mut R) -> Result<(R, Self::Header)>; |
| 25 | |
| 26 | /// Parse a single entry from `input`. Returns either a parsed representation of the entry |
| 27 | /// or None if `input` is exhausted. |
| 28 | fn parse_entry(input: &mut R, header: &Self::Header) -> Result<Option<Self::Entry>>; |
| 29 | } |
| 30 | |
| 31 | #[derive (Clone, Debug)] |
| 32 | pub struct DebugLookup<R, Parser> |
| 33 | where |
| 34 | R: Reader, |
| 35 | Parser: LookupParser<R>, |
| 36 | { |
| 37 | input_buffer: R, |
| 38 | phantom: PhantomData<Parser>, |
| 39 | } |
| 40 | |
| 41 | impl<R, Parser> From<R> for DebugLookup<R, Parser> |
| 42 | where |
| 43 | R: Reader, |
| 44 | Parser: LookupParser<R>, |
| 45 | { |
| 46 | fn from(input_buffer: R) -> Self { |
| 47 | DebugLookup { |
| 48 | input_buffer, |
| 49 | phantom: PhantomData, |
| 50 | } |
| 51 | } |
| 52 | } |
| 53 | |
| 54 | impl<R, Parser> DebugLookup<R, Parser> |
| 55 | where |
| 56 | R: Reader, |
| 57 | Parser: LookupParser<R>, |
| 58 | { |
| 59 | pub fn items(&self) -> LookupEntryIter<R, Parser> { |
| 60 | LookupEntryIter { |
| 61 | current_set: None, |
| 62 | remaining_input: self.input_buffer.clone(), |
| 63 | } |
| 64 | } |
| 65 | |
| 66 | pub fn reader(&self) -> &R { |
| 67 | &self.input_buffer |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | #[derive (Clone, Debug)] |
| 72 | pub struct LookupEntryIter<R, Parser> |
| 73 | where |
| 74 | R: Reader, |
| 75 | Parser: LookupParser<R>, |
| 76 | { |
| 77 | current_set: Option<(R, Parser::Header)>, // Only none at the very beginning and end. |
| 78 | remaining_input: R, |
| 79 | } |
| 80 | |
| 81 | impl<R, Parser> LookupEntryIter<R, Parser> |
| 82 | where |
| 83 | R: Reader, |
| 84 | Parser: LookupParser<R>, |
| 85 | { |
| 86 | /// Advance the iterator and return the next entry. |
| 87 | /// |
| 88 | /// Returns the newly parsed entry as `Ok(Some(Parser::Entry))`. Returns |
| 89 | /// `Ok(None)` when iteration is complete and all entries have already been |
| 90 | /// parsed and yielded. If an error occurs while parsing the next entry, |
| 91 | /// then this error is returned as `Err(e)`, and all subsequent calls return |
| 92 | /// `Ok(None)`. |
| 93 | /// |
| 94 | /// Can be [used with `FallibleIterator`](./index.html#using-with-fallibleiterator). |
| 95 | pub fn next(&mut self) -> Result<Option<Parser::Entry>> { |
| 96 | loop { |
| 97 | if let Some((ref mut input, ref header)) = self.current_set { |
| 98 | if !input.is_empty() { |
| 99 | match Parser::parse_entry(input, header) { |
| 100 | Ok(Some(entry)) => return Ok(Some(entry)), |
| 101 | Ok(None) => {} |
| 102 | Err(e) => { |
| 103 | input.empty(); |
| 104 | self.remaining_input.empty(); |
| 105 | return Err(e); |
| 106 | } |
| 107 | } |
| 108 | } |
| 109 | } |
| 110 | if self.remaining_input.is_empty() { |
| 111 | self.current_set = None; |
| 112 | return Ok(None); |
| 113 | } |
| 114 | match Parser::parse_header(&mut self.remaining_input) { |
| 115 | Ok(set) => { |
| 116 | self.current_set = Some(set); |
| 117 | } |
| 118 | Err(e) => { |
| 119 | self.current_set = None; |
| 120 | self.remaining_input.empty(); |
| 121 | return Err(e); |
| 122 | } |
| 123 | } |
| 124 | } |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | #[derive (Debug, Clone, PartialEq, Eq)] |
| 129 | pub struct PubStuffHeader<T = usize> { |
| 130 | format: Format, |
| 131 | length: T, |
| 132 | version: u16, |
| 133 | unit_offset: DebugInfoOffset<T>, |
| 134 | unit_length: T, |
| 135 | } |
| 136 | |
| 137 | pub trait PubStuffEntry<R: Reader> { |
| 138 | fn new( |
| 139 | die_offset: UnitOffset<R::Offset>, |
| 140 | name: R, |
| 141 | unit_header_offset: DebugInfoOffset<R::Offset>, |
| 142 | ) -> Self; |
| 143 | } |
| 144 | |
| 145 | #[derive (Clone, Debug)] |
| 146 | pub struct PubStuffParser<R, Entry> |
| 147 | where |
| 148 | R: Reader, |
| 149 | Entry: PubStuffEntry<R>, |
| 150 | { |
| 151 | // This struct is never instantiated. |
| 152 | phantom: PhantomData<(R, Entry)>, |
| 153 | } |
| 154 | |
| 155 | impl<R, Entry> LookupParser<R> for PubStuffParser<R, Entry> |
| 156 | where |
| 157 | R: Reader, |
| 158 | Entry: PubStuffEntry<R>, |
| 159 | { |
| 160 | type Header = PubStuffHeader<R::Offset>; |
| 161 | type Entry = Entry; |
| 162 | |
| 163 | /// Parse an pubthings set header. Returns a tuple of the |
| 164 | /// pubthings to be parsed for this set, and the newly created PubThingHeader struct. |
| 165 | fn parse_header(input: &mut R) -> Result<(R, Self::Header)> { |
| 166 | let (length, format) = input.read_initial_length()?; |
| 167 | let mut rest = input.split(length)?; |
| 168 | |
| 169 | let version = rest.read_u16()?; |
| 170 | if version != 2 { |
| 171 | return Err(Error::UnknownVersion(u64::from(version))); |
| 172 | } |
| 173 | |
| 174 | let unit_offset = parse_debug_info_offset(&mut rest, format)?; |
| 175 | let unit_length = rest.read_length(format)?; |
| 176 | |
| 177 | let header = PubStuffHeader { |
| 178 | format, |
| 179 | length, |
| 180 | version, |
| 181 | unit_offset, |
| 182 | unit_length, |
| 183 | }; |
| 184 | Ok((rest, header)) |
| 185 | } |
| 186 | |
| 187 | /// Parse a single pubthing. Return `None` for the null pubthing, `Some` for an actual pubthing. |
| 188 | fn parse_entry(input: &mut R, header: &Self::Header) -> Result<Option<Self::Entry>> { |
| 189 | let offset = input.read_offset(header.format)?; |
| 190 | if offset.into_u64() == 0 { |
| 191 | input.empty(); |
| 192 | Ok(None) |
| 193 | } else { |
| 194 | let name = input.read_null_terminated_slice()?; |
| 195 | Ok(Some(Self::Entry::new( |
| 196 | UnitOffset(offset), |
| 197 | name, |
| 198 | header.unit_offset, |
| 199 | ))) |
| 200 | } |
| 201 | } |
| 202 | } |
| 203 | |