/src/wasm3/source/m3_parse.c
Line | Count | Source (jump to first uncovered line) |
1 | | // |
2 | | // m3_parse.c |
3 | | // |
4 | | // Created by Steven Massey on 4/19/19. |
5 | | // Copyright © 2019 Steven Massey. All rights reserved. |
6 | | // |
7 | | |
8 | | #include "m3_env.h" |
9 | | #include "m3_compile.h" |
10 | | #include "m3_exception.h" |
11 | | #include "m3_info.h" |
12 | | |
13 | | |
14 | | M3Result ParseType_Table (IM3Module io_module, bytes_t i_bytes, cbytes_t i_end) |
15 | 0 | { |
16 | 0 | M3Result result = m3Err_none; |
17 | |
|
18 | 0 | return result; |
19 | 0 | } |
20 | | |
21 | | |
22 | | M3Result ParseType_Memory (M3MemoryInfo * o_memory, bytes_t * io_bytes, cbytes_t i_end) |
23 | 852 | { |
24 | 852 | M3Result result = m3Err_none; |
25 | | |
26 | 852 | u8 flag; |
27 | | |
28 | 852 | _ (ReadLEB_u7 (& flag, io_bytes, i_end)); // really a u1 |
29 | 852 | _ (ReadLEB_u32 (& o_memory->initPages, io_bytes, i_end)); |
30 | | |
31 | 851 | o_memory->maxPages = 0; |
32 | 851 | if (flag & (1u << 0)) |
33 | 851 | _ (ReadLEB_u32 (& o_memory->maxPages, io_bytes, i_end)); |
34 | | |
35 | 851 | o_memory->pageSize = 0; |
36 | 851 | if (flag & (1u << 3)) { |
37 | 234 | u32 logPageSize; |
38 | 234 | _ (ReadLEB_u32 (& logPageSize, io_bytes, i_end)); |
39 | 234 | o_memory->pageSize = 1u << logPageSize; |
40 | 234 | } |
41 | | |
42 | 852 | _catch: return result; |
43 | 851 | } |
44 | | |
45 | | |
46 | | M3Result ParseSection_Type (IM3Module io_module, bytes_t i_bytes, cbytes_t i_end) |
47 | 122 | { |
48 | 122 | IM3FuncType ftype = NULL; |
49 | | |
50 | 122 | _try { |
51 | 122 | u32 numTypes; |
52 | 122 | _ (ReadLEB_u32 (& numTypes, & i_bytes, i_end)); m3log (parse, "** Type [%d]", numTypes); |
53 | | |
54 | 122 | _throwif("too many types", numTypes > d_m3MaxSaneTypesCount); |
55 | | |
56 | 122 | if (numTypes) |
57 | 122 | { |
58 | | // table of IM3FuncType (that point to the actual M3FuncType struct in the Environment) |
59 | 122 | io_module->funcTypes = m3_AllocArray (IM3FuncType, numTypes); |
60 | 122 | _throwifnull (io_module->funcTypes); |
61 | 122 | io_module->numFuncTypes = numTypes; |
62 | | |
63 | 245 | for (u32 i = 0; i < numTypes; ++i) |
64 | 131 | { |
65 | 131 | i8 form; |
66 | 131 | _ (ReadLEB_i7 (& form, & i_bytes, i_end)); |
67 | 131 | _throwif (m3Err_wasmMalformed, form != -32); // for Wasm MVP |
68 | | |
69 | 128 | u32 numArgs; |
70 | 128 | _ (ReadLEB_u32 (& numArgs, & i_bytes, i_end)); |
71 | | |
72 | 128 | _throwif (m3Err_tooManyArgsRets, numArgs > d_m3MaxSaneFunctionArgRetCount); |
73 | | #if defined(M3_COMPILER_MSVC) |
74 | | u8 argTypes [d_m3MaxSaneFunctionArgRetCount]; |
75 | | #else |
76 | 127 | u8 argTypes[numArgs+1]; // make ubsan happy |
77 | 127 | #endif |
78 | 2.23k | for (u32 a = 0; a < numArgs; ++a) |
79 | 2.11k | { |
80 | 2.11k | i8 wasmType; |
81 | 2.11k | u8 argType; |
82 | 2.11k | _ (ReadLEB_i7 (& wasmType, & i_bytes, i_end)); |
83 | 2.11k | _ (NormalizeType (& argType, wasmType)); |
84 | | |
85 | 2.10k | argTypes[a] = argType; |
86 | 2.10k | } |
87 | | |
88 | 125 | u32 numRets; |
89 | 125 | _ (ReadLEB_u32 (& numRets, & i_bytes, i_end)); |
90 | 125 | _throwif (m3Err_tooManyArgsRets, (u64)(numRets) + numArgs > d_m3MaxSaneFunctionArgRetCount); |
91 | | |
92 | 125 | _ (AllocFuncType (& ftype, numRets + numArgs)); |
93 | 125 | ftype->numArgs = numArgs; |
94 | 125 | ftype->numRets = numRets; |
95 | | |
96 | 6.21k | for (u32 r = 0; r < numRets; ++r) |
97 | 6.08k | { |
98 | 6.08k | i8 wasmType; |
99 | 6.08k | u8 retType; |
100 | 6.08k | _ (ReadLEB_i7 (& wasmType, & i_bytes, i_end)); |
101 | 6.08k | _ (NormalizeType (& retType, wasmType)); |
102 | | |
103 | 6.08k | ftype->types[r] = retType; |
104 | 6.08k | } |
105 | 123 | memcpy (ftype->types + numRets, argTypes, numArgs); m3log (parse, " type %2d: %s", i, SPrintFuncTypeSignature (ftype)); |
106 | | |
107 | 123 | Environment_AddFuncType (io_module->environment, & ftype); |
108 | 123 | io_module->funcTypes [i] = ftype; |
109 | 123 | ftype = NULL; // ownership transferred to environment |
110 | 123 | } |
111 | 122 | } |
112 | | |
113 | 122 | } _catch: |
114 | | |
115 | 122 | if (result) |
116 | 8 | { |
117 | 8 | m3_Free (ftype); |
118 | | // FIX: M3FuncTypes in the table are leaked |
119 | 8 | m3_Free (io_module->funcTypes); |
120 | 8 | io_module->numFuncTypes = 0; |
121 | 8 | } |
122 | | |
123 | 122 | return result; |
124 | 122 | } |
125 | | |
126 | | |
127 | | M3Result ParseSection_Function (IM3Module io_module, bytes_t i_bytes, cbytes_t i_end) |
128 | 109 | { |
129 | 109 | M3Result result = m3Err_none; |
130 | | |
131 | 109 | u32 numFunctions; |
132 | 109 | _ (ReadLEB_u32 (& numFunctions, & i_bytes, i_end)); m3log (parse, "** Function [%d]", numFunctions); |
133 | | |
134 | 109 | _throwif("too many functions", numFunctions > d_m3MaxSaneFunctionsCount); |
135 | | |
136 | 109 | _ (Module_PreallocFunctions(io_module, io_module->numFunctions + numFunctions)); |
137 | | |
138 | 1.42k | for (u32 i = 0; i < numFunctions; ++i) |
139 | 1.31k | { |
140 | 1.31k | u32 funcTypeIndex; |
141 | 1.31k | _ (ReadLEB_u32 (& funcTypeIndex, & i_bytes, i_end)); |
142 | | |
143 | 1.31k | _ (Module_AddFunction (io_module, funcTypeIndex, NULL /* import info */)); |
144 | 1.31k | } |
145 | | |
146 | 109 | _catch: return result; |
147 | 109 | } |
148 | | |
149 | | |
150 | | M3Result ParseSection_Import (IM3Module io_module, bytes_t i_bytes, cbytes_t i_end) |
151 | 16 | { |
152 | 16 | M3Result result = m3Err_none; |
153 | | |
154 | 16 | M3ImportInfo import = { NULL, NULL }, clearImport = { NULL, NULL }; |
155 | | |
156 | 16 | u32 numImports; |
157 | 16 | _ (ReadLEB_u32 (& numImports, & i_bytes, i_end)); m3log (parse, "** Import [%d]", numImports); |
158 | | |
159 | 16 | _throwif("too many imports", numImports > d_m3MaxSaneImportsCount); |
160 | | |
161 | | // Most imports are functions, so we won't waste much space anyway (if any) |
162 | 16 | _ (Module_PreallocFunctions(io_module, numImports)); |
163 | | |
164 | 2.67k | for (u32 i = 0; i < numImports; ++i) |
165 | 2.67k | { |
166 | 2.67k | u8 importKind; |
167 | | |
168 | 2.67k | _ (Read_utf8 (& import.moduleUtf8, & i_bytes, i_end)); |
169 | 2.66k | _ (Read_utf8 (& import.fieldUtf8, & i_bytes, i_end)); |
170 | 2.66k | _ (Read_u8 (& importKind, & i_bytes, i_end)); m3log (parse, " kind: %d '%s.%s' ", |
171 | 2.66k | (u32) importKind, import.moduleUtf8, import.fieldUtf8); |
172 | 2.66k | switch (importKind) |
173 | 2.66k | { |
174 | 827 | case d_externalKind_function: |
175 | 827 | { |
176 | 827 | u32 typeIndex; |
177 | 827 | _ (ReadLEB_u32 (& typeIndex, & i_bytes, i_end)) |
178 | | |
179 | 827 | _ (Module_AddFunction (io_module, typeIndex, & import)) |
180 | 825 | import = clearImport; |
181 | | |
182 | 825 | io_module->numFuncImports++; |
183 | 825 | } |
184 | 0 | break; |
185 | | |
186 | 982 | case d_externalKind_table: |
187 | | // result = ParseType_Table (& i_bytes, i_end); |
188 | 982 | break; |
189 | | |
190 | 852 | case d_externalKind_memory: |
191 | 852 | { |
192 | 852 | _ (ParseType_Memory (& io_module->memoryInfo, & i_bytes, i_end)); |
193 | 851 | io_module->memoryImported = true; |
194 | 851 | io_module->memoryImport = import; |
195 | 851 | import = clearImport; |
196 | 851 | } |
197 | 0 | break; |
198 | | |
199 | 0 | case d_externalKind_global: |
200 | 0 | { |
201 | 0 | i8 waType; |
202 | 0 | u8 type, isMutable; |
203 | |
|
204 | 0 | _ (ReadLEB_i7 (& waType, & i_bytes, i_end)); |
205 | 0 | _ (NormalizeType (& type, waType)); |
206 | 0 | _ (ReadLEB_u7 (& isMutable, & i_bytes, i_end)); m3log (parse, " global: %s mutable=%d", c_waTypes [type], (u32) isMutable); |
207 | |
|
208 | 0 | IM3Global global; |
209 | 0 | _ (Module_AddGlobal (io_module, & global, type, isMutable, true /* isImport */)); |
210 | 0 | global->import = import; |
211 | 0 | import = clearImport; |
212 | 0 | } |
213 | 0 | break; |
214 | | |
215 | 0 | default: |
216 | 0 | _throw (m3Err_wasmMalformed); |
217 | 2.66k | } |
218 | | |
219 | 2.65k | FreeImportInfo (& import); |
220 | 2.65k | } |
221 | | |
222 | 16 | _catch: |
223 | | |
224 | 16 | FreeImportInfo (& import); |
225 | | |
226 | 16 | return result; |
227 | 16 | } |
228 | | |
229 | | |
230 | | M3Result ParseSection_Export (IM3Module io_module, bytes_t i_bytes, cbytes_t i_end) |
231 | 20 | { |
232 | 20 | M3Result result = m3Err_none; |
233 | 20 | const char * utf8 = NULL; |
234 | | |
235 | 20 | u32 numExports; |
236 | 20 | _ (ReadLEB_u32 (& numExports, & i_bytes, i_end)); m3log (parse, "** Export [%d]", numExports); |
237 | | |
238 | 20 | _throwif("too many exports", numExports > d_m3MaxSaneExportsCount); |
239 | | |
240 | 1.60k | for (u32 i = 0; i < numExports; ++i) |
241 | 1.59k | { |
242 | 1.59k | u8 exportKind; |
243 | 1.59k | u32 index; |
244 | | |
245 | 1.59k | _ (Read_utf8 (& utf8, & i_bytes, i_end)); |
246 | 1.59k | _ (Read_u8 (& exportKind, & i_bytes, i_end)); |
247 | 1.59k | _ (ReadLEB_u32 (& index, & i_bytes, i_end)); m3log (parse, " index: %3d; kind: %d; export: '%s'; ", index, (u32) exportKind, utf8); |
248 | | |
249 | 1.59k | if (exportKind == d_externalKind_function) |
250 | 431 | { |
251 | 431 | _throwif(m3Err_wasmMalformed, index >= io_module->numFunctions); |
252 | 427 | IM3Function func = &(io_module->functions [index]); |
253 | 427 | if (func->numNames < d_m3MaxDuplicateFunctionImpl) |
254 | 103 | { |
255 | 103 | func->names[func->numNames++] = utf8; |
256 | 103 | func->export_name = utf8; |
257 | 103 | utf8 = NULL; // ownership transferred to M3Function |
258 | 103 | } |
259 | 427 | } |
260 | 1.16k | else if (exportKind == d_externalKind_global) |
261 | 243 | { |
262 | 243 | _throwif(m3Err_wasmMalformed, index >= io_module->numGlobals); |
263 | 242 | IM3Global global = &(io_module->globals [index]); |
264 | 242 | m3_Free (global->name); |
265 | 242 | global->name = utf8; |
266 | 242 | utf8 = NULL; // ownership transferred to M3Global |
267 | 242 | } |
268 | 920 | else if (exportKind == d_externalKind_memory) |
269 | 190 | { |
270 | 190 | m3_Free (io_module->memoryExportName); |
271 | 190 | io_module->memoryExportName = utf8; |
272 | 190 | utf8 = NULL; // ownership transferred to M3Module |
273 | 190 | } |
274 | 730 | else if (exportKind == d_externalKind_table) |
275 | 245 | { |
276 | 245 | m3_Free (io_module->table0ExportName); |
277 | 245 | io_module->table0ExportName = utf8; |
278 | 245 | utf8 = NULL; // ownership transferred to M3Module |
279 | 245 | } |
280 | | |
281 | 1.58k | m3_Free (utf8); |
282 | 1.58k | } |
283 | | |
284 | 20 | _catch: |
285 | 20 | m3_Free (utf8); |
286 | 20 | return result; |
287 | 20 | } |
288 | | |
289 | | |
290 | | M3Result ParseSection_Start (IM3Module io_module, bytes_t i_bytes, cbytes_t i_end) |
291 | 1 | { |
292 | 1 | M3Result result = m3Err_none; |
293 | | |
294 | 1 | u32 startFuncIndex; |
295 | 1 | _ (ReadLEB_u32 (& startFuncIndex, & i_bytes, i_end)); m3log (parse, "** Start Function: %d", startFuncIndex); |
296 | | |
297 | 1 | if (startFuncIndex < io_module->numFunctions) |
298 | 1 | { |
299 | 1 | io_module->startFunction = startFuncIndex; |
300 | 1 | } |
301 | 0 | else result = "start function index out of bounds"; |
302 | | |
303 | 1 | _catch: return result; |
304 | 1 | } |
305 | | |
306 | | |
307 | | M3Result Parse_InitExpr (M3Module * io_module, bytes_t * io_bytes, cbytes_t i_end) |
308 | 397 | { |
309 | 397 | M3Result result = m3Err_none; |
310 | | |
311 | | // this doesn't generate code pages. just walks the wasm bytecode to find the end |
312 | | |
313 | | #if defined(d_m3PreferStaticAlloc) |
314 | | static M3Compilation compilation; |
315 | | #else |
316 | 397 | M3Compilation compilation; |
317 | 397 | #endif |
318 | 397 | compilation = (M3Compilation){ .runtime = NULL, .module = io_module, .wasm = * io_bytes, .wasmEnd = i_end }; |
319 | | |
320 | 397 | result = CompileBlockStatements (& compilation); |
321 | | |
322 | 397 | * io_bytes = compilation.wasm; |
323 | | |
324 | 397 | return result; |
325 | 397 | } |
326 | | |
327 | | |
328 | | M3Result ParseSection_Element (IM3Module io_module, bytes_t i_bytes, cbytes_t i_end) |
329 | 1 | { |
330 | 1 | M3Result result = m3Err_none; |
331 | | |
332 | 1 | u32 numSegments; |
333 | 1 | _ (ReadLEB_u32 (& numSegments, & i_bytes, i_end)); m3log (parse, "** Element [%d]", numSegments); |
334 | | |
335 | 1 | _throwif ("too many element segments", numSegments > d_m3MaxSaneElementSegments); |
336 | | |
337 | 1 | io_module->elementSection = i_bytes; |
338 | 1 | io_module->elementSectionEnd = i_end; |
339 | 1 | io_module->numElementSegments = numSegments; |
340 | | |
341 | 1 | _catch: return result; |
342 | 1 | } |
343 | | |
344 | | |
345 | | M3Result ParseSection_Code (M3Module * io_module, bytes_t i_bytes, cbytes_t i_end) |
346 | 86 | { |
347 | 86 | M3Result result; |
348 | | |
349 | 86 | u32 numFunctions; |
350 | 86 | _ (ReadLEB_u32 (& numFunctions, & i_bytes, i_end)); m3log (parse, "** Code [%d]", numFunctions); |
351 | | |
352 | 86 | if (numFunctions != io_module->numFunctions - io_module->numFuncImports) |
353 | 0 | { |
354 | 0 | _throw ("mismatched function count in code section"); |
355 | 0 | } |
356 | | |
357 | 424 | for (u32 f = 0; f < numFunctions; ++f) |
358 | 338 | { |
359 | 338 | const u8 * start = i_bytes; |
360 | | |
361 | 338 | u32 size; |
362 | 338 | _ (ReadLEB_u32 (& size, & i_bytes, i_end)); |
363 | | |
364 | 338 | if (size) |
365 | 86 | { |
366 | 86 | const u8 * ptr = i_bytes; |
367 | 86 | i_bytes += size; |
368 | | |
369 | 86 | if (i_bytes <= i_end) |
370 | 86 | { |
371 | | /* |
372 | | u32 numLocalBlocks; |
373 | | _ (ReadLEB_u32 (& numLocalBlocks, & ptr, i_end)); m3log (parse, " code size: %-4d", size); |
374 | | |
375 | | u32 numLocals = 0; |
376 | | |
377 | | for (u32 l = 0; l < numLocalBlocks; ++l) |
378 | | { |
379 | | u32 varCount; |
380 | | i8 wasmType; |
381 | | u8 normalType; |
382 | | |
383 | | _ (ReadLEB_u32 (& varCount, & ptr, i_end)); |
384 | | _ (ReadLEB_i7 (& wasmType, & ptr, i_end)); |
385 | | _ (NormalizeType (& normalType, wasmType)); |
386 | | |
387 | | numLocals += varCount; m3log (parse, " %2d locals; type: '%s'", varCount, c_waTypes [normalType]); |
388 | | } |
389 | | */ |
390 | | |
391 | 86 | IM3Function func = Module_GetFunction (io_module, f + io_module->numFuncImports); |
392 | | |
393 | 86 | func->module = io_module; |
394 | 86 | func->wasm = start; |
395 | 86 | func->wasmEnd = i_bytes; |
396 | | //func->ownsWasmCode = io_module->hasWasmCodeCopy; |
397 | | // func->numLocals = numLocals; |
398 | 86 | } |
399 | 86 | else _throw (m3Err_wasmSectionOverrun); |
400 | 86 | } |
401 | 338 | } |
402 | | |
403 | 86 | _catch: |
404 | | |
405 | 86 | if (not result and i_bytes != i_end) |
406 | 0 | result = m3Err_wasmSectionUnderrun; |
407 | | |
408 | 86 | return result; |
409 | 86 | } |
410 | | |
411 | | |
412 | | M3Result ParseSection_Data (M3Module * io_module, bytes_t i_bytes, cbytes_t i_end) |
413 | 38 | { |
414 | 38 | M3Result result = m3Err_none; |
415 | | |
416 | 38 | u32 numDataSegments; |
417 | 38 | _ (ReadLEB_u32 (& numDataSegments, & i_bytes, i_end)); m3log (parse, "** Data [%d]", numDataSegments); |
418 | | |
419 | 38 | _throwif("too many data segments", numDataSegments > d_m3MaxSaneDataSegments); |
420 | | |
421 | 38 | io_module->dataSegments = m3_AllocArray (M3DataSegment, numDataSegments); |
422 | 38 | _throwifnull(io_module->dataSegments); |
423 | 38 | io_module->numDataSegments = numDataSegments; |
424 | | |
425 | 125 | for (u32 i = 0; i < numDataSegments; ++i) |
426 | 108 | { |
427 | 108 | M3DataSegment * segment = & io_module->dataSegments [i]; |
428 | | |
429 | 108 | _ (ReadLEB_u32 (& segment->memoryRegion, & i_bytes, i_end)); |
430 | | |
431 | 108 | segment->initExpr = i_bytes; |
432 | 108 | _ (Parse_InitExpr (io_module, & i_bytes, i_end)); |
433 | 89 | segment->initExprSize = (u32) (i_bytes - segment->initExpr); |
434 | | |
435 | 89 | _throwif (m3Err_wasmMissingInitExpr, segment->initExprSize <= 1); |
436 | | |
437 | 89 | _ (ReadLEB_u32 (& segment->size, & i_bytes, i_end)); |
438 | 89 | segment->data = i_bytes; m3log (parse, " segment [%u] memory: %u; expr-size: %d; size: %d", |
439 | 89 | i, segment->memoryRegion, segment->initExprSize, segment->size); |
440 | 89 | i_bytes += segment->size; |
441 | | |
442 | 89 | _throwif("data segment underflow", i_bytes > i_end); |
443 | 87 | } |
444 | | |
445 | 38 | _catch: |
446 | | |
447 | 38 | return result; |
448 | 38 | } |
449 | | |
450 | | |
451 | | M3Result ParseSection_Memory (M3Module * io_module, bytes_t i_bytes, cbytes_t i_end) |
452 | 0 | { |
453 | 0 | M3Result result = m3Err_none; |
454 | | |
455 | | // TODO: MVP; assert no memory imported |
456 | |
|
457 | 0 | u32 numMemories; |
458 | 0 | _ (ReadLEB_u32 (& numMemories, & i_bytes, i_end)); m3log (parse, "** Memory [%d]", numMemories); |
459 | |
|
460 | 0 | _throwif (m3Err_tooManyMemorySections, numMemories != 1); |
461 | |
|
462 | 0 | ParseType_Memory (& io_module->memoryInfo, & i_bytes, i_end); |
463 | |
|
464 | 0 | _catch: return result; |
465 | 0 | } |
466 | | |
467 | | |
468 | | M3Result ParseSection_Global (M3Module * io_module, bytes_t i_bytes, cbytes_t i_end) |
469 | 27 | { |
470 | 27 | M3Result result = m3Err_none; |
471 | | |
472 | 27 | u32 numGlobals; |
473 | 27 | _ (ReadLEB_u32 (& numGlobals, & i_bytes, i_end)); m3log (parse, "** Global [%d]", numGlobals); |
474 | | |
475 | 27 | _throwif("too many globals", numGlobals > d_m3MaxSaneGlobalsCount); |
476 | | |
477 | 307 | for (u32 i = 0; i < numGlobals; ++i) |
478 | 289 | { |
479 | 289 | i8 waType; |
480 | 289 | u8 type, isMutable; |
481 | | |
482 | 289 | _ (ReadLEB_i7 (& waType, & i_bytes, i_end)); |
483 | 289 | _ (NormalizeType (& type, waType)); |
484 | 289 | _ (ReadLEB_u7 (& isMutable, & i_bytes, i_end)); m3log (parse, " global: [%d] %s mutable: %d", i, c_waTypes [type], (u32) isMutable); |
485 | | |
486 | 289 | IM3Global global; |
487 | 289 | _ (Module_AddGlobal (io_module, & global, type, isMutable, false /* isImport */)); |
488 | | |
489 | 289 | global->initExpr = i_bytes; |
490 | 289 | _ (Parse_InitExpr (io_module, & i_bytes, i_end)); |
491 | 280 | global->initExprSize = (u32) (i_bytes - global->initExpr); |
492 | | |
493 | 280 | _throwif (m3Err_wasmMissingInitExpr, global->initExprSize <= 1); |
494 | 280 | } |
495 | | |
496 | 27 | _catch: return result; |
497 | 27 | } |
498 | | |
499 | | |
500 | | M3Result ParseSection_Name (M3Module * io_module, bytes_t i_bytes, cbytes_t i_end) |
501 | 714 | { |
502 | 714 | M3Result result; |
503 | | |
504 | 714 | cstr_t name; |
505 | | |
506 | 1.78k | while (i_bytes < i_end) |
507 | 1.08k | { |
508 | 1.08k | u8 nameType; |
509 | 1.08k | u32 payloadLength; |
510 | | |
511 | 1.08k | _ (ReadLEB_u7 (& nameType, & i_bytes, i_end)); |
512 | 1.07k | _ (ReadLEB_u32 (& payloadLength, & i_bytes, i_end)); |
513 | | |
514 | 1.07k | bytes_t start = i_bytes; |
515 | 1.07k | if (nameType == 1) |
516 | 549 | { |
517 | 549 | u32 numNames; |
518 | 549 | _ (ReadLEB_u32 (& numNames, & i_bytes, i_end)); |
519 | | |
520 | 549 | _throwif("too many names", numNames > d_m3MaxSaneFunctionsCount); |
521 | | |
522 | 3.79k | for (u32 i = 0; i < numNames; ++i) |
523 | 3.25k | { |
524 | 3.25k | u32 index; |
525 | 3.25k | _ (ReadLEB_u32 (& index, & i_bytes, i_end)); |
526 | 3.25k | _ (Read_utf8 (& name, & i_bytes, i_end)); |
527 | | |
528 | 3.25k | if (index < io_module->numFunctions) |
529 | 1.17k | { |
530 | 1.17k | IM3Function func = &(io_module->functions [index]); |
531 | 1.17k | if (func->numNames == 0) |
532 | 147 | { |
533 | 147 | func->names[0] = name; m3log (parse, " naming function%5d: %s", index, name); |
534 | 147 | func->numNames = 1; |
535 | 147 | name = NULL; // transfer ownership |
536 | 147 | } |
537 | | // else m3log (parse, "prenamed: %s", io_module->functions [index].name); |
538 | 1.17k | } |
539 | | |
540 | 3.25k | m3_Free (name); |
541 | 3.25k | } |
542 | 549 | } |
543 | | |
544 | 1.06k | i_bytes = start + payloadLength; |
545 | 1.06k | } |
546 | | |
547 | 714 | _catch: return result; |
548 | 714 | } |
549 | | |
550 | | |
551 | | M3Result ParseSection_Custom (M3Module * io_module, bytes_t i_bytes, cbytes_t i_end) |
552 | 1.39k | { |
553 | 1.39k | M3Result result; |
554 | | |
555 | 1.39k | cstr_t name; |
556 | 1.39k | _ (Read_utf8 (& name, & i_bytes, i_end)); |
557 | 1.38k | m3log (parse, "** Custom: '%s'", name); |
558 | 1.38k | if (strcmp (name, "name") == 0) { |
559 | 714 | _ (ParseSection_Name(io_module, i_bytes, i_end)); |
560 | 700 | } else if (io_module->environment->customSectionHandler) { |
561 | 0 | _ (io_module->environment->customSectionHandler(io_module, name, i_bytes, i_end)); |
562 | 0 | } |
563 | | |
564 | 1.37k | m3_Free (name); |
565 | | |
566 | 1.39k | _catch: return result; |
567 | 1.37k | } |
568 | | |
569 | | |
570 | | M3Result ParseModuleSection (M3Module * o_module, u8 i_sectionType, bytes_t i_bytes, u32 i_numBytes) |
571 | 1.81k | { |
572 | 1.81k | M3Result result = m3Err_none; |
573 | | |
574 | 1.81k | typedef M3Result (* M3Parser) (M3Module *, bytes_t, cbytes_t); |
575 | | |
576 | 1.81k | static M3Parser s_parsers [] = |
577 | 1.81k | { |
578 | 1.81k | ParseSection_Custom, // 0 |
579 | 1.81k | ParseSection_Type, // 1 |
580 | 1.81k | ParseSection_Import, // 2 |
581 | 1.81k | ParseSection_Function, // 3 |
582 | 1.81k | NULL, // 4: TODO Table |
583 | 1.81k | ParseSection_Memory, // 5 |
584 | 1.81k | ParseSection_Global, // 6 |
585 | 1.81k | ParseSection_Export, // 7 |
586 | 1.81k | ParseSection_Start, // 8 |
587 | 1.81k | ParseSection_Element, // 9 |
588 | 1.81k | ParseSection_Code, // 10 |
589 | 1.81k | ParseSection_Data, // 11 |
590 | 1.81k | NULL, // 12: TODO DataCount |
591 | 1.81k | }; |
592 | | |
593 | 1.81k | M3Parser parser = NULL; |
594 | | |
595 | 1.81k | if (i_sectionType <= 12) |
596 | 1.81k | parser = s_parsers [i_sectionType]; |
597 | | |
598 | 1.81k | if (parser) |
599 | 1.81k | { |
600 | 1.81k | cbytes_t end = i_bytes + i_numBytes; |
601 | 1.81k | result = parser (o_module, i_bytes, end); |
602 | 1.81k | } |
603 | 0 | else |
604 | 0 | { |
605 | 0 | m3log (parse, " skipped section type: %d", (u32) i_sectionType); |
606 | 0 | } |
607 | | |
608 | 1.81k | return result; |
609 | 1.81k | } |
610 | | |
611 | | |
612 | | M3Result m3_ParseModule (IM3Environment i_environment, IM3Module * o_module, cbytes_t i_bytes, u32 i_numBytes) |
613 | 228 | { |
614 | 228 | IM3Module module; m3log (parse, "load module: %d bytes", i_numBytes); |
615 | 228 | _try { |
616 | 228 | module = m3_AllocStruct (M3Module); |
617 | 228 | _throwifnull (module); |
618 | 228 | module->name = ".unnamed"; m3log (parse, "load module: %d bytes", i_numBytes); |
619 | 228 | module->startFunction = -1; |
620 | | //module->hasWasmCodeCopy = false; |
621 | 228 | module->environment = i_environment; |
622 | | |
623 | 228 | const u8 * pos = i_bytes; |
624 | 228 | const u8 * end = pos + i_numBytes; |
625 | | |
626 | 228 | module->wasmStart = pos; |
627 | 228 | module->wasmEnd = end; |
628 | | |
629 | 228 | u32 magic, version; |
630 | 228 | _ (Read_u32 (& magic, & pos, end)); |
631 | 228 | _ (Read_u32 (& version, & pos, end)); |
632 | | |
633 | 228 | _throwif (m3Err_wasmMalformed, magic != 0x6d736100); |
634 | 224 | _throwif (m3Err_incompatibleWasmVersion, version != 1); |
635 | | |
636 | 213 | static const u8 sectionsOrder[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 10, 11, 0 }; // 0 is a placeholder |
637 | 213 | u8 expectedSection = 0; |
638 | | |
639 | 1.94k | while (pos < end) |
640 | 1.81k | { |
641 | 1.81k | u8 section; |
642 | 1.81k | _ (ReadLEB_u7 (& section, & pos, end)); |
643 | | |
644 | 1.81k | if (section != 0) { |
645 | | // Ensure sections appear only once and in order |
646 | 1.73k | while (sectionsOrder[expectedSection++] != section) { |
647 | 1.31k | _throwif(m3Err_misorderedWasmSection, expectedSection >= 12); |
648 | 1.31k | } |
649 | 424 | } |
650 | | |
651 | 1.81k | u32 sectionLength; |
652 | 1.81k | _ (ReadLEB_u32 (& sectionLength, & pos, end)); |
653 | 1.81k | _throwif(m3Err_wasmMalformed, pos + sectionLength > end); |
654 | | |
655 | 1.81k | _ (ParseModuleSection (module, section, pos, sectionLength)); |
656 | | |
657 | 1.73k | pos += sectionLength; |
658 | 1.73k | } |
659 | | |
660 | 228 | } _catch: |
661 | | |
662 | 228 | if (result) |
663 | 100 | { |
664 | 100 | m3_FreeModule (module); |
665 | 100 | module = NULL; |
666 | 100 | } |
667 | | |
668 | 228 | * o_module = module; |
669 | | |
670 | 228 | return result; |
671 | 213 | } |