Skip to content

Commit 4091817

Browse files
committed
feat: automatic parse functions for use
1 parent 631318f commit 4091817

File tree

5 files changed

+270
-296
lines changed

5 files changed

+270
-296
lines changed

electron/main.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@ import Binaryen from "binaryen";
66
import * as fs from "node:fs";
77
import express from "express";
88
import serveIndex from "serve-index";
9+
import {parseRules} from "./parse.js";
910

1011
const isDev = process.env.NODE_ENV === 'development';
1112
const __filename = fileURLToPath(import.meta.url);
1213
const __dirname = path.dirname(__filename);
14+
const rules = JSON.parse(fs.readFileSync(path.join(__dirname, "rules.json"), "utf-8"));
15+
1316

1417
function createWindow() {
1518
const win = new BrowserWindow({
@@ -43,6 +46,13 @@ function createWindow() {
4346
let buffer = Buffer.concat(chunks);
4447

4548
try {
49+
const parsed = parseRules(buffer, rules);
50+
const parsedFunctions = {};
51+
52+
for (let key in parsed) {
53+
parsedFunctions[key] = parsed[key].substring(5);
54+
}
55+
4656
const module = Binaryen.readBinary(buffer);
4757

4858
const newModule = Binaryen.readBinary(buffer);
@@ -296,33 +306,33 @@ function createWindow() {
296306
WebAssembly.instantiate = async function(buffer, imports = {}) {
297307
const wasmFunctionNames = ${JSON.stringify(funcNames)};
298308
window.ayuHooks.functions = wasmFunctionNames;
299-
309+
window.ayuHooks.parsedFunctions = ${JSON.stringify(parsedFunctions)};
310+
300311
if (!imports.hooks) imports.hooks = {};
301-
312+
302313
Object.values(wasmFunctionNames).forEach(name => {
303314
const preName = 'pre_' + name;
304315
const postName = 'post_' + name;
305-
316+
306317
if (!imports.hooks[preName]) {
307318
imports.hooks[preName] = (...args) => {
308319
// console.log('Calling hook:', preName, 'with args:', args);
309320
return window.ayuHooks?.[preName]?.(...args) ? 0 : 1;
310321
};
311322
}
312-
323+
313324
if (!imports.hooks[postName]) {
314325
imports.hooks[postName] = (ret) => {
315326
// console.log('Calling hook:', postName, 'with return value:', ret);
316327
return window.ayuHooks?.[postName]?.(ret) ?? ret;
317328
};
318329
}
319330
});
320-
331+
321332
return originalInstantiate.call(this, buffer, imports);
322333
};
323334
`);
324335

325-
// await new Promise(resolve=>fs.writeFile("out.wat", newModule.emitText(), resolve));
326336
console.log("Validate");
327337
newModule.validate();
328338
console.log("Validate pass");

electron/parse.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { decode } from "@webassemblyjs/wasm-parser";
2+
import { traverse } from "@webassemblyjs/ast";
3+
4+
export function parseRules(wasmBytes, rules) {
5+
const ast = decode(wasmBytes);
6+
7+
const funcs = [];
8+
9+
traverse(ast, {
10+
Func({ node }) {
11+
if (node.signature) {
12+
funcs.push(node);
13+
}
14+
}
15+
});
16+
17+
function matchParams(wasmParams, ruleParams) {
18+
if (!ruleParams) return true;
19+
const paramTypes = wasmParams.map(p => p.valtype);
20+
return JSON.stringify(paramTypes) === JSON.stringify(ruleParams);
21+
}
22+
23+
function matchBody(instrs, ruleBody) {
24+
if (!ruleBody) return true;
25+
let j = 0;
26+
for (let i = 0; i < instrs.length && j < ruleBody.length; i++) {
27+
const instr = instrs[i];
28+
const pat = ruleBody[j];
29+
const actualInstr = instr.object ? instr.object + '.' + instr.id : instr.id;
30+
if (actualInstr === pat) {
31+
j++;
32+
} else {
33+
j = 0;
34+
}
35+
}
36+
return j === ruleBody.length;
37+
}
38+
39+
const matches = {};
40+
for (let i = 0; i < funcs.length; i++) {
41+
const type = funcs[i].signature;
42+
const body = funcs[i].body;
43+
if(funcs[i].name.value=="func_2564"){
44+
debugger;
45+
}
46+
47+
for (const rule of rules) {
48+
if (
49+
matchParams(type?.params || [], rule.param) &&
50+
matchBody(body, rule.body)
51+
) {
52+
if (rule.parsedName) {
53+
if (matches[rule.parsedName] !== undefined) {
54+
throw new Error(
55+
`Rule "${rule.parsedName}" is matching multiple functions: [${matches[rule.parsedName]}, ${funcs[i].name.value}]`
56+
);
57+
}
58+
matches[rule.parsedName] = funcs[i].name.value;
59+
}
60+
}
61+
}
62+
}
63+
64+
for (const rule of rules) {
65+
if (rule.parsedName && !Object.keys(matches).includes(rule.parsedName)) {
66+
throw new Error(`Rule "${rule.parsedName}" is not matching any functions`);
67+
}
68+
}
69+
return matches;
70+
}

electron/rules.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[
2+
{
3+
"parsedName": "main",
4+
"body": [
5+
"get_global",
6+
"i32.const",
7+
"i32.sub",
8+
"tee_local",
9+
"set_global",
10+
"i32.const",
11+
"call",
12+
"i32.const",
13+
"u32.load8_u",
14+
"i32.eqz"
15+
]
16+
}
17+
]

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
},
1919
"dependencies": {
2020
"@jsprismarine/brigadier": "^0.13.1",
21+
"@webassemblyjs/ast": "^1.14.1",
22+
"@webassemblyjs/wasm-parser": "^1.14.1",
2123
"binaryen": "^123.0.0",
2224
"dom-to-image": "^2.6.0",
2325
"express": "^5.1.0",

0 commit comments

Comments
 (0)