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 | |