├── .gitattributes ├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── Cargo.toml ├── README.md ├── src ├── bin │ └── wasm-nm.rs └── lib.rs └── tests ├── README.md ├── hello-dash-i.expected ├── hello.expected ├── hello.rs ├── hello.wasm ├── small-hello-dash-e.expected ├── small-hello-dash-j.expected ├── small-hello.expected ├── small-hello.wasm └── tests.rs /.gitattributes: -------------------------------------------------------------------------------- 1 | README.md -diff -merge 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target/ 3 | **/*.rs.bk 4 | Cargo.lock 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | 3 | cache: cargo 4 | 5 | before_script: 6 | - cargo install -f cargo-readme 7 | 8 | rust: 9 | - stable 10 | - beta 11 | - nightly 12 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to `wasm-nm` 2 | 3 | Hi! We'd love to have your contributions! If you want help or mentorship, reach 4 | out to us in a GitHub issue, or ping `fitzgen` 5 | in [#rust on irc.mozilla.org](irc://irc.mozilla.org#rust) and introduce 6 | yourself. 7 | 8 | 9 | 10 | 11 | 12 | - [Code of Conduct](#code-of-conduct) 13 | - [Building](#building) 14 | - [Testing](#testing) 15 | - [Automatic code formatting](#automatic-code-formatting) 16 | 17 | 18 | 19 | ## Code of Conduct 20 | 21 | We abide by the [Rust Code of Conduct][coc] and ask that you do as well. 22 | 23 | [coc]: https://www.rust-lang.org/en-US/conduct.html 24 | 25 | ## Building 26 | 27 | ``` 28 | $ cargo build 29 | ``` 30 | 31 | ## Testing 32 | 33 | The tests require `cargo-readme` to be installed: 34 | ``` 35 | $ cargo install cargo-readme 36 | ``` 37 | 38 | To run all the tests: 39 | 40 | ``` 41 | $ cargo test 42 | ``` 43 | 44 | ## Automatic code formatting 45 | 46 | We use [`rustfmt`](https://github.com/rust-lang-nursery/rustfmt) to enforce a 47 | consistent code style across the whole code base. 48 | 49 | You can install the latest version of `rustfmt` with this command: 50 | 51 | ``` 52 | $ rustup update nightly 53 | $ cargo install -f rustfmt-nightly 54 | ``` 55 | 56 | Ensure that `~/.cargo/bin` is on your path. 57 | 58 | Once that is taken care of, you can (re)format all code by running this command: 59 | 60 | ``` 61 | $ cargo fmt 62 | ``` 63 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Nick Fitzgerald "] 3 | description = "Print the symbols that are imported in and exported from a wasm file." 4 | keywords = ["symbol", "wasm", "nm"] 5 | license = "Apache-2.0/MIT" 6 | name = "wasm-nm" 7 | readme = "./README.md" 8 | repository = "https://github.com/fitzgen/wasm-nm" 9 | version = "0.2.1" 10 | 11 | [[bin]] 12 | doc = false 13 | name = "wasm-nm" 14 | path = "src/bin/wasm-nm.rs" 15 | required-features = ["exe"] 16 | 17 | [dependencies] 18 | failure = "0.1.1" 19 | parity-wasm = "0.19.0" 20 | 21 | [dependencies.clap] 22 | optional = true 23 | version = "2.29.0" 24 | 25 | [features] 26 | default = ["exe"] 27 | exe = ["clap"] 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wasm-nm 2 | 3 | [![](https://docs.rs/wasm-nm/badge.svg)](https://docs.rs/wasm-nm/) [![](https://img.shields.io/crates/v/wasm-nm.svg)](https://crates.io/crates/wasm-nm) [![](https://img.shields.io/crates/d/wasm-nm.png)](https://crates.io/crates/wasm-nm) [![Build Status](https://travis-ci.org/fitzgen/wasm-nm.png?branch=master)](https://travis-ci.org/fitzgen/wasm-nm) 4 | 5 | List the symbols within a wasm file. 6 | 7 | * [Library](#library) 8 | * [Executable](#executable) 9 | * [License](#license) 10 | * [Contributing](#contributing) 11 | 12 | ### Executable 13 | 14 | To install the `wasm-nm` executable, run 15 | 16 | ``` 17 | $ cargo install wasm-nm 18 | ``` 19 | 20 | For information on using the `wasm-nm` executable, run 21 | 22 | ``` 23 | $ wasm-nm --help 24 | ``` 25 | 26 | #### Using `wasm-nm` as a Size Profiler 27 | 28 | `wasm-nm` can function as a rudimentary size profiler for `.wasm` files. 29 | 30 | The `-z` option enables printing a function's code size. The unix `sort` utility 31 | can be used to sort the symbols by size. The `rustfilt` utility can be used to 32 | demangle Rust symbols (`cargo install rustfilt`). 33 | 34 | ``` 35 | $ wasm-nm -z path/to/something.wasm | sort -n -u -r | rustfilt | head 36 | 3578 p dlmalloc::dlmalloc::Dlmalloc::malloc::hb37c2fafc9847520 37 | 3307 e quicksilver 38 | 1427 p ::fmt::h0cf4ea19d7121472 39 | 1287 p std::panicking::rust_panic_with_hook::h52b2005910c55f47 40 | 1268 p core::fmt::Formatter::pad::hdb2be9f507201bd1 41 | 1248 p core::str::slice_error_fail::h09ffe3974e261c49 42 | 1064 p core::fmt::write::h914fcaafc6fb200a 43 | 987 p core::fmt::Formatter::pad_integral::h2f2f83d99c318b28 44 | 945 p <&'a T as core::fmt::Debug>::fmt::h4a5a01d440d30f67 45 | 918 p dlmalloc::dlmalloc::Dlmalloc::free::h8185738df2a87b48 46 | ``` 47 | 48 | ### Library 49 | 50 | To use `wasm-nm` as a library, add this to your `Cargo.toml`: 51 | 52 | ```toml 53 | [dependencies.wasm-nm] 54 | # Do not build the executable. 55 | default-features = false 56 | ``` 57 | 58 | See [docs.rs/wasm-nm][docs] for API documentation. 59 | 60 | [docs]: https://docs.rs/wasm-nm 61 | 62 | ### License 63 | 64 | Licensed under either of 65 | 66 | * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 67 | 68 | * [MIT license](http://opensource.org/licenses/MIT) 69 | 70 | at your option. 71 | 72 | ### Contributing 73 | 74 | See 75 | [CONTRIBUTING.md](https://github.com/fitzgen/wasm-nm/blob/master/CONTRIBUTING.md) 76 | for hacking. 77 | 78 | Unless you explicitly state otherwise, any contribution intentionally submitted 79 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 80 | dual licensed as above, without any additional terms or conditions. 81 | 82 | 83 | License: Apache-2.0/MIT 84 | -------------------------------------------------------------------------------- /src/bin/wasm-nm.rs: -------------------------------------------------------------------------------- 1 | extern crate clap; 2 | extern crate failure; 3 | extern crate wasm_nm; 4 | 5 | use std::fs; 6 | use std::io; 7 | use std::process; 8 | 9 | fn main() { 10 | if let Err(()) = try_main() { 11 | process::exit(1) 12 | } 13 | } 14 | 15 | fn try_main() -> Result<(), ()> { 16 | let matches = parse_args(); 17 | 18 | let mut opts = wasm_nm::Options::default(); 19 | 20 | if matches.is_present("only_imports") { 21 | opts = wasm_nm::Options::nothing(); 22 | opts.imports = true; 23 | } else if matches.is_present("only_exports") { 24 | opts = wasm_nm::Options::nothing(); 25 | opts.exports = true; 26 | } else if matches.is_present("only_privates") { 27 | opts = wasm_nm::Options::nothing(); 28 | opts.privates = true; 29 | } 30 | 31 | if matches.is_present("sizes") { 32 | opts.sizes = true; 33 | } 34 | 35 | let mut any_errors = false; 36 | for path in matches.values_of("file").unwrap() { 37 | if let Err(e) = print_symbols_in_one(path, opts.clone(), &matches) { 38 | eprintln!("error: {}: {}", path, e); 39 | any_errors = true; 40 | } 41 | } 42 | 43 | if any_errors { 44 | Err(()) 45 | } else { 46 | Ok(()) 47 | } 48 | } 49 | 50 | fn print_symbols_in_one( 51 | path: &str, 52 | opts: wasm_nm::Options, 53 | matches: &clap::ArgMatches<'static>, 54 | ) -> Result<(), failure::Error> { 55 | let file = fs::File::open(path)?; 56 | let mut file = io::BufReader::new(file); 57 | 58 | let print_sizes = opts.sizes; 59 | let symbols = wasm_nm::symbols(opts, &mut file)?; 60 | 61 | let just_symbols = matches.is_present("just_symbols"); 62 | for sym in symbols.iter() { 63 | if print_sizes { 64 | match sym { 65 | wasm_nm::Symbol::Import { .. } => print!("0 "), 66 | wasm_nm::Symbol::Export { size, .. } | wasm_nm::Symbol::Private { size, .. } => { 67 | print!("{} ", size.unwrap_or(0)) 68 | } 69 | } 70 | } 71 | if !just_symbols { 72 | match sym { 73 | wasm_nm::Symbol::Import { .. } => print!("i "), 74 | wasm_nm::Symbol::Export { .. } => print!("e "), 75 | wasm_nm::Symbol::Private { .. } => print!("p "), 76 | } 77 | } 78 | println!("{}", sym); 79 | } 80 | 81 | Ok(()) 82 | } 83 | 84 | fn parse_args() -> clap::ArgMatches<'static> { 85 | clap::App::new(env!("CARGO_PKG_NAME")) 86 | .version(env!("CARGO_PKG_VERSION")) 87 | .author(env!("CARGO_PKG_AUTHORS")) 88 | .about(env!("CARGO_PKG_DESCRIPTION")) 89 | .long_about( 90 | "\ 91 | wasm-nm displays imported and exported symbols in a wasm file. 92 | 93 | Each symbol is preceded by its symbol type: \"i\" for imported symbols, \"e\" 94 | for exported symbols, and \"p\" for private symbols. Alternatively, the -j flag 95 | can be used to avoid any prefixes. 96 | ", 97 | ) 98 | .arg( 99 | clap::Arg::with_name("file") 100 | .required(true) 101 | .multiple(true) 102 | .help("The wasm file(s) whose symbols should be dumped."), 103 | ) 104 | .arg( 105 | clap::Arg::with_name("just_symbols") 106 | .short("j") 107 | .help("Just display the symbol names (no type)."), 108 | ) 109 | .arg( 110 | clap::Arg::with_name("sizes") 111 | .short("z") 112 | .help("Display symbol size (in bytes)."), 113 | ) 114 | .arg( 115 | clap::Arg::with_name("only_imports") 116 | .short("i") 117 | .conflicts_with("only_exports") 118 | .conflicts_with("only_privates") 119 | .help("Display only import symbols."), 120 | ) 121 | .arg( 122 | clap::Arg::with_name("no_imports") 123 | .short("I") 124 | .conflicts_with("only_imports") 125 | .help("Do not display import symbols."), 126 | ) 127 | .arg( 128 | clap::Arg::with_name("only_exports") 129 | .short("e") 130 | .conflicts_with("only_imports") 131 | .conflicts_with("only_privates") 132 | .help("Display only export symbols."), 133 | ) 134 | .arg( 135 | clap::Arg::with_name("no_exports") 136 | .short("E") 137 | .conflicts_with("only_exports") 138 | .help("Do not display export symbols."), 139 | ) 140 | .arg( 141 | clap::Arg::with_name("only_privates") 142 | .short("p") 143 | .conflicts_with("only_exports") 144 | .conflicts_with("only_imports") 145 | .help("Display only private symbols."), 146 | ) 147 | .arg( 148 | clap::Arg::with_name("no_privates") 149 | .short("P") 150 | .conflicts_with("only_privates") 151 | .help("Do not display private symbols."), 152 | ) 153 | .get_matches() 154 | } 155 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | 3 | [![](https://docs.rs/wasm-nm/badge.svg)](https://docs.rs/wasm-nm/) [![](https://img.shields.io/crates/v/wasm-nm.svg)](https://crates.io/crates/wasm-nm) [![](https://img.shields.io/crates/d/wasm-nm.png)](https://crates.io/crates/wasm-nm) [![Build Status](https://travis-ci.org/fitzgen/wasm-nm.png?branch=master)](https://travis-ci.org/fitzgen/wasm-nm) 4 | 5 | List the symbols within a wasm file. 6 | 7 | * [Library](#library) 8 | * [Executable](#executable) 9 | * [License](#license) 10 | * [Contributing](#contributing) 11 | 12 | ## Executable 13 | 14 | To install the `wasm-nm` executable, run 15 | 16 | ```text 17 | $ cargo install wasm-nm 18 | ``` 19 | 20 | For information on using the `wasm-nm` executable, run 21 | 22 | ```text 23 | $ wasm-nm --help 24 | ``` 25 | 26 | ### Using `wasm-nm` as a Size Profiler 27 | 28 | `wasm-nm` can function as a rudimentary size profiler for `.wasm` files. 29 | 30 | The `-z` option enables printing a function's code size. The unix `sort` utility 31 | can be used to sort the symbols by size. The `rustfilt` utility can be used to 32 | demangle Rust symbols (`cargo install rustfilt`). 33 | 34 | ```text 35 | $ wasm-nm -z path/to/something.wasm | sort -n -u -r | rustfilt | head 36 | 3578 p dlmalloc::dlmalloc::Dlmalloc::malloc::hb37c2fafc9847520 37 | 3307 e quicksilver 38 | 1427 p ::fmt::h0cf4ea19d7121472 39 | 1287 p std::panicking::rust_panic_with_hook::h52b2005910c55f47 40 | 1268 p core::fmt::Formatter::pad::hdb2be9f507201bd1 41 | 1248 p core::str::slice_error_fail::h09ffe3974e261c49 42 | 1064 p core::fmt::write::h914fcaafc6fb200a 43 | 987 p core::fmt::Formatter::pad_integral::h2f2f83d99c318b28 44 | 945 p <&'a T as core::fmt::Debug>::fmt::h4a5a01d440d30f67 45 | 918 p dlmalloc::dlmalloc::Dlmalloc::free::h8185738df2a87b48 46 | ``` 47 | 48 | ## Library 49 | 50 | To use `wasm-nm` as a library, add this to your `Cargo.toml`: 51 | 52 | ```toml 53 | [dependencies.wasm-nm] 54 | # Do not build the executable. 55 | default-features = false 56 | ``` 57 | 58 | See [docs.rs/wasm-nm][docs] for API documentation. 59 | 60 | [docs]: https://docs.rs/wasm-nm 61 | 62 | ## License 63 | 64 | Licensed under either of 65 | 66 | * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 67 | 68 | * [MIT license](http://opensource.org/licenses/MIT) 69 | 70 | at your option. 71 | 72 | ## Contributing 73 | 74 | See 75 | [CONTRIBUTING.md](https://github.com/fitzgen/wasm-nm/blob/master/CONTRIBUTING.md) 76 | for hacking. 77 | 78 | Unless you explicitly state otherwise, any contribution intentionally submitted 79 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 80 | dual licensed as above, without any additional terms or conditions. 81 | 82 | */ 83 | 84 | #![deny(missing_docs)] 85 | #![deny(missing_debug_implementations)] 86 | 87 | extern crate failure; 88 | extern crate parity_wasm; 89 | 90 | use parity_wasm::elements::{Deserialize, FuncBody, ImportEntry, Internal, Module, Section, 91 | Serialize, VarUint32, VarUint7}; 92 | use std::borrow::Cow; 93 | use std::collections::HashMap; 94 | use std::fmt; 95 | use std::iter; 96 | use std::io; 97 | use std::slice; 98 | use std::str; 99 | 100 | /// Options for controlling which symbols are iterated over. 101 | #[derive(Clone, Debug)] 102 | pub struct Options { 103 | /// Should imported symbols be iterated over? 104 | pub imports: bool, 105 | 106 | /// Should exported symbols be iterated over? 107 | pub exports: bool, 108 | 109 | /// Should private symbols be iterated over? 110 | pub privates: bool, 111 | 112 | /// Should the symbols' sizes be computed? 113 | pub sizes: bool, 114 | } 115 | 116 | impl 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 | 127 | impl Options { 128 | /// Construct options for iterating over *none* of the symbol kinds. 129 | pub fn nothing() -> Options { 130 | Options { 131 | imports: false, 132 | exports: false, 133 | privates: false, 134 | sizes: false, 135 | } 136 | } 137 | } 138 | 139 | /// Get the symbols in the given wasm file. 140 | pub fn symbols(opts: Options, reader: &mut R) -> Result 141 | where 142 | R: io::Read, 143 | { 144 | let module = Module::deserialize(reader)?; 145 | Ok(Symbols { opts, module }) 146 | } 147 | 148 | /// The set of symbols in a wasm file. 149 | pub struct Symbols { 150 | opts: Options, 151 | module: Module, 152 | } 153 | 154 | impl 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 | 163 | // Cribbed from wasm-gc; waiting for the name section support to be upstreamed 164 | // into parity-wasm. 165 | fn decode_name_map<'a>( 166 | mut bytes: &'a [u8], 167 | num_imports: usize, 168 | ) -> Result>, 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 | 198 | impl Symbols { 199 | /// Iterate over the symbols. 200 | pub fn iter(&self) -> SymbolsIter { 201 | // Find the set of function indices that are exported. 202 | 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 | /// An iterator returned by `Symbols::iter`, which iterates over the symbols in 239 | /// a wasm file. 240 | #[derive(Debug)] 241 | pub struct SymbolsIter<'a> { 242 | symbols: &'a Symbols, 243 | state: SymbolsIterState<'a>, 244 | exports: HashMap, 245 | names: Option>>, 246 | } 247 | 248 | #[derive(Debug)] 249 | enum SymbolsIterState<'a> { 250 | Imports(slice::Iter<'a, ImportEntry>), 251 | Functions(iter::Enumerate>), 252 | Finished, 253 | } 254 | 255 | impl<'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 | 265 | fn function_size(index: usize, module: &Module) -> Option { 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 | 278 | impl<'a> Iterator for SymbolsIter<'a> { 279 | type Item = Symbol<'a>; 280 | 281 | fn next(&mut self) -> Option> { 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 | /// A symbol from a wasm file. 345 | #[derive(Clone, Debug)] 346 | pub enum Symbol<'a> { 347 | /// An imported symbol. 348 | Import { 349 | /// The symbol's name. 350 | name: &'a str, 351 | }, 352 | 353 | /// An exported symbol. 354 | Export { 355 | /// The symbol's name. 356 | name: &'a str, 357 | /// The symbol's size, if available. 358 | size: Option, 359 | }, 360 | 361 | /// A private function that is not exported. 362 | Private { 363 | /// The function table index for this private function. 364 | index: u32, 365 | /// The name from the name section, if that information exists. 366 | name: Option>, 367 | /// The symbol's size, if available. 368 | size: Option, 369 | }, 370 | } 371 | 372 | impl<'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 | } 384 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | To regenerate the wasm files: 2 | 3 | ``` 4 | $ rustc +nightly --target wasm32-unknown-unknown -O -g ./hello.rs 5 | $ wasm-gc hello.wasm small-hello.wasm 6 | ``` 7 | -------------------------------------------------------------------------------- /tests/hello-dash-i.expected: -------------------------------------------------------------------------------- 1 | i imported 2 | -------------------------------------------------------------------------------- /tests/hello.expected: -------------------------------------------------------------------------------- 1 | i imported 2 | p _ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h4a005ebb0fff14ceE 3 | p _ZN4core3ops8function6FnOnce9call_once17hfec8c71b0834a396E 4 | p _ZN4core3ptr13drop_in_place17haec76f9ee14b5e35E 5 | p _ZN33_$LT$alloc..vec..Vec$LT$T$GT$$GT$13reserve_exact17h12cd11688004ca4bE 6 | p _ZN33_$LT$alloc..vec..Vec$LT$T$GT$$GT$13shrink_to_fit17hab6a6becd91a127fE 7 | p _ZN33_$LT$alloc..vec..Vec$LT$T$GT$$GT$17extend_from_slice17h55be1b9e3931382fE 8 | p _ZN49_$LT$alloc..raw_vec..RawVec$LT$T$C$$u20$A$GT$$GT$6double17hcb678cb3bee53ad7E 9 | p _ZN53_$LT$$RF$$u27$a$u20$T$u20$as$u20$core..fmt..Debug$GT$3fmt17h4a5a01d440d30f67E 10 | p _ZN3std10sys_common11at_exit_imp7cleanup17h3cbcee67c7d8b406E 11 | p _ZN3std10sys_common11thread_info11THREAD_INFO7__getit17h5520c8a621a7d891E 12 | p _ZN3std10sys_common12thread_local9StaticKey9lazy_init17h0e26fad736fa74a6E 13 | p _ZN4core6result13unwrap_failed17h0cf9629bbd9645feE 14 | p _ZN4core6result13unwrap_failed17h1db66428c6b7f087E 15 | p _ZN4core6result13unwrap_failed17haeeb2813da2027baE 16 | p _ZN4core6result13unwrap_failed17hbd0e0d830f79de1aE 17 | p _ZN4core6result13unwrap_failed17hec2c782fbf0c355cE 18 | p _ZN3std5error5Error5cause17h70c0e8f8d884244eE 19 | p _ZN3std5error5Error7type_id17h0597eb3374c8b596E 20 | p _ZN281_$LT$std..error..$LT$impl$u20$core..convert..From$LT$alloc..string..String$GT$$u20$for$u20$alloc..boxed..Box$LT$std..error..Error$u20$$u2b$$u20$core..marker..Sync$u20$$u2b$$u20$core..marker..Send$u20$$u2b$$u20$$u27$static$GT$$GT$..from..StringError$u20$as$u20$std..error..Error$GT$11description17heae9827b7cd47142E 21 | p _ZN282_$LT$std..error..$LT$impl$u20$core..convert..From$LT$alloc..string..String$GT$$u20$for$u20$alloc..boxed..Box$LT$std..error..Error$u20$$u2b$$u20$core..marker..Sync$u20$$u2b$$u20$core..marker..Send$u20$$u2b$$u20$$u27$static$GT$$GT$..from..StringError$u20$as$u20$core..fmt..Display$GT$3fmt17h4b11ad51403e1489E 22 | p _ZN3std2io5Write9write_all17h1e22c345ee74bd20E 23 | p _ZN3std2io5Write9write_fmt17he1152d8bae99d65bE 24 | p _ZN4core3ptr13drop_in_place17h2bdbaf674f0aee8fE 25 | p _ZN280_$LT$std..error..$LT$impl$u20$core..convert..From$LT$alloc..string..String$GT$$u20$for$u20$alloc..boxed..Box$LT$std..error..Error$u20$$u2b$$u20$core..marker..Sync$u20$$u2b$$u20$core..marker..Send$u20$$u2b$$u20$$u27$static$GT$$GT$..from..StringError$u20$as$u20$core..fmt..Debug$GT$3fmt17h710025ce6ce2de1fE 26 | p _ZN4core3ptr13drop_in_place17h65247ce7e4709129E 27 | p _ZN4core3fmt5Write10write_char17hb47c60d960f24025E 28 | p _ZN4core3fmt5Write9write_fmt17hd6115c3c6bf97ff1E 29 | p _ZN4core3ptr13drop_in_place17hcd2d108484489df3E 30 | p _ZN94_$LT$std..io..Write..write_fmt..Adaptor$LT$$u27$a$C$$u20$T$GT$$u20$as$u20$core..fmt..Write$GT$9write_str17hfb203f95b9e34b22E 31 | p _ZN4core3ptr13drop_in_place17h8f35c23f76abee51E 32 | p _ZN3std2io5error5Error3new17h381dae13d0f2cf0dE 33 | p _ZN33_$LT$alloc..arc..Arc$LT$T$GT$$GT$9drop_slow17h933c0bf4db588528E 34 | p _ZN36_$LT$T$u20$as$u20$core..any..Any$GT$11get_type_id17hcf276e0529accfd4E 35 | p _ZN4core3fmt5Write9write_fmt17hf94ca4b41923d8fbE 36 | p _ZN4core3ptr13drop_in_place17ha05a3a5b67481aadE 37 | p _ZN53_$LT$$RF$$u27$a$u20$T$u20$as$u20$core..fmt..Debug$GT$3fmt17h14a99863a6b1c9daE 38 | p _ZN3std6thread6Thread3new17h84c5176c2b27bd8aE 39 | p _ZN62_$LT$std..ffi..c_str..NulError$u20$as$u20$core..fmt..Debug$GT$3fmt17hebab1e70554ff965E 40 | p _ZN4core3ptr13drop_in_place17h9caabe1a35ed262cE 41 | p _ZN4core3ptr13drop_in_place17heb39250dd62cb94bE 42 | p _ZN3std6thread5local2os13destroy_value17h742a7e47335460b8E 43 | p _ZN3std6thread5local2os13destroy_value17hb42727554f684767E 44 | p _ZN3std6thread5local2os13destroy_value17hc4fcd9b61f79c3b7E 45 | p _ZN3std10sys_common9backtrace28__rust_begin_short_backtrace17hb9f3968452a7d8dbE 46 | p _ZN82_$LT$std..sys_common..poison..PoisonError$LT$T$GT$$u20$as$u20$core..fmt..Debug$GT$3fmt17h9ca8a5a1dc3f81beE 47 | p _ZN3std10sys_common6memchr8fallback6memchr17hb120b04790bd1299E 48 | p _ZN3std10sys_common4util10dumb_print17hd5898bb2eda1120aE 49 | p _ZN3std9panicking11begin_panic17hdbf9a3586ca2db9bE 50 | p _ZN3std9panicking20rust_panic_with_hook17h52b2005910c55f47E 51 | p _ZN3std9panicking12default_hook28_$u7b$$u7b$closure$u7d$$u7d$17h02c960b6aa5cdc20E 52 | p _ZN4core3ptr13drop_in_place17h47ff60385eded4a9E 53 | p _ZN3std2io5impls69_$LT$impl$u20$std..io..Write$u20$for$u20$$RF$$u27$a$u20$mut$u20$W$GT$5write17h624a99b6a307d797E 54 | p _ZN3std2io5impls69_$LT$impl$u20$std..io..Write$u20$for$u20$$RF$$u27$a$u20$mut$u20$W$GT$5flush17hc3482b034a6a4db7E 55 | p _ZN3std2io5impls69_$LT$impl$u20$std..io..Write$u20$for$u20$$RF$$u27$a$u20$mut$u20$W$GT$9write_all17h91b04ea836f43923E 56 | p _ZN3std2io5impls69_$LT$impl$u20$std..io..Write$u20$for$u20$$RF$$u27$a$u20$mut$u20$W$GT$9write_fmt17h52f014db65414dc6E 57 | p _ZN3std9panicking12LOCAL_STDERR7__getit17ha4b201e512ab3c66E 58 | p _ZN4core3ptr13drop_in_place17h87473f3cb67ee6ecE 59 | p _ZN36_$LT$T$u20$as$u20$core..any..Any$GT$11get_type_id17hba485be8a12c6119E 60 | p _ZN3std9panicking18update_panic_count11PANIC_COUNT7__getit17h4ec790dd4d7f8dcfE 61 | p _ZN3std9panicking15begin_panic_fmt17h47786a9a66db0de4E 62 | p _ZN3std9panicking11begin_panic17h1edc0d1d8a3585ffE 63 | p _ZN4core3ptr13drop_in_place17h9f6f00b5724f00f3E.899 64 | p _ZN53_$LT$$RF$$u27$a$u20$T$u20$as$u20$core..fmt..Debug$GT$3fmt17h2a3f4d7a59ce4687E 65 | p _ZN55_$LT$$RF$$u27$a$u20$T$u20$as$u20$core..fmt..Display$GT$3fmt17he00d690ee0dec7e2E 66 | p _ZN96_$LT$core..fmt..Write..write_fmt..Adapter$LT$$u27$a$C$$u20$T$GT$$u20$as$u20$core..fmt..Write$GT$10write_char17hc94f70c97a18b983E 67 | p _ZN96_$LT$core..fmt..Write..write_fmt..Adapter$LT$$u27$a$C$$u20$T$GT$$u20$as$u20$core..fmt..Write$GT$10write_char17he86ec787baa105aaE 68 | p _ZN96_$LT$core..fmt..Write..write_fmt..Adapter$LT$$u27$a$C$$u20$T$GT$$u20$as$u20$core..fmt..Write$GT$9write_fmt17h00448269bcfc4360E 69 | p _ZN96_$LT$core..fmt..Write..write_fmt..Adapter$LT$$u27$a$C$$u20$T$GT$$u20$as$u20$core..fmt..Write$GT$9write_fmt17h41014a1452ce9a71E 70 | p _ZN96_$LT$core..fmt..Write..write_fmt..Adapter$LT$$u27$a$C$$u20$T$GT$$u20$as$u20$core..fmt..Write$GT$9write_str17h44cd5c7a6bd3fa24E 71 | p _ZN96_$LT$core..fmt..Write..write_fmt..Adapter$LT$$u27$a$C$$u20$T$GT$$u20$as$u20$core..fmt..Write$GT$9write_str17h9e92886134f68c4dE 72 | p _ZN68_$LT$std..thread..local..AccessError$u20$as$u20$core..fmt..Debug$GT$3fmt17h38e9d4b028b59070E 73 | p _ZN46_$LT$std..thread..local..LocalKey$LT$T$GT$$GT$8try_with17hfce1cc9f36b426d0E 74 | p __muldi3 75 | e __muldi3 76 | e __multi3 77 | e __mulosi4 78 | e __mulodi4 79 | e __muloti4 80 | e __divsi3 81 | e __divdi3 82 | e __divti3 83 | e __modsi3 84 | e __moddi3 85 | e __modti3 86 | e __divmodsi4 87 | e __divmoddi4 88 | e __ashldi3 89 | e __ashlti3 90 | e __ashrdi3 91 | e __ashrti3 92 | e __lshrdi3 93 | e __lshrti3 94 | e __udivsi3 95 | e __umodsi3 96 | e __udivmodsi4 97 | e __udivdi3 98 | e __udivmoddi4 99 | e __umoddi3 100 | e __udivti3 101 | e __udivmodti4 102 | e __umodti3 103 | e memcpy 104 | e memmove 105 | e memset 106 | e memcmp 107 | e __addsf3 108 | e __adddf3 109 | e __floatsisf 110 | e __floatsidf 111 | e __floatdidf 112 | e __floattisf 113 | e __floattidf 114 | e __floatunsisf 115 | e __floatunsidf 116 | e __floatundidf 117 | e __floatuntisf 118 | e __floatuntidf 119 | e __fixsfsi 120 | e __fixsfdi 121 | e __fixsfti 122 | e __fixdfsi 123 | e __fixdfdi 124 | e __fixdfti 125 | e __fixunssfsi 126 | e __fixunssfdi 127 | e __fixunssfti 128 | e __fixunsdfsi 129 | e __fixunsdfdi 130 | e __fixunsdfti 131 | e __divsf3 132 | e __divdf3 133 | e __mulsf3 134 | e __muldf3 135 | e __powisf2 136 | e __powidf2 137 | e __subsf3 138 | e __subdf3 139 | e rust_eh_personality 140 | p _ZN8dlmalloc8dlmalloc8Dlmalloc18unlink_large_chunk17h9160cadc87bd9b58E 141 | p _ZN8dlmalloc8dlmalloc8Dlmalloc18insert_large_chunk17h95b574ef6905303cE 142 | p _ZN8dlmalloc8dlmalloc8Dlmalloc7realloc17h8a4bcf906f9969a3E 143 | p _ZN8dlmalloc8dlmalloc8Dlmalloc13dispose_chunk17hfb236c21060aea2fE 144 | p _ZN8dlmalloc8dlmalloc8Dlmalloc4free17h8185738df2a87b48E 145 | p _ZN33_$LT$alloc..vec..Vec$LT$T$GT$$GT$17extend_from_slice17hf187e100f0904e3cE 146 | p _ZN49_$LT$alloc..raw_vec..RawVec$LT$T$C$$u20$A$GT$$GT$11allocate_in17hf473635a28c2f60fE 147 | p _ZN4core3fmt3num52_$LT$impl$u20$core..fmt..Debug$u20$for$u20$usize$GT$3fmt17he64994cf6f0229efE 148 | p _ZN4core3fmt3num54_$LT$impl$u20$core..fmt..Display$u20$for$u20$usize$GT$3fmt17h2bb1c7279256f668E 149 | p _ZN4core3fmt3num52_$LT$impl$u20$core..fmt..Display$u20$for$u20$u32$GT$3fmt17h7507ae0df89e6b5aE 150 | p _ZN96_$LT$core..fmt..Write..write_fmt..Adapter$LT$$u27$a$C$$u20$T$GT$$u20$as$u20$core..fmt..Write$GT$9write_str17hf28d5d031ad32011E 151 | p _ZN96_$LT$core..fmt..Write..write_fmt..Adapter$LT$$u27$a$C$$u20$T$GT$$u20$as$u20$core..fmt..Write$GT$10write_char17h12aa346679c88006E 152 | p _ZN96_$LT$core..fmt..Write..write_fmt..Adapter$LT$$u27$a$C$$u20$T$GT$$u20$as$u20$core..fmt..Write$GT$9write_fmt17h0a74b8dc2e247efaE 153 | p _ZN4core3fmt10ArgumentV110show_usize17h80e90b29feae30e4E 154 | p _ZN4core3fmt5write17h914fcaafc6fb200aE 155 | p _ZN4core3ptr13drop_in_place17h6f534c8c21ea70acE 156 | p _ZN4core3fmt9Formatter12pad_integral17h2f2f83d99c318b28E 157 | p _ZN4core3fmt9Formatter12pad_integral28_$u7b$$u7b$closure$u7d$$u7d$17h260e793666777f47E 158 | p _ZN4core3fmt9Formatter3pad17hdb2be9f507201bd1E 159 | p _ZN40_$LT$str$u20$as$u20$core..fmt..Debug$GT$3fmt17h0cf4ea19d7121472E 160 | p _ZN41_$LT$char$u20$as$u20$core..fmt..Debug$GT$3fmt17h21dd5ee27649cffdE 161 | p _ZN55_$LT$$RF$$u27$a$u20$T$u20$as$u20$core..fmt..Display$GT$3fmt17hdef34141bbace6f9E 162 | p _ZN75_$LT$$RF$$u27$a$u20$mut$u20$I$u20$as$u20$core..iter..iterator..Iterator$GT$4next17h71d732fe2f55b336E 163 | p _ZN4core3str16slice_error_fail17h09ffe3974e261c49E 164 | p _ZN82_$LT$core..fmt..builders..PadAdapter$LT$$u27$a$GT$$u20$as$u20$core..fmt..Write$GT$9write_str17he73b859f871181bcE 165 | p _ZN4core3fmt8builders10DebugTuple5field17h0824d538bf53adccE 166 | p _ZN4core3fmt5Write10write_char17hcbedcd1253b69125E 167 | p _ZN4core3fmt5Write9write_fmt17he646b8663fbc84c9E 168 | p _ZN4core3ptr13drop_in_place17hea7e6e6e99670c73E 169 | p _ZN4core9panicking5panic17h39c17c1237fb0327E 170 | p _ZN4core9panicking18panic_bounds_check17h92acfa905e83b8aeE 171 | p _ZN4core9panicking9panic_fmt17he30a33b74d717e0eE 172 | p _ZN71_$LT$core..ops..range..Range$LT$Idx$GT$$u20$as$u20$core..fmt..Debug$GT$3fmt17h7ea97092a23a5a63E 173 | p _ZN4core6option13expect_failed17h6ffc8268d6be0c2fE 174 | p _ZN60_$LT$core..cell..BorrowError$u20$as$u20$core..fmt..Debug$GT$3fmt17h34889acdacce7e2aE 175 | p _ZN63_$LT$core..cell..BorrowMutError$u20$as$u20$core..fmt..Debug$GT$3fmt17hff9567832a7eda60E 176 | p _ZN4core12char_private12is_printable17hc5280a2390ffc7fcE 177 | p _ZN4core12char_private5check17hd971f4210d6de5c9E 178 | p _ZN4core5slice20slice_index_len_fail17he20ea683b5502d9aE 179 | p _ZN4core5slice22slice_index_order_fail17h2c23bc1ce370b6f1E 180 | p fluxions 181 | e fluxions 182 | e quicksilver 183 | e main 184 | p __wasm_nullptr 185 | p _start 186 | -------------------------------------------------------------------------------- /tests/hello.rs: -------------------------------------------------------------------------------- 1 | #![cfg(target_arch = "wasm32")] 2 | 3 | #[no_mangle] 4 | pub fn fluxions(x: usize) -> usize { 5 | unsafe { imported(x) } 6 | } 7 | 8 | #[no_mangle] 9 | pub fn quicksilver(_: usize) {} 10 | 11 | extern "C" { 12 | fn imported(x: usize) -> usize; 13 | } 14 | 15 | #[no_mangle] 16 | pub fn main() {} 17 | -------------------------------------------------------------------------------- /tests/hello.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fitzgen/wasm-nm/b5084804b33c49d937719400d5e43d2a07e3e2fe/tests/hello.wasm -------------------------------------------------------------------------------- /tests/small-hello-dash-e.expected: -------------------------------------------------------------------------------- 1 | e fluxions 2 | e quicksilver 3 | -------------------------------------------------------------------------------- /tests/small-hello-dash-j.expected: -------------------------------------------------------------------------------- 1 | imported 2 | std::rt::lang_start::{{closure}}::h4a005ebb0fff14ce 3 | core::ops::function::FnOnce::call_once::hfec8c71b0834a396 4 | core::ptr::drop_in_place::haec76f9ee14b5e35 5 | >::reserve_exact::h12cd11688004ca4b 6 | >::shrink_to_fit::hab6a6becd91a127f 7 | >::extend_from_slice::h55be1b9e3931382f 8 | >::double::hcb678cb3bee53ad7 9 | <&'a T as core::fmt::Debug>::fmt::h4a5a01d440d30f67 10 | std::sys_common::at_exit_imp::cleanup::h3cbcee67c7d8b406 11 | std::sys_common::thread_info::THREAD_INFO::__getit::h5520c8a621a7d891 12 | std::sys_common::thread_local::StaticKey::lazy_init::h0e26fad736fa74a6 13 | core::result::unwrap_failed::h0cf9629bbd9645fe 14 | core::result::unwrap_failed::h1db66428c6b7f087 15 | core::result::unwrap_failed::haeeb2813da2027ba 16 | core::result::unwrap_failed::hbd0e0d830f79de1a 17 | core::result::unwrap_failed::hec2c782fbf0c355c 18 | std::error::Error::cause::h70c0e8f8d884244e 19 | std::error::Error::type_id::h0597eb3374c8b596 20 | for alloc::boxed::Box>::from::StringError as std::error::Error>::description::heae9827b7cd47142 21 | for alloc::boxed::Box>::from::StringError as core::fmt::Display>::fmt::h4b11ad51403e1489 22 | std::io::Write::write_all::h1e22c345ee74bd20 23 | std::io::Write::write_fmt::he1152d8bae99d65b 24 | core::ptr::drop_in_place::h2bdbaf674f0aee8f 25 | for alloc::boxed::Box>::from::StringError as core::fmt::Debug>::fmt::h710025ce6ce2de1f 26 | core::ptr::drop_in_place::h65247ce7e4709129 27 | core::fmt::Write::write_char::hb47c60d960f24025 28 | core::fmt::Write::write_fmt::hd6115c3c6bf97ff1 29 | core::ptr::drop_in_place::hcd2d108484489df3 30 | as core::fmt::Write>::write_str::hfb203f95b9e34b22 31 | core::ptr::drop_in_place::h8f35c23f76abee51 32 | std::io::error::Error::new::h381dae13d0f2cf0d 33 | >::drop_slow::h933c0bf4db588528 34 | ::get_type_id::hcf276e0529accfd4 35 | core::fmt::Write::write_fmt::hf94ca4b41923d8fb 36 | core::ptr::drop_in_place::ha05a3a5b67481aad 37 | <&'a T as core::fmt::Debug>::fmt::h14a99863a6b1c9da 38 | std::thread::Thread::new::h84c5176c2b27bd8a 39 | ::fmt::hebab1e70554ff965 40 | core::ptr::drop_in_place::h9caabe1a35ed262c 41 | core::ptr::drop_in_place::heb39250dd62cb94b 42 | std::thread::local::os::destroy_value::h742a7e47335460b8 43 | std::thread::local::os::destroy_value::hb42727554f684767 44 | std::thread::local::os::destroy_value::hc4fcd9b61f79c3b7 45 | std::sys_common::backtrace::__rust_begin_short_backtrace::hb9f3968452a7d8db 46 | as core::fmt::Debug>::fmt::h9ca8a5a1dc3f81be 47 | std::sys_common::memchr::fallback::memchr::hb120b04790bd1299 48 | std::sys_common::util::dumb_print::hd5898bb2eda1120a 49 | std::panicking::begin_panic::hdbf9a3586ca2db9b 50 | std::panicking::rust_panic_with_hook::h52b2005910c55f47 51 | std::panicking::default_hook::{{closure}}::h02c960b6aa5cdc20 52 | core::ptr::drop_in_place::h47ff60385eded4a9 53 | std::io::impls::::write::h624a99b6a307d797 54 | std::io::impls::::flush::hc3482b034a6a4db7 55 | std::io::impls::::write_all::h91b04ea836f43923 56 | std::io::impls::::write_fmt::h52f014db65414dc6 57 | std::panicking::LOCAL_STDERR::__getit::ha4b201e512ab3c66 58 | core::ptr::drop_in_place::h87473f3cb67ee6ec 59 | ::get_type_id::hba485be8a12c6119 60 | std::panicking::update_panic_count::PANIC_COUNT::__getit::h4ec790dd4d7f8dcf 61 | std::panicking::begin_panic_fmt::h47786a9a66db0de4 62 | std::panicking::begin_panic::h1edc0d1d8a3585ff 63 | _ZN4core3ptr13drop_in_place17h9f6f00b5724f00f3E.899 64 | <&'a T as core::fmt::Debug>::fmt::h2a3f4d7a59ce4687 65 | <&'a T as core::fmt::Display>::fmt::he00d690ee0dec7e2 66 | as core::fmt::Write>::write_char::hc94f70c97a18b983 67 | as core::fmt::Write>::write_char::he86ec787baa105aa 68 | as core::fmt::Write>::write_fmt::h00448269bcfc4360 69 | as core::fmt::Write>::write_fmt::h41014a1452ce9a71 70 | as core::fmt::Write>::write_str::h44cd5c7a6bd3fa24 71 | as core::fmt::Write>::write_str::h9e92886134f68c4d 72 | ::fmt::h38e9d4b028b59070 73 | >::try_with::hfce1cc9f36b426d0 74 | memcpy 75 | dlmalloc::dlmalloc::Dlmalloc::malloc::hb37c2fafc9847520 76 | dlmalloc::dlmalloc::Dlmalloc::unlink_large_chunk::h9160cadc87bd9b58 77 | dlmalloc::dlmalloc::Dlmalloc::insert_large_chunk::h95b574ef6905303c 78 | dlmalloc::dlmalloc::Dlmalloc::realloc::h8a4bcf906f9969a3 79 | dlmalloc::dlmalloc::Dlmalloc::dispose_chunk::hfb236c21060aea2f 80 | dlmalloc::dlmalloc::Dlmalloc::free::h8185738df2a87b48 81 | >::extend_from_slice::hf187e100f0904e3c 82 | >::allocate_in::hf473635a28c2f60f 83 | core::fmt::num::::fmt::he64994cf6f0229ef 84 | core::fmt::num::::fmt::h2bb1c7279256f668 85 | core::fmt::num::::fmt::h7507ae0df89e6b5a 86 | as core::fmt::Write>::write_str::hf28d5d031ad32011 87 | as core::fmt::Write>::write_char::h12aa346679c88006 88 | as core::fmt::Write>::write_fmt::h0a74b8dc2e247efa 89 | core::fmt::ArgumentV1::show_usize::h80e90b29feae30e4 90 | core::fmt::write::h914fcaafc6fb200a 91 | core::ptr::drop_in_place::h6f534c8c21ea70ac 92 | core::fmt::Formatter::pad_integral::h2f2f83d99c318b28 93 | core::fmt::Formatter::pad_integral::{{closure}}::h260e793666777f47 94 | core::fmt::Formatter::pad::hdb2be9f507201bd1 95 | ::fmt::h0cf4ea19d7121472 96 | ::fmt::h21dd5ee27649cffd 97 | <&'a T as core::fmt::Display>::fmt::hdef34141bbace6f9 98 | <&'a mut I as core::iter::iterator::Iterator>::next::h71d732fe2f55b336 99 | core::str::slice_error_fail::h09ffe3974e261c49 100 | as core::fmt::Write>::write_str::he73b859f871181bc 101 | core::fmt::builders::DebugTuple::field::h0824d538bf53adcc 102 | core::fmt::Write::write_char::hcbedcd1253b69125 103 | core::fmt::Write::write_fmt::he646b8663fbc84c9 104 | core::ptr::drop_in_place::hea7e6e6e99670c73 105 | core::panicking::panic::h39c17c1237fb0327 106 | core::panicking::panic_bounds_check::h92acfa905e83b8ae 107 | core::panicking::panic_fmt::he30a33b74d717e0e 108 | as core::fmt::Debug>::fmt::h7ea97092a23a5a63 109 | core::option::expect_failed::h6ffc8268d6be0c2f 110 | ::fmt::h34889acdacce7e2a 111 | ::fmt::hff9567832a7eda60 112 | core::char_private::is_printable::hc5280a2390ffc7fc 113 | core::char_private::check::hd971f4210d6de5c9 114 | core::slice::slice_index_len_fail::he20ea683b5502d9a 115 | core::slice::slice_index_order_fail::h2c23bc1ce370b6f1 116 | fluxions 117 | fluxions 118 | quicksilver 119 | hello::main::h2b8b138267cb20a6 120 | __wasm_nullptr 121 | _start 122 | -------------------------------------------------------------------------------- /tests/small-hello.expected: -------------------------------------------------------------------------------- 1 | i imported 2 | p std::rt::lang_start::{{closure}}::h4a005ebb0fff14ce 3 | p core::ops::function::FnOnce::call_once::hfec8c71b0834a396 4 | p core::ptr::drop_in_place::haec76f9ee14b5e35 5 | p >::reserve_exact::h12cd11688004ca4b 6 | p >::shrink_to_fit::hab6a6becd91a127f 7 | p >::extend_from_slice::h55be1b9e3931382f 8 | p >::double::hcb678cb3bee53ad7 9 | p <&'a T as core::fmt::Debug>::fmt::h4a5a01d440d30f67 10 | p std::sys_common::at_exit_imp::cleanup::h3cbcee67c7d8b406 11 | p std::sys_common::thread_info::THREAD_INFO::__getit::h5520c8a621a7d891 12 | p std::sys_common::thread_local::StaticKey::lazy_init::h0e26fad736fa74a6 13 | p core::result::unwrap_failed::h0cf9629bbd9645fe 14 | p core::result::unwrap_failed::h1db66428c6b7f087 15 | p core::result::unwrap_failed::haeeb2813da2027ba 16 | p core::result::unwrap_failed::hbd0e0d830f79de1a 17 | p core::result::unwrap_failed::hec2c782fbf0c355c 18 | p std::error::Error::cause::h70c0e8f8d884244e 19 | p std::error::Error::type_id::h0597eb3374c8b596 20 | p for alloc::boxed::Box>::from::StringError as std::error::Error>::description::heae9827b7cd47142 21 | p for alloc::boxed::Box>::from::StringError as core::fmt::Display>::fmt::h4b11ad51403e1489 22 | p std::io::Write::write_all::h1e22c345ee74bd20 23 | p std::io::Write::write_fmt::he1152d8bae99d65b 24 | p core::ptr::drop_in_place::h2bdbaf674f0aee8f 25 | p for alloc::boxed::Box>::from::StringError as core::fmt::Debug>::fmt::h710025ce6ce2de1f 26 | p core::ptr::drop_in_place::h65247ce7e4709129 27 | p core::fmt::Write::write_char::hb47c60d960f24025 28 | p core::fmt::Write::write_fmt::hd6115c3c6bf97ff1 29 | p core::ptr::drop_in_place::hcd2d108484489df3 30 | p as core::fmt::Write>::write_str::hfb203f95b9e34b22 31 | p core::ptr::drop_in_place::h8f35c23f76abee51 32 | p std::io::error::Error::new::h381dae13d0f2cf0d 33 | p >::drop_slow::h933c0bf4db588528 34 | p ::get_type_id::hcf276e0529accfd4 35 | p core::fmt::Write::write_fmt::hf94ca4b41923d8fb 36 | p core::ptr::drop_in_place::ha05a3a5b67481aad 37 | p <&'a T as core::fmt::Debug>::fmt::h14a99863a6b1c9da 38 | p std::thread::Thread::new::h84c5176c2b27bd8a 39 | p ::fmt::hebab1e70554ff965 40 | p core::ptr::drop_in_place::h9caabe1a35ed262c 41 | p core::ptr::drop_in_place::heb39250dd62cb94b 42 | p std::thread::local::os::destroy_value::h742a7e47335460b8 43 | p std::thread::local::os::destroy_value::hb42727554f684767 44 | p std::thread::local::os::destroy_value::hc4fcd9b61f79c3b7 45 | p std::sys_common::backtrace::__rust_begin_short_backtrace::hb9f3968452a7d8db 46 | p as core::fmt::Debug>::fmt::h9ca8a5a1dc3f81be 47 | p std::sys_common::memchr::fallback::memchr::hb120b04790bd1299 48 | p std::sys_common::util::dumb_print::hd5898bb2eda1120a 49 | p std::panicking::begin_panic::hdbf9a3586ca2db9b 50 | p std::panicking::rust_panic_with_hook::h52b2005910c55f47 51 | p std::panicking::default_hook::{{closure}}::h02c960b6aa5cdc20 52 | p core::ptr::drop_in_place::h47ff60385eded4a9 53 | p std::io::impls::::write::h624a99b6a307d797 54 | p std::io::impls::::flush::hc3482b034a6a4db7 55 | p std::io::impls::::write_all::h91b04ea836f43923 56 | p std::io::impls::::write_fmt::h52f014db65414dc6 57 | p std::panicking::LOCAL_STDERR::__getit::ha4b201e512ab3c66 58 | p core::ptr::drop_in_place::h87473f3cb67ee6ec 59 | p ::get_type_id::hba485be8a12c6119 60 | p std::panicking::update_panic_count::PANIC_COUNT::__getit::h4ec790dd4d7f8dcf 61 | p std::panicking::begin_panic_fmt::h47786a9a66db0de4 62 | p std::panicking::begin_panic::h1edc0d1d8a3585ff 63 | p _ZN4core3ptr13drop_in_place17h9f6f00b5724f00f3E.899 64 | p <&'a T as core::fmt::Debug>::fmt::h2a3f4d7a59ce4687 65 | p <&'a T as core::fmt::Display>::fmt::he00d690ee0dec7e2 66 | p as core::fmt::Write>::write_char::hc94f70c97a18b983 67 | p as core::fmt::Write>::write_char::he86ec787baa105aa 68 | p as core::fmt::Write>::write_fmt::h00448269bcfc4360 69 | p as core::fmt::Write>::write_fmt::h41014a1452ce9a71 70 | p as core::fmt::Write>::write_str::h44cd5c7a6bd3fa24 71 | p as core::fmt::Write>::write_str::h9e92886134f68c4d 72 | p ::fmt::h38e9d4b028b59070 73 | p >::try_with::hfce1cc9f36b426d0 74 | p memcpy 75 | p dlmalloc::dlmalloc::Dlmalloc::malloc::hb37c2fafc9847520 76 | p dlmalloc::dlmalloc::Dlmalloc::unlink_large_chunk::h9160cadc87bd9b58 77 | p dlmalloc::dlmalloc::Dlmalloc::insert_large_chunk::h95b574ef6905303c 78 | p dlmalloc::dlmalloc::Dlmalloc::realloc::h8a4bcf906f9969a3 79 | p dlmalloc::dlmalloc::Dlmalloc::dispose_chunk::hfb236c21060aea2f 80 | p dlmalloc::dlmalloc::Dlmalloc::free::h8185738df2a87b48 81 | p >::extend_from_slice::hf187e100f0904e3c 82 | p >::allocate_in::hf473635a28c2f60f 83 | p core::fmt::num::::fmt::he64994cf6f0229ef 84 | p core::fmt::num::::fmt::h2bb1c7279256f668 85 | p core::fmt::num::::fmt::h7507ae0df89e6b5a 86 | p as core::fmt::Write>::write_str::hf28d5d031ad32011 87 | p as core::fmt::Write>::write_char::h12aa346679c88006 88 | p as core::fmt::Write>::write_fmt::h0a74b8dc2e247efa 89 | p core::fmt::ArgumentV1::show_usize::h80e90b29feae30e4 90 | p core::fmt::write::h914fcaafc6fb200a 91 | p core::ptr::drop_in_place::h6f534c8c21ea70ac 92 | p core::fmt::Formatter::pad_integral::h2f2f83d99c318b28 93 | p core::fmt::Formatter::pad_integral::{{closure}}::h260e793666777f47 94 | p core::fmt::Formatter::pad::hdb2be9f507201bd1 95 | p ::fmt::h0cf4ea19d7121472 96 | p ::fmt::h21dd5ee27649cffd 97 | p <&'a T as core::fmt::Display>::fmt::hdef34141bbace6f9 98 | p <&'a mut I as core::iter::iterator::Iterator>::next::h71d732fe2f55b336 99 | p core::str::slice_error_fail::h09ffe3974e261c49 100 | p as core::fmt::Write>::write_str::he73b859f871181bc 101 | p core::fmt::builders::DebugTuple::field::h0824d538bf53adcc 102 | p core::fmt::Write::write_char::hcbedcd1253b69125 103 | p core::fmt::Write::write_fmt::he646b8663fbc84c9 104 | p core::ptr::drop_in_place::hea7e6e6e99670c73 105 | p core::panicking::panic::h39c17c1237fb0327 106 | p core::panicking::panic_bounds_check::h92acfa905e83b8ae 107 | p core::panicking::panic_fmt::he30a33b74d717e0e 108 | p as core::fmt::Debug>::fmt::h7ea97092a23a5a63 109 | p core::option::expect_failed::h6ffc8268d6be0c2f 110 | p ::fmt::h34889acdacce7e2a 111 | p ::fmt::hff9567832a7eda60 112 | p core::char_private::is_printable::hc5280a2390ffc7fc 113 | p core::char_private::check::hd971f4210d6de5c9 114 | p core::slice::slice_index_len_fail::he20ea683b5502d9a 115 | p core::slice::slice_index_order_fail::h2c23bc1ce370b6f1 116 | p fluxions 117 | e fluxions 118 | e quicksilver 119 | p hello::main::h2b8b138267cb20a6 120 | p __wasm_nullptr 121 | p _start 122 | -------------------------------------------------------------------------------- /tests/small-hello.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fitzgen/wasm-nm/b5084804b33c49d937719400d5e43d2a07e3e2fe/tests/small-hello.wasm -------------------------------------------------------------------------------- /tests/tests.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::io::Read; 3 | use std::process::Command; 4 | 5 | #[test] 6 | fn cargo_readme_up_to_date() { 7 | println!("Checking that `cargo readme > README.md` is up to date..."); 8 | 9 | let expected = Command::new("cargo") 10 | .arg("readme") 11 | .current_dir(env!("CARGO_MANIFEST_DIR")) 12 | .output() 13 | .expect("should run `cargo readme` OK") 14 | .stdout; 15 | let expected = String::from_utf8_lossy(&expected); 16 | 17 | let actual = { 18 | let mut file = File::open(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md")) 19 | .expect("should open README.md file"); 20 | let mut s = String::new(); 21 | file.read_to_string(&mut s) 22 | .expect("should read contents of file to string"); 23 | s 24 | }; 25 | 26 | if actual != expected { 27 | panic!("Run `cargo readme > README.md` to update README.md"); 28 | } 29 | } 30 | 31 | macro_rules! test { 32 | ( $name:ident => $wasm:expr; $expected:expr ) => { 33 | test!($name => $wasm; []; $expected); 34 | }; 35 | ( $name:ident => $wasm:expr ; $flags:expr ; $expected:expr ) => { 36 | #[test] 37 | #[cfg(feature = "exe")] 38 | fn $name() { 39 | let flags = $flags; 40 | let flags: &[&str] = &flags[..]; 41 | let output = Command::new("cargo") 42 | .arg("run") 43 | .arg("--") 44 | .args(flags) 45 | .arg(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/", $wasm)) 46 | .output() 47 | .expect("should `cargo run` OK"); 48 | 49 | let mut expected_file = File::open(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/", $expected)) 50 | .expect(concat!("should open ", $expected)); 51 | 52 | let mut expected = vec![]; 53 | expected_file.read_to_end(&mut expected).expect("should read to end"); 54 | 55 | println!("actual =\n{}", String::from_utf8_lossy(&output.stdout)); 56 | println!("expected =\n{}", String::from_utf8_lossy(&expected)); 57 | 58 | if output.stdout != expected { 59 | panic!("{} does not match", $expected); 60 | } 61 | } 62 | 63 | } 64 | } 65 | 66 | test!(hello => "hello.wasm"; "hello.expected"); 67 | test!(hello_dash_i => "hello.wasm"; ["-i"]; "hello-dash-i.expected"); 68 | test!(small_hello => "small-hello.wasm"; "small-hello.expected"); 69 | test!(small_hello_dash_j => "small-hello.wasm"; ["-j"]; "small-hello-dash-j.expected"); 70 | test!(small_hello_dash_e => "small-hello.wasm"; ["-e"]; "small-hello-dash-e.expected"); 71 | --------------------------------------------------------------------------------