1 | /* |
2 | * Copyright 2017 WebAssembly Community Group participants |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | // |
18 | // Emit a JavaScript wrapper to run a wasm module with some test |
19 | // values, useful for fuzzing. |
20 | // |
21 | |
22 | #include "wasm-type.h" |
23 | #include "wasm.h" |
24 | #include <string> |
25 | |
26 | namespace wasm { |
27 | |
28 | inline std::string generateJSWrapper(Module& wasm) { |
29 | std::string ret; |
30 | ret += "if (typeof console === 'undefined') {\n" |
31 | " console = { log: print };\n" |
32 | "}\n" |
33 | "var tempRet0;\n" |
34 | "var binary;\n" |
35 | "if (typeof process === 'object' && typeof require === 'function' /* " |
36 | "node.js detection */) {\n" |
37 | " var args = process.argv.slice(2);\n" |
38 | " binary = require('fs').readFileSync(args[0]);\n" |
39 | " if (!binary.buffer) binary = new Uint8Array(binary);\n" |
40 | "} else {\n" |
41 | " var args;\n" |
42 | " if (typeof scriptArgs != 'undefined') {\n" |
43 | " args = scriptArgs;\n" |
44 | " } else if (typeof arguments != 'undefined') {\n" |
45 | " args = arguments;\n" |
46 | " }\n" |
47 | " if (typeof readbuffer === 'function') {\n" |
48 | " binary = new Uint8Array(readbuffer(args[0]));\n" |
49 | " } else {\n" |
50 | " binary = read(args[0], 'binary');\n" |
51 | " }\n" |
52 | "}\n" |
53 | "function literal(x, type) {\n" |
54 | " var ret = '';\n" |
55 | " switch (type) {\n" |
56 | " case 'i32': ret += (x | 0); break;\n" |
57 | " case 'f32':\n" |
58 | " case 'f64': {\n" |
59 | " if (x == 0 && (1 / x) < 0) ret += '-';\n" |
60 | " ret += Number(x).toString();\n" |
61 | " break;\n" |
62 | " }\n" |
63 | " // For anything else, just print the type.\n" |
64 | " default: ret += type; break;\n" |
65 | " }\n" |
66 | " return ret;\n" |
67 | "}\n" |
68 | "var instance = new WebAssembly.Instance(new " |
69 | "WebAssembly.Module(binary), {\n" |
70 | " 'fuzzing-support': {\n" |
71 | " 'log-i32': function(x) { " |
72 | "console.log('[LoggingExternalInterface logging ' + literal(x, 'i32') " |
73 | "+ ']') },\n" |
74 | " 'log-i64': function(x, y) { " |
75 | "console.log('[LoggingExternalInterface logging ' + literal(x, 'i32') " |
76 | "+ ' ' + literal(y, 'i32') + ']') },\n" // legalization: two i32s |
77 | " 'log-f32': function(x) { " |
78 | "console.log('[LoggingExternalInterface logging ' + literal(x, 'f64') " |
79 | "+ ']') },\n" // legalization: an f64 |
80 | " 'log-f64': function(x) { " |
81 | "console.log('[LoggingExternalInterface logging ' + literal(x, 'f64') " |
82 | "+ ']') },\n" |
83 | " },\n" |
84 | " 'env': {\n" |
85 | " 'setTempRet0': function(x) { tempRet0 = x },\n" |
86 | " 'getTempRet0': function() { return tempRet0 },\n" |
87 | " },\n" |
88 | "});\n" ; |
89 | for (auto& exp : wasm.exports) { |
90 | if (exp->kind != ExternalKind::Function) { |
91 | continue; // something exported other than a function |
92 | } |
93 | auto* func = wasm.getFunction(exp->value); |
94 | ret += "try {\n" ; |
95 | ret += std::string(" console.log('[fuzz-exec] calling " ) + |
96 | exp->name.toString() + "');\n" ; |
97 | if (func->getResults() != Type::none) { |
98 | ret += std::string(" console.log('[fuzz-exec] note result: " ) + |
99 | exp->name.toString() + " => ' + literal(" ; |
100 | } else { |
101 | ret += " " ; |
102 | } |
103 | ret += std::string("instance.exports." ) + exp->name.toString() + "(" ; |
104 | bool first = true; |
105 | for (auto param : func->getParams()) { |
106 | // zeros in arguments TODO more? |
107 | if (first) { |
108 | first = false; |
109 | } else { |
110 | ret += ", " ; |
111 | } |
112 | if (param.isRef()) { |
113 | ret += "null" ; |
114 | } else { |
115 | ret += "0" ; |
116 | if (param == Type::i64) { |
117 | ret += ", 0" ; |
118 | } |
119 | } |
120 | } |
121 | ret += ")" ; |
122 | if (func->getResults() != Type::none) { |
123 | ret += ", '" + func->getResults().toString() + "'))" ; |
124 | // TODO: getTempRet |
125 | } |
126 | ret += ";\n" ; |
127 | ret += "} catch (e) {\n" ; |
128 | ret += " console.log('exception!' /* + e */);\n" ; |
129 | ret += "}\n" ; |
130 | } |
131 | return ret; |
132 | } |
133 | |
134 | } // namespace wasm |
135 | |