├── .gitignore
├── README.md
├── config-overrides.js
├── package.json
├── public
└── index.html
├── src
├── component
│ ├── app
│ │ ├── App.css
│ │ └── App.tsx
│ ├── editor
│ │ └── Editor.tsx
│ ├── settings
│ │ ├── Settings.css
│ │ └── Settings.tsx
│ └── sidebar
│ │ ├── Sidebar.css
│ │ ├── Sidebar.tsx
│ │ ├── SidebarIcon.css
│ │ └── SidebarIcon.tsx
├── index.css
├── index.tsx
├── language
│ └── index.ts
└── react-app-env.d.ts
├── tsconfig.json
├── wasm-remapper
├── .gitignore
├── Cargo.toml
├── README.md
└── src
│ ├── lib.rs
│ └── utils.rs
├── wasm2wat
├── .cargo-ok
├── .gitignore
├── Cargo.toml
└── src
│ ├── lib.rs
│ └── utils.rs
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # wasm-remapper-web
2 | A web app to help reverse engineer WebAssembly binaries.
3 |
4 | ## Demo
5 | wasm-remapper-web is live at https://remapper.zebulon.dev/
6 |
7 | ## How it works
8 | Wasm-remapper-web works by cross referencing every function inside the input WebAssembly binary with a **reference** WebAssembly binary with debug symbols. If you are able to determine the compiler version used to generate the input binary you can generally compile a binary that includes many functions from the standard library and generate a remapped output binary.
9 |
10 | ## As a library
11 | wasm-remapper-web is built on top of my Rust library called [wasm_remapper](https://github.com/vlakreeh/wasm_remapper).
12 |
13 | [](https://crates.io/crates/wasm_remapper)
14 | [](https://docs.rs/wasm_remapper/)
15 |
--------------------------------------------------------------------------------
/config-overrides.js:
--------------------------------------------------------------------------------
1 | const MonacoWebpackPlugin = require("monaco-editor-webpack-plugin");
2 | const path = require('path');
3 |
4 | module.exports = function override(config, env) {
5 | const wasmExtensionRegExp = /\.wasm$/;
6 |
7 | config.resolve.extensions.push('.wasm');
8 |
9 | config.module.rules.forEach(rule => {
10 | (rule.oneOf || []).forEach(oneOf => {
11 | if (oneOf.loader && oneOf.loader.indexOf('file-loader') >= 0) {
12 | // make file-loader ignore WASM files
13 | oneOf.exclude.push(wasmExtensionRegExp);
14 | }
15 | });
16 | });
17 |
18 | // add a dedicated loader for WASM
19 | config.module.rules.push({
20 | test: wasmExtensionRegExp,
21 | include: path.resolve(__dirname, 'src'),
22 | use: [{ loader: require.resolve('wasm-loader'), options: {} }]
23 | });
24 | config.plugins.push(new MonacoWebpackPlugin({
25 | languages: ["javascript"]
26 | }));
27 | return config;
28 | }
29 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "wasm-remapper-web",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@babel/plugin-syntax-import-meta": "^7.10.4",
7 | "@material-ui/core": "^4.11.0",
8 | "@testing-library/jest-dom": "^4.2.4",
9 | "@testing-library/react": "^9.3.2",
10 | "@testing-library/user-event": "^7.1.2",
11 | "@types/jest": "^24.0.0",
12 | "@types/node": "^12.0.0",
13 | "@types/react": "^16.9.0",
14 | "@types/react-dom": "^16.9.0",
15 | "eva-icons": "^1.1.3",
16 | "file-saver": "^2.0.2",
17 | "monaco-editor": "^0.20.0",
18 | "monaco-editor-webpack-plugin": "^1.9.0",
19 | "react": "^16.13.1",
20 | "react-dom": "^16.13.1",
21 | "react-dropzone": "^11.2.0",
22 | "react-monaco-editor": "^0.40.0",
23 | "react-resize-detector": "^5.2.0",
24 | "react-scripts": "3.4.3",
25 | "react-tooltip": "^4.2.10",
26 | "typescript": "~3.7.2",
27 | "wasm-remapper": "./wasm-remapper/pkg",
28 | "wasm2wat": "./wasm2wat/pkg"
29 | },
30 | "scripts": {
31 | "start": "react-app-rewired start",
32 | "build": "react-app-rewired build",
33 | "test": "react-app-rewired test",
34 | "eject": "react-app-rewired eject"
35 | },
36 | "eslintConfig": {
37 | "extends": "react-app"
38 | },
39 | "browserslist": {
40 | "production": [
41 | ">0.2%",
42 | "not dead",
43 | "not op_mini all"
44 | ],
45 | "development": [
46 | "last 1 chrome version",
47 | "last 1 firefox version",
48 | "last 1 safari version"
49 | ]
50 | },
51 | "devDependencies": {
52 | "@types/file-saver": "^2.0.1",
53 | "@types/react-resize-detector": "^5.0.0",
54 | "react-app-rewired": "^2.1.6",
55 | "wasm-loader": "^1.3.0"
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Wasm Remapper
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/component/app/App.css:
--------------------------------------------------------------------------------
1 | @import url("https://dev-cats.github.io/code-snippets/JetBrainsMono.css");
2 |
3 | #app {
4 | height: 100vh;
5 | display: flex;
6 | flex-direction: row;
7 | overflow: hidden;
8 | }
--------------------------------------------------------------------------------
/src/component/app/App.tsx:
--------------------------------------------------------------------------------
1 | import React, { createContext, useState } from "react";
2 | import Editor from "../editor/Editor";
3 | import Settings from "../settings/Settings";
4 | import Sidebar from "../sidebar/Sidebar";
5 | import "./App.css";
6 |
7 | function readWasmFromLocalStorage(key: string): Uint8Array | undefined {
8 | const fromStorage = localStorage.getItem(key);
9 |
10 | if (fromStorage) {
11 | return new Uint8Array(Buffer.from(fromStorage, "base64"));
12 | }
13 |
14 | return undefined;
15 | }
16 |
17 | export type AppContextData = {
18 | inputWasm?: Uint8Array,
19 | referenceWasm?: Uint8Array,
20 | matchingThreshold: number,
21 | setMatchingThreshold?: (x: number) => void,
22 | ignoreDataSectionConstants: boolean,
23 | requireExactFunctionLocals: boolean,
24 | setIgnoreDataSectionConstants?: (value: boolean) => void,
25 | setRequireExactFunctionLocals?: (value: boolean) => void,
26 | };
27 |
28 | export const AppContext = createContext({
29 | matchingThreshold: 0.9,
30 | ignoreDataSectionConstants: false,
31 | requireExactFunctionLocals: true
32 | });
33 |
34 | const createSaveHook = (setWasmFunc: (wasm: Uint8Array) => void, key: string): (arg0: Uint8Array) => void => {
35 | return (wasm) => {
36 | const base64String = Buffer.from(wasm).toString("base64");
37 | localStorage.setItem(key, base64String);
38 | setWasmFunc(wasm);
39 | };
40 | };
41 |
42 | function App() {
43 | const [inputWasm, setInputWasm] = useState(readWasmFromLocalStorage("wasm.input"));
44 | const [referenceWasm, setReferenceWasm] = useState(readWasmFromLocalStorage("wasm.reference"));
45 |
46 | const [matchingThreshold, setMatchingThreshold] = useState(0.9);
47 | const [ignoreDataSectionConstants, setIgnoreDataSectionConstants] = useState(false);
48 | const [requireExactFunctionLocals, setRequireExactFunctionLocals] = useState(true);
49 |
50 | const [opened, setOpened] = useState(false);
51 |
52 | const providerValue = {
53 | referenceWasm,
54 | inputWasm,
55 | matchingThreshold,
56 | setMatchingThreshold,
57 | ignoreDataSectionConstants,
58 | requireExactFunctionLocals,
59 | setIgnoreDataSectionConstants,
60 | setRequireExactFunctionLocals,
61 | };
62 |
63 | return (
64 |
65 | setOpened(false)}>
66 |
67 | setOpened(true)}/>
68 |
69 |
70 |
71 |
72 | );
73 | }
74 |
75 | export default App;
76 |
--------------------------------------------------------------------------------
/src/component/editor/Editor.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import MonacoEditor from "react-monaco-editor";
3 | import monaco from "monaco-editor";
4 | import { useDropzone } from "react-dropzone";
5 |
6 | // Global editor options
7 | const options: monaco.editor.IStandaloneEditorConstructionOptions = {
8 | fontFamily: "JetBrains Mono",
9 | readOnly: true,
10 | minimap: {
11 | renderCharacters: false
12 | },
13 | automaticLayout: true
14 | };
15 |
16 | export type EditorProps = {
17 | type: "input" | "reference",
18 | setWasm: (wasm: Uint8Array) => void,
19 | };
20 |
21 | export default function Editor(props: EditorProps) {
22 | const { type, setWasm } = props;
23 | const localCode = localStorage.getItem(`wat.${type}`) || `;; Drop the ${type} wasm here`;
24 | const [code, setCode] = useState(localCode);
25 |
26 | const onDrop = async ([wasmBlob]: Blob[]) => {
27 | const { wasm2wat } = await import("wasm2wat");
28 | const buffer = await wasmBlob.arrayBuffer();
29 | const wasm = new Uint8Array(buffer);
30 | const wat = wasm2wat(wasm);
31 |
32 | setCode(wat);
33 | setWasm(wasm);
34 | localStorage.setItem(`wat.${type}`, wat);
35 | };
36 | const { getRootProps, getInputProps } = useDropzone({ onDrop, noClick: true });
37 |
38 | return (
39 |
40 |
41 |
);
42 | }
--------------------------------------------------------------------------------
/src/component/settings/Settings.css:
--------------------------------------------------------------------------------
1 | #settings-container {
2 | position: absolute;
3 | left: 0px;
4 | top: 0px;
5 | width: 100vw;
6 | height: 100vh;
7 |
8 | margin: 0px;
9 | padding: 0px;
10 |
11 | display: flex;
12 | align-items: center;
13 | justify-content: center;
14 |
15 | color: #EEE;
16 | }
17 |
18 | #settings-panel {
19 | display: flex;
20 | flex-direction: column;
21 | align-items: center;
22 |
23 | padding: 1rem;
24 | width: max(300px, 10vw);
25 | background-color: #212121;
26 | box-shadow: 0px 5px 10px -4px black;
27 | }
28 |
--------------------------------------------------------------------------------
/src/component/settings/Settings.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from "react";
2 | import Button from '@material-ui/core/Button';
3 | import Slider from '@material-ui/core/Slider';
4 | import "./Settings.css";
5 | import FormControlLabel from "@material-ui/core/FormControlLabel";
6 | import Checkbox from "@material-ui/core/Checkbox";
7 | import { AppContext } from "../app/App";
8 |
9 | export type SettingsProps = {
10 | opened: boolean,
11 | closeSettings: () => void,
12 | };
13 |
14 | export default function Settings({ opened, closeSettings }: SettingsProps) {
15 | const {
16 | matchingThreshold, setMatchingThreshold,
17 | ignoreDataSectionConstants, setIgnoreDataSectionConstants,
18 | requireExactFunctionLocals, setRequireExactFunctionLocals
19 | } = useContext(AppContext);
20 |
21 | const style = { zIndex: opened ? 1000 : -1, display: opened ? undefined : "none" };
22 |
23 | return (
24 |
25 |
26 |
Settings
27 | Matching Threshold
28 | `${Math.round(value)}%`}
32 | valueLabelDisplay="auto"
33 | step={1}
34 | min={0}
35 | max={100}
36 | onChange={(_, value: number | number[]) => setMatchingThreshold!(value as number / 100.0)}
37 | style={{ width: "200px" }}
38 | />
39 | setIgnoreDataSectionConstants!(!ignoreDataSectionConstants)}
44 | name="checkedB"
45 | color="primary"
46 | />
47 | }
48 | label="Ignore data section constants"
49 | />
50 | setRequireExactFunctionLocals!(!requireExactFunctionLocals)}
55 | name="checkedB"
56 | color="primary"
57 | />
58 | }
59 | label="Require exact function locals"
60 | />
61 |
62 |
63 |
64 | );
65 | }
--------------------------------------------------------------------------------
/src/component/sidebar/Sidebar.css:
--------------------------------------------------------------------------------
1 | #sidebar {
2 | height: 100%;
3 | background-color: #212121;
4 | display: flex;
5 | flex-direction: column;
6 | }
--------------------------------------------------------------------------------
/src/component/sidebar/Sidebar.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from "react";
2 | import SidebarIcon from "./SidebarIcon";
3 | import ReactTooltip from "react-tooltip";
4 | import { saveAs } from "file-saver";
5 | import "./Sidebar.css"
6 | import { AppContext } from "../app/App";
7 |
8 | export type SidebarProps = {
9 | openSettings: () => void,
10 | };
11 |
12 | export default function Sidebar(props: SidebarProps) {
13 | const { inputWasm, referenceWasm, matchingThreshold, ignoreDataSectionConstants, requireExactFunctionLocals } = useContext(AppContext);
14 |
15 | const remapClickHandler = async () => {
16 | const { remap } = await import("wasm-remapper");
17 |
18 | if (!inputWasm) {
19 | alert("Missing input binary");
20 | return;
21 | }
22 |
23 | if (!referenceWasm) {
24 | alert("Missing input binary");
25 | return;
26 | }
27 |
28 | const outputWasm = remap(
29 | inputWasm,
30 | referenceWasm,
31 | matchingThreshold,
32 | ignoreDataSectionConstants,
33 | requireExactFunctionLocals
34 | );
35 | const outputBlob = new Blob([outputWasm], { type: "application/wasm" });
36 | saveAs(outputBlob, "output.wasm");
37 | };
38 |
39 | return ();
55 | }
--------------------------------------------------------------------------------
/src/component/sidebar/SidebarIcon.css:
--------------------------------------------------------------------------------
1 | .sidebarIcon {
2 | width: 3.5rem;
3 | height: 3.5rem;
4 | transition: 0.3s;
5 | }
6 |
7 | .sidebarIcon > svg {
8 | padding: 1rem;
9 | transition: 0.3s;
10 | filter: invert() brightness(60%);
11 | }
12 |
13 | .sidebarIcon:hover {
14 | background-color: #313131;
15 | }
16 |
17 | .sidebarIcon:hover > svg {
18 | filter: invert() brightness(80%);
19 | }
--------------------------------------------------------------------------------
/src/component/sidebar/SidebarIcon.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from "react";
2 | import "./SidebarIcon.css";
3 |
4 | const eva = require("eva-icons");
5 |
6 | export type SidebarIconProps = {
7 | src: string,
8 | alt?: string,
9 | dataFor?: string,
10 | onClick?: () => void,
11 | };
12 |
13 | export default function SidebarIcon({ src, alt, dataFor, onClick }: SidebarIconProps) {
14 | useEffect(() => eva.replace(), []);
15 | return (
16 |
![{alt}]()
17 |
);
18 | }
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #1e1e1e;
3 | margin: 0px;
4 | font-family: Arial, Helvetica, sans-serif;
5 | }
6 |
7 | .overflowingContentWidgets {
8 | display: none;
9 | }
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 | import App from "./component/app/App";
4 | import { register } from "./language";
5 | import "./index.css";
6 |
7 | register();
8 |
9 | function Root() {
10 | return (
11 |
12 |
13 |
14 | );
15 | }
16 |
17 | ReactDOM.render(
18 | ,
19 | document.getElementById("root")
20 | );
21 |
--------------------------------------------------------------------------------
/src/language/index.ts:
--------------------------------------------------------------------------------
1 | import * as monaco from "monaco-editor";
2 |
3 | type WatLang = {
4 | keywords: string[],
5 | typeKeywords: string[],
6 | specialKeywords: string[],
7 | }
8 |
9 | const wat: monaco.languages.IMonarchLanguage | WatLang = {
10 | keywords: ["module",
11 | "table",
12 | "memory",
13 | "export",
14 | "import",
15 | "func",
16 | "result",
17 | "offset",
18 | "anyfunc",
19 | "type",
20 | "data",
21 | "start",
22 | "element",
23 | "global",
24 | "local",
25 | "mut",
26 | "param",
27 | "result"],
28 | specialKeywords: ["block", "loop", "end"],
29 | typeKeywords: ["i32", "i64", "f32", "f64", "funcref", "call"],
30 | tokenizer: {
31 | root: [
32 | [/\$\w+/, "identifier"],
33 | [/\d*\.\d+([eE][-+]?\d+)?/, "number.float"],
34 | [/0[xX][0-9a-fA-F]+/, "number.hex"],
35 | [/\d+/, "number"],
36 | [/".*"/, "string"],
37 | [/\(;.*;\)/, "comment"],
38 | [/;;.*/, "comment"],
39 | [/(\w+)\./, { token: "type.keyword" }],
40 | [/[a-zA-Z_]\w*/, {
41 | cases: {
42 | "@typeKeywords": "type.keyword",
43 | "@specialKeywords": "control",
44 | "@keywords": { token: "keyword.$0" }
45 | }
46 | }]
47 | ]
48 | }
49 | };
50 |
51 | export function register() {
52 | monaco.languages.register({ id: "wat" });
53 | monaco.languages.setMonarchTokensProvider("wat", wat as unknown as monaco.languages.IMonarchLanguage);
54 | monaco.editor.defineTheme("vs-dark-wat", {
55 | base: "vs-dark",
56 | inherit: true,
57 | colors: {},
58 | rules: [
59 | { token: "control", foreground: "C586C0" },
60 | { token: "identifier", foreground: "DCDCAA" },
61 | ]
62 | });
63 | }
--------------------------------------------------------------------------------
/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | interface Blob {
4 | arrayBuffer: () => Promise
5 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "strict": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "module": "esnext",
16 | "moduleResolution": "node",
17 | "resolveJsonModule": true,
18 | "isolatedModules": true,
19 | "noEmit": true,
20 | "jsx": "react"
21 | },
22 | "include": [
23 | "src"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/wasm-remapper/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | **/*.rs.bk
3 | Cargo.lock
4 | bin/
5 | pkg/
6 | wasm-pack.log
7 |
--------------------------------------------------------------------------------
/wasm-remapper/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "wasm-remapper"
3 | version = "0.1.0"
4 | authors = ["vlakreeh "]
5 | edition = "2018"
6 |
7 | [package.metadata.wasm-pack.profile.release]
8 | wasm-opt = false
9 |
10 | [lib]
11 | crate-type = ["cdylib", "rlib"]
12 |
13 | [features]
14 | default = ["console_error_panic_hook"]
15 |
16 | [dependencies]
17 | wasm-bindgen = "0.2.63"
18 |
19 | # The `console_error_panic_hook` crate provides better debugging of panics by
20 | # logging them with `console.error`. This is great for development, but requires
21 | # all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
22 | # code size when deploying.
23 | console_error_panic_hook = { version = "0.1.6", optional = true }
24 |
25 | # `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size
26 | # compared to the default allocator's ~10K. It is slower than the default
27 | # allocator, however.
28 | #
29 | # Unfortunately, `wee_alloc` requires nightly Rust when targeting wasm for now.
30 | wee_alloc = { version = "0.4.5", optional = true }
31 | wasm_remapper = "0.1.0"
32 |
33 | [dev-dependencies]
34 | wasm-bindgen-test = "0.3.13"
35 |
36 | [profile.release]
37 | # Tell `rustc` to optimize for small code size.
38 | opt-level = "s"
39 |
--------------------------------------------------------------------------------
/wasm-remapper/README.md:
--------------------------------------------------------------------------------
1 |
19 |
20 | ## About
21 |
22 | [**📚 Read this template tutorial! 📚**][template-docs]
23 |
24 | This template is designed for compiling Rust libraries into WebAssembly and
25 | publishing the resulting package to NPM.
26 |
27 | Be sure to check out [other `wasm-pack` tutorials online][tutorials] for other
28 | templates and usages of `wasm-pack`.
29 |
30 | [tutorials]: https://rustwasm.github.io/docs/wasm-pack/tutorials/index.html
31 | [template-docs]: https://rustwasm.github.io/docs/wasm-pack/tutorials/npm-browser-packages/index.html
32 |
33 | ## 🚴 Usage
34 |
35 | ### 🐑 Use `cargo generate` to Clone this Template
36 |
37 | [Learn more about `cargo generate` here.](https://github.com/ashleygwilliams/cargo-generate)
38 |
39 | ```
40 | cargo generate --git https://github.com/rustwasm/wasm-pack-template.git --name my-project
41 | cd my-project
42 | ```
43 |
44 | ### 🛠️ Build with `wasm-pack build`
45 |
46 | ```
47 | wasm-pack build
48 | ```
49 |
50 | ### 🔬 Test in Headless Browsers with `wasm-pack test`
51 |
52 | ```
53 | wasm-pack test --headless --firefox
54 | ```
55 |
56 | ### 🎁 Publish to NPM with `wasm-pack publish`
57 |
58 | ```
59 | wasm-pack publish
60 | ```
61 |
62 | ## 🔋 Batteries Included
63 |
64 | * [`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) for communicating
65 | between WebAssembly and JavaScript.
66 | * [`console_error_panic_hook`](https://github.com/rustwasm/console_error_panic_hook)
67 | for logging panic messages to the developer console.
68 | * [`wee_alloc`](https://github.com/rustwasm/wee_alloc), an allocator optimized
69 | for small code size.
70 |
--------------------------------------------------------------------------------
/wasm-remapper/src/lib.rs:
--------------------------------------------------------------------------------
1 | mod utils;
2 |
3 | use wasm_bindgen::prelude::*;
4 | use wasm_remapper::*;
5 |
6 | // When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
7 | // allocator.
8 | #[cfg(feature = "wee_alloc")]
9 | #[global_allocator]
10 | static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
11 |
12 | #[wasm_bindgen]
13 | #[allow(non_snake_case)]
14 | pub fn remap(
15 | input: &[u8],
16 | reference: &[u8],
17 | matchingThreshold: f32,
18 | ignoreDataSectionConstants: bool,
19 | requireExactFunctionLocals: bool,
20 | ) -> Result, JsValue> {
21 | Remapper::builder()
22 | .input(input)
23 | .reference(reference)
24 | .matching_threshold(matchingThreshold)
25 | .ingore_constant_data_section_pointers(ignoreDataSectionConstants)
26 | .require_exact_function_locals(requireExactFunctionLocals)
27 | .build()
28 | .map_err(|error| JsValue::from_str(&error.to_string()))?
29 | .remap()
30 | .map(|output| output.output)
31 | .map_err(|error| JsValue::from_str(&error.to_string()))
32 | }
33 |
--------------------------------------------------------------------------------
/wasm-remapper/src/utils.rs:
--------------------------------------------------------------------------------
1 | #[allow(unused)]
2 | pub fn set_panic_hook() {
3 | // When the `console_error_panic_hook` feature is enabled, we can call the
4 | // `set_panic_hook` function at least once during initialization, and then
5 | // we will get better error messages if our code ever panics.
6 | //
7 | // For more details see
8 | // https://github.com/rustwasm/console_error_panic_hook#readme
9 | #[cfg(feature = "console_error_panic_hook")]
10 | console_error_panic_hook::set_once();
11 | }
12 |
--------------------------------------------------------------------------------
/wasm2wat/.cargo-ok:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zebp/wasm-remapper-web/5ce7fc79843f7b4d142965657242ece86cafe4ab/wasm2wat/.cargo-ok
--------------------------------------------------------------------------------
/wasm2wat/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | **/*.rs.bk
3 | Cargo.lock
4 | bin/
5 | pkg/
6 | wasm-pack.log
7 |
--------------------------------------------------------------------------------
/wasm2wat/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "wasm2wat"
3 | version = "0.1.0"
4 | authors = ["vlakreeh "]
5 | edition = "2018"
6 |
7 | [package.metadata.wasm-pack.profile.release]
8 | wasm-opt = false
9 |
10 | [lib]
11 | crate-type = ["cdylib", "rlib"]
12 |
13 | [features]
14 | default = ["console_error_panic_hook"]
15 |
16 | [dependencies]
17 | wasm-bindgen = "0.2.63"
18 |
19 | # The `console_error_panic_hook` crate provides better debugging of panics by
20 | # logging them with `console.error`. This is great for development, but requires
21 | # all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
22 | # code size when deploying.
23 | console_error_panic_hook = { version = "0.1.6", optional = true }
24 |
25 | # `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size
26 | # compared to the default allocator's ~10K. It is slower than the default
27 | # allocator, however.
28 | #
29 | # Unfortunately, `wee_alloc` requires nightly Rust when targeting wasm for now.
30 | wee_alloc = { version = "0.4.5", optional = true }
31 | wasmprinter = "0.2.9"
32 |
33 | [profile.release]
34 | # Tell `rustc` to optimize for small code size.
35 | opt-level = "s"
36 |
--------------------------------------------------------------------------------
/wasm2wat/src/lib.rs:
--------------------------------------------------------------------------------
1 | mod utils;
2 |
3 | use wasm_bindgen::prelude::*;
4 |
5 | // When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
6 | // allocator.
7 | #[cfg(feature = "wee_alloc")]
8 | #[global_allocator]
9 | static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
10 |
11 | #[wasm_bindgen]
12 | pub fn wasm2wat(input: &[u8]) -> Result {
13 | wasmprinter::print_bytes(input).map_err(|error| error.to_string().into())
14 | }
15 |
--------------------------------------------------------------------------------
/wasm2wat/src/utils.rs:
--------------------------------------------------------------------------------
1 | #[allow(unused)]
2 | pub fn set_panic_hook() {
3 | // When the `console_error_panic_hook` feature is enabled, we can call the
4 | // `set_panic_hook` function at least once during initialization, and then
5 | // we will get better error messages if our code ever panics.
6 | //
7 | // For more details see
8 | // https://github.com/rustwasm/console_error_panic_hook#readme
9 | #[cfg(feature = "console_error_panic_hook")]
10 | console_error_panic_hook::set_once();
11 | }
12 |
--------------------------------------------------------------------------------