1#![deny(missing_docs)]
85#![deny(missing_debug_implementations)]
86
87extern crate failure;
88extern crate parity_wasm;
89
90use parity_wasm::elements::{Deserialize, FuncBody, ImportEntry, Internal, Module, Section,
91 Serialize, VarUint32, VarUint7};
92use std::borrow::Cow;
93use std::collections::HashMap;
94use std::fmt;
95use std::iter;
96use std::io;
97use std::slice;
98use std::str;
99
100#[derive(Clone, Debug)]
102pub struct Options {
103 pub imports: bool,
105
106 pub exports: bool,
108
109 pub privates: bool,
111
112 pub sizes: bool,
114}
115
116impl Default for Options {
117 fn default() -> Options {
118 Options {
119 imports: true,
120 exports: true,
121 privates: true,
122 sizes: false,
123 }
124 }
125}
126
127impl Options {
128 pub fn nothing() -> Options {
130 Options {
131 imports: false,
132 exports: false,
133 privates: false,
134 sizes: false,
135 }
136 }
137}
138
139pub fn symbols<R>(opts: Options, reader: &mut R) -> Result<Symbols, failure::Error>
141where
142 R: io::Read,
143{
144 let module = Module::deserialize(reader)?;
145 Ok(Symbols { opts, module })
146}
147
148pub struct Symbols {
150 opts: Options,
151 module: Module,
152}
153
154impl fmt::Debug for Symbols {
155 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
156 f.debug_struct("Symbols")
157 .field("opts", &self.opts)
158 .field("module", &"...")
159 .finish()
160 }
161}
162
163fn decode_name_map<'a>(
166 mut bytes: &'a [u8],
167 num_imports: usize,
168) -> Result<HashMap<u32, Cow<'a, str>>, failure::Error> {
169 while !bytes.is_empty() {
170 let name_type = u8::from(VarUint7::deserialize(&mut bytes)?);
171 let name_payload_len = u32::from(VarUint32::deserialize(&mut bytes)?);
172 let (these_bytes, rest) = bytes.split_at(name_payload_len as usize);
173
174 if name_type == 1 {
175 bytes = these_bytes;
176 } else {
177 bytes = rest;
178 continue;
179 }
180
181 let count = u32::from(VarUint32::deserialize(&mut bytes)?);
182 let mut names = HashMap::with_capacity(count as usize);
183 for _ in 0..count {
184 let index =
185 u32::from(VarUint32::deserialize(&mut bytes)?).saturating_sub(num_imports as u32);
186 let name_len = u32::from(VarUint32::deserialize(&mut bytes)?);
187 let (name, rest) = bytes.split_at(name_len as usize);
188 bytes = rest;
189 let name = String::from_utf8_lossy(name);
190 names.insert(index, name);
191 }
192 return Ok(names);
193 }
194
195 return Ok(Default::default());
196}
197
198impl Symbols {
199 pub fn iter(&self) -> SymbolsIter {
201 let exports = self.module
203 .export_section()
204 .map_or(HashMap::new(), |section| {
205 section
206 .entries()
207 .iter()
208 .filter_map(|entry| match *entry.internal() {
209 Internal::Function(idx) => Some((idx, entry.field())),
210 _ => None,
211 })
212 .collect()
213 });
214
215 let num_imports = self.module
216 .import_section()
217 .map_or(0, |imports| imports.entries().len());
218
219 let names = self.module
220 .sections()
221 .iter()
222 .filter_map(|section| match *section {
223 Section::Custom(ref custom) if custom.name() == "name" => Some(custom),
224 _ => None,
225 })
226 .next()
227 .and_then(|name_section| decode_name_map(name_section.payload(), num_imports).ok());
228
229 SymbolsIter {
230 symbols: self,
231 state: SymbolsIterState::new(self),
232 exports,
233 names,
234 }
235 }
236}
237
238#[derive(Debug)]
241pub struct SymbolsIter<'a> {
242 symbols: &'a Symbols,
243 state: SymbolsIterState<'a>,
244 exports: HashMap<u32, &'a str>,
245 names: Option<HashMap<u32, Cow<'a, str>>>,
246}
247
248#[derive(Debug)]
249enum SymbolsIterState<'a> {
250 Imports(slice::Iter<'a, ImportEntry>),
251 Functions(iter::Enumerate<slice::Iter<'a, FuncBody>>),
252 Finished,
253}
254
255impl<'a> SymbolsIterState<'a> {
256 fn new(symbols: &'a Symbols) -> SymbolsIterState<'a> {
257 SymbolsIterState::Imports(if let Some(section) = symbols.module.import_section() {
258 section.entries().iter()
259 } else {
260 [].iter()
261 })
262 }
263}
264
265fn function_size(index: usize, module: &Module) -> Option<usize> {
266 module
267 .code_section()
268 .and_then(|section| section.bodies().iter().nth(index))
269 .and_then(|body| {
270 let mut encoded = vec![];
271 if let Err(_) = body.code().clone().serialize(&mut encoded) {
272 return None;
273 }
274 Some(encoded.len())
275 })
276}
277
278impl<'a> Iterator for SymbolsIter<'a> {
279 type Item = Symbol<'a>;
280
281 fn next(&mut self) -> Option<Symbol<'a>> {
282 loop {
283 self.state = match self.state {
284 SymbolsIterState::Finished => return None,
285 SymbolsIterState::Imports(ref mut imports) => match (
286 self.symbols.opts.imports,
287 imports.next(),
288 ) {
289 (true, Some(import)) => {
290 return Some(Symbol::Import {
291 name: import.field(),
292 })
293 }
294 (false, _) | (true, None) => SymbolsIterState::Functions(
295 if let Some(section) = self.symbols.module.code_section() {
296 section.bodies().iter().enumerate()
297 } else {
298 [].iter().enumerate()
299 },
300 ),
301 },
302 SymbolsIterState::Functions(ref mut functions) => {
303 let (i, function) = match functions.next() {
304 Some(next) => next,
305 _ => break,
306 };
307 match (i, function, self.exports.get(&(i as u32))) {
308 (i, _, Some(export)) if self.symbols.opts.exports => {
309 return Some(Symbol::Export {
310 name: export,
311 size: if self.symbols.opts.sizes {
312 function_size(i, &self.symbols.module)
313 } else {
314 None
315 },
316 });
317 }
318 (i, _function, None) if self.symbols.opts.privates => {
319 let i = i as u32;
320 let name = self.names.as_ref().and_then(|names| names.get(&i).cloned());
321 return Some(Symbol::Private {
322 index: i,
323 name,
324 size: if self.symbols.opts.sizes {
325 function_size(i as usize, &self.symbols.module)
326 } else {
327 None
328 },
329 });
330 }
331 _ => {
332 continue;
333 }
334 }
335 }
336 };
337 }
338
339 self.state = SymbolsIterState::Finished;
340 None
341 }
342}
343
344#[derive(Clone, Debug)]
346pub enum Symbol<'a> {
347 Import {
349 name: &'a str,
351 },
352
353 Export {
355 name: &'a str,
357 size: Option<usize>,
359 },
360
361 Private {
363 index: u32,
365 name: Option<Cow<'a, str>>,
367 size: Option<usize>,
369 },
370}
371
372impl<'a> fmt::Display for Symbol<'a> {
373 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
374 match *self {
375 Symbol::Import { name } | Symbol::Export { name, .. } => f.write_str(name),
376 Symbol::Private {
377 name: Some(ref name),
378 ..
379 } => f.write_str(&name),
380 Symbol::Private { index, .. } => write!(f, "function[{}]", index),
381 }
382 }
383}