wasmparser/
readers.rs

1/* Copyright 2018 Mozilla Foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16use crate::{BinaryReader, BinaryReaderError, Result};
17use ::core::fmt;
18use ::core::marker;
19use ::core::ops::Range;
20
21mod component;
22mod core;
23
24pub use self::component::*;
25pub use self::core::*;
26
27/// A trait implemented for items that can be decoded directly from a
28/// `BinaryReader`, or that which can be parsed from the WebAssembly binary
29/// format.
30///
31/// Note that this is also accessible as a [`BinaryReader::read`] method.
32pub trait FromReader<'a>: Sized {
33    /// Attempts to read `Self` from the provided binary reader, returning an
34    /// error if it is unable to do so.
35    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self>;
36}
37
38impl<'a> FromReader<'a> for u32 {
39    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
40        reader.read_var_u32()
41    }
42}
43
44impl<'a> FromReader<'a> for &'a str {
45    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
46        reader.read_string()
47    }
48}
49
50impl<'a, T, U> FromReader<'a> for (T, U)
51where
52    T: FromReader<'a>,
53    U: FromReader<'a>,
54{
55    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
56        Ok((reader.read()?, reader.read()?))
57    }
58}
59
60/// A generic structure for reading a section of a WebAssembly binary which has
61/// a limited number of items within it.
62///
63/// Many WebAssembly sections are a count of items followed by that many items.
64/// This helper structure can be used to parse these sections and provides
65/// an iteration-based API for reading the contents.
66///
67/// Note that this always implements the [`Clone`] trait to represent the
68/// ability to parse the section multiple times.
69pub struct SectionLimited<'a, T> {
70    reader: BinaryReader<'a>,
71    count: u32,
72    _marker: marker::PhantomData<T>,
73}
74
75impl<'a, T> SectionLimited<'a, T> {
76    /// Creates a new section reader from the provided contents.
77    ///
78    /// The `data` provided here is the data of the section itself that will be
79    /// parsed. The `offset` argument is the byte offset, in the original wasm
80    /// binary, that the section was found. The `offset` argument is used
81    /// for error reporting.
82    ///
83    /// # Errors
84    ///
85    /// Returns an error if a 32-bit count couldn't be read from the `data`.
86    pub fn new(mut reader: BinaryReader<'a>) -> Result<Self> {
87        let count = reader.read_var_u32()?;
88        Ok(SectionLimited {
89            reader,
90            count,
91            _marker: marker::PhantomData,
92        })
93    }
94
95    /// Returns the count of total items within this section.
96    pub fn count(&self) -> u32 {
97        self.count
98    }
99
100    /// Returns whether the original byte offset of this section.
101    pub fn original_position(&self) -> usize {
102        self.reader.original_position()
103    }
104
105    /// Returns the range, as byte offsets, of this section within the original
106    /// wasm binary.
107    pub fn range(&self) -> Range<usize> {
108        self.reader.range()
109    }
110
111    /// Returns an iterator which yields not only each item in this section but
112    /// additionally the offset of each item within the section.
113    pub fn into_iter_with_offsets(self) -> SectionLimitedIntoIterWithOffsets<'a, T>
114    where
115        T: FromReader<'a>,
116    {
117        SectionLimitedIntoIterWithOffsets {
118            iter: self.into_iter(),
119        }
120    }
121}
122
123impl<T> Clone for SectionLimited<'_, T> {
124    fn clone(&self) -> Self {
125        SectionLimited {
126            reader: self.reader.clone(),
127            count: self.count,
128            _marker: self._marker,
129        }
130    }
131}
132
133impl<T> fmt::Debug for SectionLimited<'_, T> {
134    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135        f.debug_struct("SectionLimited")
136            .field("count", &self.count)
137            .field("range", &self.range())
138            .finish()
139    }
140}
141
142impl<'a, T> IntoIterator for SectionLimited<'a, T>
143where
144    T: FromReader<'a>,
145{
146    type Item = Result<T>;
147    type IntoIter = SectionLimitedIntoIter<'a, T>;
148
149    fn into_iter(self) -> Self::IntoIter {
150        SectionLimitedIntoIter {
151            remaining: self.count,
152            section: self,
153            end: false,
154        }
155    }
156}
157
158/// A consuming iterator of a [`SectionLimited`].
159///
160/// This is created via the [`IntoIterator`] `impl` for the [`SectionLimited`]
161/// type.
162pub struct SectionLimitedIntoIter<'a, T> {
163    section: SectionLimited<'a, T>,
164    remaining: u32,
165    end: bool,
166}
167
168impl<T> SectionLimitedIntoIter<'_, T> {
169    /// Returns the current byte offset of the section within this iterator.
170    pub fn original_position(&self) -> usize {
171        self.section.reader.original_position()
172    }
173}
174
175impl<'a, T> Iterator for SectionLimitedIntoIter<'a, T>
176where
177    T: FromReader<'a>,
178{
179    type Item = Result<T>;
180
181    fn next(&mut self) -> Option<Result<T>> {
182        if self.end {
183            return None;
184        }
185        if self.remaining == 0 {
186            self.end = true;
187            if self.section.reader.eof() {
188                return None;
189            }
190            return Some(Err(BinaryReaderError::new(
191                "section size mismatch: unexpected data at the end of the section",
192                self.section.reader.original_position(),
193            )));
194        }
195        let result = self.section.reader.read();
196        self.end = result.is_err();
197        self.remaining -= 1;
198        Some(result)
199    }
200
201    fn size_hint(&self) -> (usize, Option<usize>) {
202        let remaining = self.remaining as usize;
203        (remaining, Some(remaining))
204    }
205}
206
207impl<'a, T> ExactSizeIterator for SectionLimitedIntoIter<'a, T> where T: FromReader<'a> {}
208
209/// An iterator over a limited section iterator.
210pub struct SectionLimitedIntoIterWithOffsets<'a, T> {
211    iter: SectionLimitedIntoIter<'a, T>,
212}
213
214impl<'a, T> Iterator for SectionLimitedIntoIterWithOffsets<'a, T>
215where
216    T: FromReader<'a>,
217{
218    type Item = Result<(usize, T)>;
219
220    fn next(&mut self) -> Option<Self::Item> {
221        let pos = self.iter.section.reader.original_position();
222        Some(self.iter.next()?.map(|item| (pos, item)))
223    }
224
225    fn size_hint(&self) -> (usize, Option<usize>) {
226        self.iter.size_hint()
227    }
228}
229
230impl<'a, T> ExactSizeIterator for SectionLimitedIntoIterWithOffsets<'a, T> where T: FromReader<'a> {}
231
232/// A trait implemented for subsections of another outer section.
233///
234/// This is currently only used for subsections within custom sections, such as
235/// the `name` section of core wasm.
236///
237/// This is used in conjunction with [`Subsections`].
238pub trait Subsection<'a>: Sized {
239    /// Converts the section identifier provided with the section contents into
240    /// a typed section
241    fn from_reader(id: u8, reader: BinaryReader<'a>) -> Result<Self>;
242}
243
244/// Iterator/reader over the contents of a section which is composed of
245/// subsections.
246///
247/// This reader is used for the core `name` section, for example. This type
248/// primarily implements [`Iterator`] for advancing through the sections.
249pub struct Subsections<'a, T> {
250    reader: BinaryReader<'a>,
251    _marker: marker::PhantomData<T>,
252}
253
254impl<'a, T> Subsections<'a, T> {
255    /// Creates a new reader for the specified section contents starting at
256    /// `offset` within the original wasm file.
257    pub fn new(reader: BinaryReader<'a>) -> Self {
258        Subsections {
259            reader,
260            _marker: marker::PhantomData,
261        }
262    }
263
264    /// Returns whether the original byte offset of this section.
265    pub fn original_position(&self) -> usize {
266        self.reader.original_position()
267    }
268
269    /// Returns the range, as byte offsets, of this section within the original
270    /// wasm binary.
271    pub fn range(&self) -> Range<usize> {
272        self.reader.range()
273    }
274
275    fn read(&mut self) -> Result<T>
276    where
277        T: Subsection<'a>,
278    {
279        let subsection_id = self.reader.read_u7()?;
280        let reader = self.reader.read_reader()?;
281        T::from_reader(subsection_id, reader)
282    }
283}
284
285impl<T> Clone for Subsections<'_, T> {
286    fn clone(&self) -> Self {
287        Subsections {
288            reader: self.reader.clone(),
289            _marker: self._marker,
290        }
291    }
292}
293
294impl<T> fmt::Debug for Subsections<'_, T> {
295    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
296        f.debug_struct("Subsections")
297            .field("range", &self.range())
298            .finish()
299    }
300}
301
302impl<'a, T> Iterator for Subsections<'a, T>
303where
304    T: Subsection<'a>,
305{
306    type Item = Result<T>;
307
308    fn next(&mut self) -> Option<Result<T>> {
309        if self.reader.eof() {
310            None
311        } else {
312            Some(self.read())
313        }
314    }
315}