]>
Commit | Line | Data |
---|---|---|
f035d41b XL |
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 | } |