1 /* Capstone Disassembly Engine */
2 /* By Spike, xwings 2019 */
3 
4 #include <string.h>
5 #include <stddef.h> // offsetof macro
6 // alternatively #include "../../utils.h" like everyone else
7 
8 #include "WASMDisassembler.h"
9 #include "WASMMapping.h"
10 #include "../../cs_priv.h"
11 
12 static const short opcodes[256] = {
13 	WASM_INS_UNREACHABLE,
14 	WASM_INS_NOP,
15 	WASM_INS_BLOCK,
16 	WASM_INS_LOOP,
17 	WASM_INS_IF,
18 	WASM_INS_ELSE,
19 	-1,
20 	-1,
21 	-1,
22 	-1,
23 	-1,
24 	WASM_INS_END,
25 	WASM_INS_BR,
26 	WASM_INS_BR_IF,
27 	WASM_INS_BR_TABLE,
28 	WASM_INS_RETURN,
29 	WASM_INS_CALL,
30 	WASM_INS_CALL_INDIRECT,
31 	-1,
32 	-1,
33 	-1,
34 	-1,
35 	-1,
36 	-1,
37 	-1,
38 	-1,
39 	WASM_INS_DROP,
40 	WASM_INS_SELECT,
41 	-1,
42 	-1,
43 	-1,
44 	-1,
45 	WASM_INS_GET_LOCAL,
46 	WASM_INS_SET_LOCAL,
47 	WASM_INS_TEE_LOCAL,
48 	WASM_INS_GET_GLOBAL,
49 	WASM_INS_SET_GLOBAL,
50 	-1,
51 	-1,
52 	-1,
53 	WASM_INS_I32_LOAD,
54 	WASM_INS_I64_LOAD,
55 	WASM_INS_F32_LOAD,
56 	WASM_INS_F64_LOAD,
57 	WASM_INS_I32_LOAD8_S,
58 	WASM_INS_I32_LOAD8_U,
59 	WASM_INS_I32_LOAD16_S,
60 	WASM_INS_I32_LOAD16_U,
61 	WASM_INS_I64_LOAD8_S,
62 	WASM_INS_I64_LOAD8_U,
63 	WASM_INS_I64_LOAD16_S,
64 	WASM_INS_I64_LOAD16_U,
65 	WASM_INS_I64_LOAD32_S,
66 	WASM_INS_I64_LOAD32_U,
67 	WASM_INS_I32_STORE,
68 	WASM_INS_I64_STORE,
69 	WASM_INS_F32_STORE,
70 	WASM_INS_F64_STORE,
71 	WASM_INS_I32_STORE8,
72 	WASM_INS_I32_STORE16,
73 	WASM_INS_I64_STORE8,
74 	WASM_INS_I64_STORE16,
75 	WASM_INS_I64_STORE32,
76 	WASM_INS_CURRENT_MEMORY,
77 	WASM_INS_GROW_MEMORY,
78 	WASM_INS_I32_CONST,
79 	WASM_INS_I64_CONST,
80 	WASM_INS_F32_CONST,
81 	WASM_INS_F64_CONST,
82 	WASM_INS_I32_EQZ,
83 	WASM_INS_I32_EQ,
84 	WASM_INS_I32_NE,
85 	WASM_INS_I32_LT_S,
86 	WASM_INS_I32_LT_U,
87 	WASM_INS_I32_GT_S,
88 	WASM_INS_I32_GT_U,
89 	WASM_INS_I32_LE_S,
90 	WASM_INS_I32_LE_U,
91 	WASM_INS_I32_GE_S,
92 	WASM_INS_I32_GE_U,
93 	WASM_INS_I64_EQZ,
94 	WASM_INS_I64_EQ,
95 	WASM_INS_I64_NE,
96 	WASM_INS_I64_LT_S,
97 	WASM_INS_I64_LT_U,
98 	WASN_INS_I64_GT_S,
99 	WASM_INS_I64_GT_U,
100 	WASM_INS_I64_LE_S,
101 	WASM_INS_I64_LE_U,
102 	WASM_INS_I64_GE_S,
103 	WASM_INS_I64_GE_U,
104 	WASM_INS_F32_EQ,
105 	WASM_INS_F32_NE,
106 	WASM_INS_F32_LT,
107 	WASM_INS_F32_GT,
108 	WASM_INS_F32_LE,
109 	WASM_INS_F32_GE,
110 	WASM_INS_F64_EQ,
111 	WASM_INS_F64_NE,
112 	WASM_INS_F64_LT,
113 	WASM_INS_F64_GT,
114 	WASM_INS_F64_LE,
115 	WASM_INS_F64_GE,
116 	WASM_INS_I32_CLZ,
117 	WASM_INS_I32_CTZ,
118 	WASM_INS_I32_POPCNT,
119 	WASM_INS_I32_ADD,
120 	WASM_INS_I32_SUB,
121 	WASM_INS_I32_MUL,
122 	WASM_INS_I32_DIV_S,
123 	WASM_INS_I32_DIV_U,
124 	WASM_INS_I32_REM_S,
125 	WASM_INS_I32_REM_U,
126 	WASM_INS_I32_AND,
127 	WASM_INS_I32_OR,
128 	WASM_INS_I32_XOR,
129 	WASM_INS_I32_SHL,
130 	WASM_INS_I32_SHR_S,
131 	WASM_INS_I32_SHR_U,
132 	WASM_INS_I32_ROTL,
133 	WASM_INS_I32_ROTR,
134 	WASM_INS_I64_CLZ,
135 	WASM_INS_I64_CTZ,
136 	WASM_INS_I64_POPCNT,
137 	WASM_INS_I64_ADD,
138 	WASM_INS_I64_SUB,
139 	WASM_INS_I64_MUL,
140 	WASM_INS_I64_DIV_S,
141 	WASM_INS_I64_DIV_U,
142 	WASM_INS_I64_REM_S,
143 	WASM_INS_I64_REM_U,
144 	WASM_INS_I64_AND,
145 	WASM_INS_I64_OR,
146 	WASM_INS_I64_XOR,
147 	WASM_INS_I64_SHL,
148 	WASM_INS_I64_SHR_S,
149 	WASM_INS_I64_SHR_U,
150 	WASM_INS_I64_ROTL,
151 	WASM_INS_I64_ROTR,
152 	WASM_INS_F32_ABS,
153 	WASM_INS_F32_NEG,
154 	WASM_INS_F32_CEIL,
155 	WASM_INS_F32_FLOOR,
156 	WASM_INS_F32_TRUNC,
157 	WASM_INS_F32_NEAREST,
158 	WASM_INS_F32_SQRT,
159 	WASM_INS_F32_ADD,
160 	WASM_INS_F32_SUB,
161 	WASM_INS_F32_MUL,
162 	WASM_INS_F32_DIV,
163 	WASM_INS_F32_MIN,
164 	WASM_INS_F32_MAX,
165 	WASM_INS_F32_COPYSIGN,
166 	WASM_INS_F64_ABS,
167 	WASM_INS_F64_NEG,
168 	WASM_INS_F64_CEIL,
169 	WASM_INS_F64_FLOOR,
170 	WASM_INS_F64_TRUNC,
171 	WASM_INS_F64_NEAREST,
172 	WASM_INS_F64_SQRT,
173 	WASM_INS_F64_ADD,
174 	WASM_INS_F64_SUB,
175 	WASM_INS_F64_MUL,
176 	WASM_INS_F64_DIV,
177 	WASM_INS_F64_MIN,
178 	WASM_INS_F64_MAX,
179 	WASM_INS_F64_COPYSIGN,
180 	WASM_INS_I32_WARP_I64,
181 	WASP_INS_I32_TRUNC_S_F32,
182 	WASM_INS_I32_TRUNC_U_F32,
183 	WASM_INS_I32_TRUNC_S_F64,
184 	WASM_INS_I32_TRUNC_U_F64,
185 	WASM_INS_I64_EXTEND_S_I32,
186 	WASM_INS_I64_EXTEND_U_I32,
187 	WASM_INS_I64_TRUNC_S_F32,
188 	WASM_INS_I64_TRUNC_U_F32,
189 	WASM_INS_I64_TRUNC_S_F64,
190 	WASM_INS_I64_TRUNC_U_F64,
191 	WASM_INS_F32_CONVERT_S_I32,
192 	WASM_INS_F32_CONVERT_U_I32,
193 	WASM_INS_F32_CONVERT_S_I64,
194 	WASM_INS_F32_CONVERT_U_I64,
195 	WASM_INS_F32_DEMOTE_F64,
196 	WASM_INS_F64_CONVERT_S_I32,
197 	WASM_INS_F64_CONVERT_U_I32,
198 	WASM_INS_F64_CONVERT_S_I64,
199 	WASM_INS_F64_CONVERT_U_I64,
200 	WASM_INS_F64_PROMOTE_F32,
201 	WASM_INS_I32_REINTERPRET_F32,
202 	WASM_INS_I64_REINTERPRET_F64,
203 	WASM_INS_F32_REINTERPRET_I32,
204 	WASM_INS_F64_REINTERPRET_I64,
205 	-1,
206 	-1,
207 	-1,
208 	-1,
209 	-1,
210 	-1,
211 	-1,
212 	-1,
213 	-1,
214 	-1,
215 	-1,
216 	-1,
217 	-1,
218 	-1,
219 	-1,
220 	-1,
221 	-1,
222 	-1,
223 	-1,
224 	-1,
225 	-1,
226 	-1,
227 	-1,
228 	-1,
229 	-1,
230 	-1,
231 	-1,
232 	-1,
233 	-1,
234 	-1,
235 	-1,
236 	-1,
237 	-1,
238 	-1,
239 	-1,
240 	-1,
241 	-1,
242 	-1,
243 	-1,
244 	-1,
245 	-1,
246 	-1,
247 	-1,
248 	-1,
249 	-1,
250 	-1,
251 	-1,
252 	-1,
253 	-1,
254 	-1,
255 	-1,
256 	-1,
257 	-1,
258 	-1,
259 	-1,
260 	-1,
261 	-1,
262 	-1,
263 	-1,
264 	-1,
265 	-1,
266 	-1,
267 	-1,
268 	-1,
269 };
270 
271 // input 	| code: code pointer start from varuint32
272 //       	| code_len: real code len count from varint
273 //       	| leng: return value, means length of varint. -1 means error
274 // return	| varint
275 static uint32_t get_varuint32(const uint8_t *code, size_t code_len, size_t *leng)
276 {
277 	uint32_t data = 0;
278 	int i;
279 
280 	for(i = 0;; i++) {
281 		if (code_len < i + 1) {
282 			*leng = -1;
283 			return 0;
284 		}
285 
286 
287 		if (i > 4 || (i == 4 && (code[i] & 0x7f) > 0x0f)) {
288 			*leng = -1;
289 			return 0;
290 		}
291 
292 		data = data + (((uint32_t) code[i] & 0x7f) << (i * 7));
293 		if (code[i] >> 7 == 0) {
294 			break;
295 		}
296 	}
297 
298 	*leng = i + 1;
299 
300 	return data;
301 }
302 
303 // input 	| code : code pointer start from varuint64
304 //       	| code_len : real code len count from varint
305 //       	| leng: return value, means length of varint. -1 means error
306 // return 	| varint
307 static uint64_t get_varuint64(const uint8_t *code, size_t code_len, size_t *leng)
308 {
309 	uint64_t data;
310 	int i;
311 
312 	data = 0;
313 	for(i = 0;; i++){
314 		if (code_len < i + 1) {
315 			*leng = -1;
316 			return 0;
317 		}
318 
319 		if (i > 9 || (i == 9 && (code[i] & 0x7f) > 0x01)) {
320 			*leng = -1;
321 			return 0;
322 		}
323 
324 		data = data + (((uint64_t) code[i] & 0x7f) << (i * 7));
325 		if (code[i] >> 7 == 0) {
326 			break;
327 		}
328 	}
329 
330 	*leng = i + 1;
331 
332 	return data;
333 }
334 
335 // input	| code : code pointer start from uint32
336 //			| dest : the pointer where we store the uint32
337 // return	| None
338 static void get_uint32(const uint8_t *code, uint32_t *dest)
339 {
340 	memcpy(dest, code, 4);
341 }
342 
343 // input	| code : code pointer start from uint32
344 // 			| dest : the pointer where we store the uint64
345 // return 	| None
346 static void get_uint64(const uint8_t *code, uint64_t *dest)
347 {
348 	memcpy(dest, code, 8);
349 }
350 
351 // input	| code : code pointer start from varint7
352 // 			| code_len : start from the code pointer to the end, how long is it
353 // 			| leng : length of the param , -1 means error
354 // return 	| data of varint7
355 static int8_t get_varint7(const uint8_t *code, size_t code_len, size_t *leng)
356 {
357 	int8_t data;
358 
359 	if (code_len < 1) {
360 		*leng = -1;
361 		return -1;
362 	}
363 
364 	*leng = 1;
365 
366 	if (code[0] == 0x40) {
367 		return -1;
368 	}
369 
370 	data = code[0] & 0x7f;
371 
372 	return data;
373 }
374 
375 // input 	| code : code pointer start from varuint32
376 // 			| code_len : start from the code pointer to the end, how long is it
377 // 			| param_size : pointer of the param size
378 // 			| MI : Mcinst handler in this round of disasm
379 // return 	| true/false if the function successfully finished
380 static bool read_varuint32(const uint8_t *code, size_t code_len, uint16_t *param_size, MCInst *MI)
381 {
382 	size_t len = 0;
383 	uint32_t data;
384 
385 	data = get_varuint32(code, code_len, &len);
386 	if (len == -1) {
387 		return false;
388 	}
389 
390 	if (MI->flat_insn->detail) {
391 		MI->flat_insn->detail->wasm.op_count = 1;
392 		MI->flat_insn->detail->wasm.operands[0].type = WASM_OP_VARUINT32;
393 		MI->flat_insn->detail->wasm.operands[0].size= len;
394 		MI->flat_insn->detail->wasm.operands[0].varuint32= data;
395 	}
396 
397 	MI->wasm_data.size = len;
398 	MI->wasm_data.type = WASM_OP_VARUINT32;
399 	MI->wasm_data.uint32 = data;
400 	*param_size = len;
401 
402 	return true;
403 }
404 
405 // input 	| code : code pointer start from varuint64
406 // 			| code_len : start from the code pointer to the end, how long is it
407 // 			| param_size : pointer of the param size
408 // 			| MI : Mcinst handler in this round of disasm
409 // return 	| true/false if the function successfully finished
410 static bool read_varuint64(const uint8_t *code, size_t code_len, uint16_t *param_size, MCInst *MI)
411 {
412 	size_t len = 0;
413 	uint64_t data;
414 
415 	data = get_varuint64(code, code_len, &len);
416 	if (len == -1) {
417 		return false;
418 	}
419 
420 	if (MI->flat_insn->detail) {
421 		MI->flat_insn->detail->wasm.op_count = 1;
422 		MI->flat_insn->detail->wasm.operands[0].type = WASM_OP_VARUINT64;
423 		MI->flat_insn->detail->wasm.operands[0].size = len;
424 		MI->flat_insn->detail->wasm.operands[0].varuint64 = data;
425 	}
426 
427 	MI->wasm_data.size = len;
428 	MI->wasm_data.type = WASM_OP_VARUINT64;
429 	MI->wasm_data.uint64 = data;
430 	*param_size = len;
431 
432 	return true;
433 }
434 
435 // input 	| code : code pointer start from memoryimmediate
436 // 			| code_len : start from the code pointer to the end, how long is it
437 // 			| param_size : pointer of the param size (sum of two params)
438 // 			| MI : Mcinst handler in this round of disasm
439 // return 	| true/false if the function successfully finished
440 static bool read_memoryimmediate(const uint8_t *code, size_t code_len, uint16_t *param_size, MCInst *MI)
441 {
442 	size_t tmp, len = 0;
443 	uint32_t data[2];
444 
445 	if (MI->flat_insn->detail) {
446 		MI->flat_insn->detail->wasm.op_count = 2;
447 	}
448 
449 	data[0] = get_varuint32(code, code_len, &tmp);
450 	if (tmp == -1) {
451 		return false;
452 	}
453 
454 	if (MI->flat_insn->detail) {
455 		MI->flat_insn->detail->wasm.operands[0].type = WASM_OP_VARUINT32;
456 		MI->flat_insn->detail->wasm.operands[0].size = tmp;
457 		MI->flat_insn->detail->wasm.operands[0].varuint32 = data[0];
458 	}
459 
460 	len = tmp;
461 	data[1] = get_varuint32(&code[len], code_len - len, &tmp);
462 	if (len == -1) {
463 		return false;
464 	}
465 
466 	if (MI->flat_insn->detail) {
467 		MI->flat_insn->detail->wasm.operands[1].type = WASM_OP_VARUINT32;
468 		MI->flat_insn->detail->wasm.operands[1].size = tmp;
469 		MI->flat_insn->detail->wasm.operands[1].varuint32 = data[1];
470 	}
471 
472 	len += tmp;
473 	MI->wasm_data.size = len;
474 	MI->wasm_data.type = WASM_OP_IMM;
475 	MI->wasm_data.immediate[0] = data[0];
476 	MI->wasm_data.immediate[1] = data[1];
477 	*param_size = len;
478 
479 	return true;
480 }
481 
482 // input 	| code : code pointer start from uint32
483 // 			| code_len : start from the code pointer to the end, how long is it
484 // 			| param_size : pointer of the param size
485 // 			| MI : Mcinst handler in this round of disasm
486 // return 	| true/false if the function successfully finished
487 static bool read_uint32(const uint8_t *code, size_t code_len, uint16_t *param_size, MCInst *MI)
488 {
489 	if (code_len < 4) {
490 		return false;
491 	}
492 
493 	get_uint32(code, &(MI->wasm_data.uint32));
494 
495 	if (MI->flat_insn->detail) {
496 		MI->flat_insn->detail->wasm.op_count = 1;
497 		MI->flat_insn->detail->wasm.operands[0].type = WASM_OP_UINT32;
498 		MI->flat_insn->detail->wasm.operands[0].size = 4;
499 		get_uint32(code, &(MI->flat_insn->detail->wasm.operands[0].uint32));
500 	}
501 
502 	MI->wasm_data.size = 4;
503 	MI->wasm_data.type = WASM_OP_UINT32;
504 	*param_size = 4;
505 
506 	return true;
507 }
508 
509 // input 	| code : code pointer start from uint64
510 // 			| code_len : start from the code pointer to the end, how long is it
511 // 			| param_size : pointer of the param size
512 // 			| MI : Mcinst handler in this round of disasm
513 // return 	| true/false if the function successfully finished
514 static bool read_uint64(const uint8_t *code, size_t code_len, uint16_t *param_size, MCInst *MI)
515 {
516 	if (code_len < 8) {
517 		return false;
518 	}
519 
520 	get_uint64(code, &(MI->wasm_data.uint64));
521 
522 	if (MI->flat_insn->detail) {
523 		MI->flat_insn->detail->wasm.op_count = 1;
524 		MI->flat_insn->detail->wasm.operands[0].type = WASM_OP_UINT64;
525 		MI->flat_insn->detail->wasm.operands[0].size = 8;
526 		get_uint64(code, &(MI->flat_insn->detail->wasm.operands[0].uint64));
527 	}
528 
529 	MI->wasm_data.size = 8;
530 	MI->wasm_data.type = WASM_OP_UINT64;
531 	*param_size = 8;
532 
533 	return true;
534 }
535 
536 // input 	| code : code pointer start from brtable
537 // 			| code_len : start from the code pointer to the end, how long is it
538 // 			| param_size : pointer of the param size (sum of all param)
539 // 			| MI : Mcinst handler in this round of disasm
540 // return 	| true/false if the function successfully finished
541 static bool read_brtable(const uint8_t *code, size_t code_len, uint16_t *param_size, MCInst *MI)
542 {
543 	uint32_t length, default_target;
544 	int tmp_len = 0, i;
545 	size_t var_len;
546 
547 	// read length
548 	length = get_varuint32(code, code_len, &var_len);
549 	if (var_len == -1) {
550 		return false;
551 	}
552 
553 	tmp_len += var_len;
554 	MI->wasm_data.brtable.length = length;
555 	if (length >= UINT32_MAX - tmp_len) {
556 		// integer overflow check
557 		return false;
558 	}
559 	if (code_len < tmp_len + length) {
560 		// safety check that we have minimum enough data to read
561 		return false;
562 	}
563 	// base address + 1 byte opcode + tmp_len for number of cases = start of targets
564 	MI->wasm_data.brtable.address = MI->address + 1 + tmp_len;
565 
566 	if (MI->flat_insn->detail) {
567 		MI->flat_insn->detail->wasm.op_count = 1;
568 		MI->flat_insn->detail->wasm.operands[0].type = WASM_OP_BRTABLE;
569 		MI->flat_insn->detail->wasm.operands[0].brtable.length = MI->wasm_data.brtable.length;
570 		MI->flat_insn->detail->wasm.operands[0].brtable.address = MI->wasm_data.brtable.address;
571 	}
572 
573 	// read data
574 	for(i = 0; i < length; i++){
575 		if (code_len < tmp_len) {
576 			return false;
577 		}
578 
579 		get_varuint32(code + tmp_len, code_len - tmp_len, &var_len);
580 		if (var_len == -1) {
581 			return false;
582 		}
583 
584 		tmp_len += var_len;
585 	}
586 
587 	// read default target
588 	default_target = get_varuint32(code + tmp_len, code_len - tmp_len, &var_len);
589 	if (var_len == -1) {
590 		return false;
591 	}
592 
593 	MI->wasm_data.brtable.default_target = default_target;
594 	MI->wasm_data.type = WASM_OP_BRTABLE;
595 	*param_size = tmp_len + var_len;
596 
597 	if (MI->flat_insn->detail) {
598 		MI->flat_insn->detail->wasm.operands[0].size = *param_size;
599 		MI->flat_insn->detail->wasm.operands[0].brtable.default_target = MI->wasm_data.brtable.default_target;
600 	}
601 
602 	return true;
603 }
604 
605 // input 	| code : code pointer start from varint7
606 // 			| code_len : start from the code pointer to the end, how long is it
607 // 			| param_size : pointer of the param size
608 // 			| MI : Mcinst handler in this round of disasm
609 // return 	| true/false if the function successfully finished
610 static bool read_varint7(const uint8_t *code, size_t code_len, uint16_t *param_size, MCInst *MI)
611 {
612 	size_t len = 0;
613 
614 	MI->wasm_data.type = WASM_OP_INT7;
615 	MI->wasm_data.int7 = get_varint7(code, code_len, &len);
616 	if (len == -1) {
617 		return false;
618 	}
619 
620 	if (MI->flat_insn->detail) {
621 		MI->flat_insn->detail->wasm.op_count = 1;
622 		MI->flat_insn->detail->wasm.operands[0].type = WASM_OP_INT7;
623 		MI->flat_insn->detail->wasm.operands[0].size = 1;
624 		MI->flat_insn->detail->wasm.operands[0].int7 = MI->wasm_data.int7;
625 	}
626 
627 	*param_size = len;
628 
629 	return true;
630 }
631 
632 bool WASM_getInstruction(csh ud, const uint8_t *code, size_t code_len,
633 		MCInst *MI, uint16_t *size, uint64_t address, void *inst_info)
634 {
635 	unsigned char opcode;
636 	uint16_t param_size;
637 
638 	if (code_len == 0)
639 		return false;
640 
641 	opcode = code[0];
642 	if (opcodes[opcode] == -1) {
643 		// invalid opcode
644 		return false;
645 	}
646 
647 	// valid opcode
648 	MI->address = address;
649 	MI->OpcodePub = MI->Opcode = opcode;
650 
651 	if (MI->flat_insn->detail) {
652 		memset(MI->flat_insn->detail, 0, offsetof(cs_detail, wasm)+sizeof(cs_wasm));
653 		WASM_get_insn_id((cs_struct *)ud, MI->flat_insn, opcode);
654 	}
655 
656 	// setup groups
657 	switch(opcode) {
658 		default:
659 			return false;
660 
661 		case WASM_INS_I32_CONST:
662 			if (code_len == 1 || !read_varuint32(&code[1], code_len - 1, &param_size, MI)) {
663 				return false;
664 			}
665 
666 			if (MI->flat_insn->detail) {
667 				MI->flat_insn->detail->wasm.op_count = 1;
668 				MI->flat_insn->detail->groups[MI->flat_insn->detail->groups_count] = WASM_GRP_NUMBERIC;
669 				MI->flat_insn->detail->groups_count++;
670 			}
671 
672 			*size = param_size + 1;
673 
674 			break;
675 
676 		case WASM_INS_I64_CONST:
677 			if (code_len == 1 || !read_varuint64(&code[1], code_len - 1, &param_size, MI)) {
678 				return false;
679 			}
680 
681 			if (MI->flat_insn->detail) {
682 				MI->flat_insn->detail->wasm.op_count = 1;
683 				MI->flat_insn->detail->groups[MI->flat_insn->detail->groups_count] = WASM_GRP_NUMBERIC;
684 				MI->flat_insn->detail->groups_count++;
685 			}
686 
687 			*size = param_size + 1;
688 
689 			break;
690 
691 		case WASM_INS_F32_CONST:
692 			if (code_len == 1 || !read_uint32(&code[1], code_len - 1, &param_size, MI)) {
693 				return false;
694 			}
695 
696 			if (MI->flat_insn->detail) {
697 				MI->flat_insn->detail->wasm.op_count = 1;
698 				MI->flat_insn->detail->groups[MI->flat_insn->detail->groups_count] = WASM_GRP_NUMBERIC;
699 				MI->flat_insn->detail->groups_count++;
700 			}
701 
702 			*size = param_size + 1;
703 
704 			break;
705 
706 		case WASM_INS_F64_CONST:
707 			if (code_len == 1 || !read_uint64(&code[1], code_len - 1, &param_size, MI)) {
708 				return false;
709 			}
710 
711 			if (MI->flat_insn->detail) {
712 				MI->flat_insn->detail->wasm.op_count = 1;
713 				MI->flat_insn->detail->groups[MI->flat_insn->detail->groups_count] = WASM_GRP_NUMBERIC;
714 				MI->flat_insn->detail->groups_count++;
715 			}
716 
717 			*size = param_size + 1;
718 
719 			break;
720 
721 		case WASM_INS_I32_EQZ:
722 		case WASM_INS_I32_EQ:
723 		case WASM_INS_I32_NE:
724 		case WASM_INS_I32_LT_S:
725 		case WASM_INS_I32_LT_U:
726 		case WASM_INS_I32_GT_S:
727 		case WASM_INS_I32_GT_U:
728 		case WASM_INS_I32_LE_S:
729 		case WASM_INS_I32_LE_U:
730 		case WASM_INS_I32_GE_S:
731 		case WASM_INS_I32_GE_U:
732 		case WASM_INS_I64_EQZ:
733 		case WASM_INS_I64_EQ:
734 		case WASM_INS_I64_NE:
735 		case WASM_INS_I64_LT_S:
736 		case WASM_INS_I64_LT_U:
737 		case WASN_INS_I64_GT_S:
738 		case WASM_INS_I64_GT_U:
739 		case WASM_INS_I64_LE_S:
740 		case WASM_INS_I64_LE_U:
741 		case WASM_INS_I64_GE_S:
742 		case WASM_INS_I64_GE_U:
743 		case WASM_INS_F32_EQ:
744 		case WASM_INS_F32_NE:
745 		case WASM_INS_F32_LT:
746 		case WASM_INS_F32_GT:
747 		case WASM_INS_F32_LE:
748 		case WASM_INS_F32_GE:
749 		case WASM_INS_F64_EQ:
750 		case WASM_INS_F64_NE:
751 		case WASM_INS_F64_LT:
752 		case WASM_INS_F64_GT:
753 		case WASM_INS_F64_LE:
754 		case WASM_INS_F64_GE:
755 		case WASM_INS_I32_CLZ:
756 		case WASM_INS_I32_CTZ:
757 		case WASM_INS_I32_POPCNT:
758 		case WASM_INS_I32_ADD:
759 		case WASM_INS_I32_SUB:
760 		case WASM_INS_I32_MUL:
761 		case WASM_INS_I32_DIV_S:
762 		case WASM_INS_I32_DIV_U:
763 		case WASM_INS_I32_REM_S:
764 		case WASM_INS_I32_REM_U:
765 		case WASM_INS_I32_AND:
766 		case WASM_INS_I32_OR:
767 		case WASM_INS_I32_XOR:
768 		case WASM_INS_I32_SHL:
769 		case WASM_INS_I32_SHR_S:
770 		case WASM_INS_I32_SHR_U:
771 		case WASM_INS_I32_ROTL:
772 		case WASM_INS_I32_ROTR:
773 		case WASM_INS_I64_CLZ:
774 		case WASM_INS_I64_CTZ:
775 		case WASM_INS_I64_POPCNT:
776 		case WASM_INS_I64_ADD:
777 		case WASM_INS_I64_SUB:
778 		case WASM_INS_I64_MUL:
779 		case WASM_INS_I64_DIV_S:
780 		case WASM_INS_I64_DIV_U:
781 		case WASM_INS_I64_REM_S:
782 		case WASM_INS_I64_REM_U:
783 		case WASM_INS_I64_AND:
784 		case WASM_INS_I64_OR:
785 		case WASM_INS_I64_XOR:
786 		case WASM_INS_I64_SHL:
787 		case WASM_INS_I64_SHR_S:
788 		case WASM_INS_I64_SHR_U:
789 		case WASM_INS_I64_ROTL:
790 		case WASM_INS_I64_ROTR:
791 		case WASM_INS_F32_ABS:
792 		case WASM_INS_F32_NEG:
793 		case WASM_INS_F32_CEIL:
794 		case WASM_INS_F32_FLOOR:
795 		case WASM_INS_F32_TRUNC:
796 		case WASM_INS_F32_NEAREST:
797 		case WASM_INS_F32_SQRT:
798 		case WASM_INS_F32_ADD:
799 		case WASM_INS_F32_SUB:
800 		case WASM_INS_F32_MUL:
801 		case WASM_INS_F32_DIV:
802 		case WASM_INS_F32_MIN:
803 		case WASM_INS_F32_MAX:
804 		case WASM_INS_F32_COPYSIGN:
805 		case WASM_INS_F64_ABS:
806 		case WASM_INS_F64_NEG:
807 		case WASM_INS_F64_CEIL:
808 		case WASM_INS_F64_FLOOR:
809 		case WASM_INS_F64_TRUNC:
810 		case WASM_INS_F64_NEAREST:
811 		case WASM_INS_F64_SQRT:
812 		case WASM_INS_F64_ADD:
813 		case WASM_INS_F64_SUB:
814 		case WASM_INS_F64_MUL:
815 		case WASM_INS_F64_DIV:
816 		case WASM_INS_F64_MIN:
817 		case WASM_INS_F64_MAX:
818 		case WASM_INS_F64_COPYSIGN:
819 		case WASM_INS_I32_WARP_I64:
820 		case WASP_INS_I32_TRUNC_S_F32:
821 		case WASM_INS_I32_TRUNC_U_F32:
822 		case WASM_INS_I32_TRUNC_S_F64:
823 		case WASM_INS_I32_TRUNC_U_F64:
824 		case WASM_INS_I64_EXTEND_S_I32:
825 		case WASM_INS_I64_EXTEND_U_I32:
826 		case WASM_INS_I64_TRUNC_S_F32:
827 		case WASM_INS_I64_TRUNC_U_F32:
828 		case WASM_INS_I64_TRUNC_S_F64:
829 		case WASM_INS_I64_TRUNC_U_F64:
830 		case WASM_INS_F32_CONVERT_S_I32:
831 		case WASM_INS_F32_CONVERT_U_I32:
832 		case WASM_INS_F32_CONVERT_S_I64:
833 		case WASM_INS_F32_CONVERT_U_I64:
834 		case WASM_INS_F32_DEMOTE_F64:
835 		case WASM_INS_F64_CONVERT_S_I32:
836 		case WASM_INS_F64_CONVERT_U_I32:
837 		case WASM_INS_F64_CONVERT_S_I64:
838 		case WASM_INS_F64_CONVERT_U_I64:
839 		case WASM_INS_F64_PROMOTE_F32:
840 		case WASM_INS_I32_REINTERPRET_F32:
841 		case WASM_INS_I64_REINTERPRET_F64:
842 		case WASM_INS_F32_REINTERPRET_I32:
843 		case WASM_INS_F64_REINTERPRET_I64:
844 			MI->wasm_data.type = WASM_OP_NONE;
845 
846 			if (MI->flat_insn->detail) {
847 				MI->flat_insn->detail->wasm.op_count = 0;
848 				MI->flat_insn->detail->groups[MI->flat_insn->detail->groups_count] = WASM_GRP_NUMBERIC;
849 				MI->flat_insn->detail->groups_count++;
850 			}
851 
852 			*size = 1;
853 
854 			break;
855 
856 		case WASM_INS_DROP:
857 		case WASM_INS_SELECT:
858 			MI->wasm_data.type = WASM_OP_NONE;
859 
860 			if (MI->flat_insn->detail) {
861 				MI->flat_insn->detail->wasm.op_count = 0;
862 				MI->flat_insn->detail->groups[MI->flat_insn->detail->groups_count] = WASM_GRP_PARAMETRIC;
863 				MI->flat_insn->detail->groups_count++;
864 			}
865 
866 			*size = 1;
867 
868 			break;
869 
870 		case WASM_INS_GET_LOCAL:
871 		case WASM_INS_SET_LOCAL:
872 		case WASM_INS_TEE_LOCAL:
873 		case WASM_INS_GET_GLOBAL:
874 		case WASM_INS_SET_GLOBAL:
875 			if (code_len == 1 || !read_varuint32(&code[1], code_len - 1, &param_size, MI)) {
876 				return false;
877 			}
878 
879 			if (MI->flat_insn->detail) {
880 				MI->flat_insn->detail->wasm.op_count = 1;
881 				MI->flat_insn->detail->groups[MI->flat_insn->detail->groups_count] = WASM_GRP_VARIABLE;
882 				MI->flat_insn->detail->groups_count++;
883 			}
884 
885 			*size = param_size + 1;
886 
887 			break;
888 
889 		case WASM_INS_I32_LOAD:
890 		case WASM_INS_I64_LOAD:
891 		case WASM_INS_F32_LOAD:
892 		case WASM_INS_F64_LOAD:
893 		case WASM_INS_I32_LOAD8_S:
894 		case WASM_INS_I32_LOAD8_U:
895 		case WASM_INS_I32_LOAD16_S:
896 		case WASM_INS_I32_LOAD16_U:
897 		case WASM_INS_I64_LOAD8_S:
898 		case WASM_INS_I64_LOAD8_U:
899 		case WASM_INS_I64_LOAD16_S:
900 		case WASM_INS_I64_LOAD16_U:
901 		case WASM_INS_I64_LOAD32_S:
902 		case WASM_INS_I64_LOAD32_U:
903 		case WASM_INS_I32_STORE:
904 		case WASM_INS_I64_STORE:
905 		case WASM_INS_F32_STORE:
906 		case WASM_INS_F64_STORE:
907 		case WASM_INS_I32_STORE8:
908 		case WASM_INS_I32_STORE16:
909 		case WASM_INS_I64_STORE8:
910 		case WASM_INS_I64_STORE16:
911 		case WASM_INS_I64_STORE32:
912 			if (code_len == 1 || !read_memoryimmediate(&code[1], code_len - 1, &param_size, MI)) {
913 				return false;
914 			}
915 
916 			if (MI->flat_insn->detail) {
917 				MI->flat_insn->detail->wasm.op_count = 2;
918 				MI->flat_insn->detail->groups[MI->flat_insn->detail->groups_count] = WASM_GRP_MEMORY;
919 				MI->flat_insn->detail->groups_count++;
920 			}
921 
922 			*size = param_size + 1;
923 
924 			break;
925 
926 		case WASM_INS_CURRENT_MEMORY:
927 		case WASM_INS_GROW_MEMORY:
928 			MI->wasm_data.type = WASM_OP_NONE;
929 
930 			if (MI->flat_insn->detail) {
931 				MI->flat_insn->detail->wasm.op_count = 0;
932 				MI->flat_insn->detail->groups[MI->flat_insn->detail->groups_count] = WASM_GRP_MEMORY;
933 				MI->flat_insn->detail->groups_count++;
934 			}
935 
936 			*size = 1;
937 
938 			break;
939 
940 		case WASM_INS_UNREACHABLE:
941 		case WASM_INS_NOP:
942 		case WASM_INS_ELSE:
943 		case WASM_INS_END:
944 		case WASM_INS_RETURN:
945 			MI->wasm_data.type = WASM_OP_NONE;
946 
947 			if (MI->flat_insn->detail) {
948 				MI->flat_insn->detail->wasm.op_count = 0;
949 				MI->flat_insn->detail->groups[MI->flat_insn->detail->groups_count] = WASM_GRP_CONTROL;
950 				MI->flat_insn->detail->groups_count++;
951 			}
952 
953 			*size = 1;
954 
955 			break;
956 
957 		case WASM_INS_BLOCK:
958 		case WASM_INS_LOOP:
959 		case WASM_INS_IF:
960 			if (code_len == 1 || !read_varint7(&code[1], code_len - 1, &param_size, MI)) {
961 				return false;
962 			}
963 
964 			if (MI->flat_insn->detail) {
965 				MI->flat_insn->detail->wasm.op_count = 1;
966 				MI->flat_insn->detail->groups[MI->flat_insn->detail->groups_count] = WASM_GRP_CONTROL;
967 				MI->flat_insn->detail->groups_count++;
968 			}
969 
970 			*size = param_size + 1;
971 
972 			break;
973 
974 		case WASM_INS_BR:
975 		case WASM_INS_BR_IF:
976 		case WASM_INS_CALL:
977 		case WASM_INS_CALL_INDIRECT:
978 			if (code_len == 1 || !read_varuint32(&code[1], code_len - 1, &param_size, MI)) {
979 				return false;
980 			}
981 
982 			if (MI->flat_insn->detail) {
983 				MI->flat_insn->detail->wasm.op_count = 1;
984 				MI->flat_insn->detail->groups[MI->flat_insn->detail->groups_count] = WASM_GRP_CONTROL;
985 				MI->flat_insn->detail->groups_count++;
986 			}
987 
988 			*size = param_size + 1;
989 
990 			break;
991 
992 		case WASM_INS_BR_TABLE:
993 			if (code_len == 1 || !read_brtable(&code[1], code_len - 1, &param_size, MI)) {
994 				return false;
995 			}
996 
997 			if (MI->flat_insn->detail) {
998 				MI->flat_insn->detail->wasm.op_count = 1;
999 				MI->flat_insn->detail->groups[MI->flat_insn->detail->groups_count] = WASM_GRP_CONTROL;
1000 				MI->flat_insn->detail->groups_count++;
1001 			}
1002 
1003 			*size = param_size + 1;
1004 
1005 			break;
1006 	}
1007 
1008 	return true;
1009 }
1010