1 /* radare2 - LGPL - Copyright 2017 - pancake, cgvwzq */
2 
3 #include <r_types.h>
4 #include <r_util.h>
5 #include <r_lib.h>
6 #include <r_bin.h>
7 
8 #include "wasm.h"
9 
10 typedef size_t (*ConsumeFcn) (const ut8 *p, const ut8 *max, ut32 *out_value);
11 typedef void *(*ParseEntryFcn) (RBuffer *b, ut64 max);
12 
13 // RBuffer consume functions
consume_r(RBuffer * b,ut64 max,size_t * n_out,ConsumeFcn consume_fcn)14 static ut32 consume_r(RBuffer *b, ut64 max, size_t *n_out, ConsumeFcn consume_fcn) {
15 	r_return_val_if_fail (b && n_out && consume_fcn, 0);
16 
17 	size_t n;
18 	ut32 tmp;
19 	ut64 cur = r_buf_tell (b);
20 	if (max >= r_buf_size (b) || cur > max) {
21 		return 0;
22 	}
23 	// 16 bytes are enough to store 128bits values
24 	ut8 *buf = R_NEWS (ut8, 16);
25 	if (!buf) {
26 		return 0;
27 	}
28 	r_buf_read (b, buf, 16);
29 	if (!(n = consume_fcn (buf, buf + max + 1, &tmp))) {
30 		free (buf);
31 		return 0;
32 	}
33 	r_buf_seek (b, cur + n, R_BUF_SET);
34 	*n_out = n;
35 	free (buf);
36 	return tmp;
37 }
38 
consume_u32_r(RBuffer * b,ut64 max,ut32 * out)39 static size_t consume_u32_r(RBuffer *b, ut64 max, ut32 *out) {
40 	size_t n = 0;
41 	ut32 tmp = consume_r (b, max, &n, read_u32_leb128);
42 	if (out) {
43 		*out = tmp;
44 	}
45 	return n;
46 }
47 
consume_u7_r(RBuffer * b,ut64 max,ut8 * out)48 static size_t consume_u7_r(RBuffer *b, ut64 max, ut8 *out) {
49 	size_t n;
50 	ut32 tmp = consume_r (b, max, &n, read_u32_leb128);
51 	if (out) {
52 		*out = (ut8) (tmp & 0x7f);
53 	}
54 	return n;
55 }
56 
consume_s7_r(RBuffer * b,ut64 max,st8 * out)57 static size_t consume_s7_r(RBuffer *b, ut64 max, st8 *out) {
58 	size_t n;
59 	ut32 tmp = consume_r (b, max, &n, (ConsumeFcn)read_i32_leb128);
60 	if (out) {
61 		*out = (st8) (((tmp & 0x10000000) << 7) | (tmp & 0x7f));
62 	}
63 	return n;
64 }
65 
consume_u1_r(RBuffer * b,ut64 max,ut8 * out)66 static size_t consume_u1_r(RBuffer *b, ut64 max, ut8 *out) {
67 	size_t n;
68 	ut32 tmp = consume_r (b, max, &n, read_u32_leb128);
69 	if (out) {
70 		*out = (ut8) (tmp & 0x1);
71 	}
72 	return n;
73 }
74 
consume_str_r(RBuffer * b,ut64 max,size_t sz,char * out)75 static size_t consume_str_r(RBuffer *b, ut64 max, size_t sz, char *out) {
76 	r_return_val_if_fail (b, 0);
77 	ut64 cur = r_buf_tell (b);
78 	*out = 0;
79 	max = R_MIN (max, sz);
80 	if (max >= r_buf_size (b) || cur > max) {
81 		return 0;
82 	}
83 	if (!(cur + sz - 1 <= max)) {
84 		return 0;
85 	}
86 	if (sz > 0) {
87 		r_buf_read (b, (ut8 *)out, sz);
88 	} else {
89 		*out = 0;
90 	}
91 	return sz;
92 }
93 
consume_init_expr_r(RBuffer * b,ut64 max,ut8 eoc,void * out)94 static size_t consume_init_expr_r(RBuffer *b, ut64 max, ut8 eoc, void *out) {
95 	if (!b || max >= r_buf_size (b) || r_buf_tell (b) > max) {
96 		return 0;
97 	}
98 	size_t res = 0;
99 	ut8 cur = r_buf_read8 (b);
100 	while (r_buf_tell (b) <= max && cur != eoc) {
101 		cur = r_buf_read8 (b);
102 		res++;
103 	}
104 	if (cur != eoc) {
105 		return 0;
106 	}
107 	return res + 1;
108 }
109 
consume_locals_r(RBuffer * b,ut64 max,RBinWasmCodeEntry * out)110 static size_t consume_locals_r(RBuffer *b, ut64 max, RBinWasmCodeEntry *out) {
111 	ut64 cur = r_buf_tell (b);
112 	if (!b || max >= r_buf_size (b) || cur > max) {
113 		return 0;
114 	}
115 	ut32 count = out ? out->local_count : 0;
116 	if (count > 0) {
117 		if (!(out->locals = R_NEWS0 (struct r_bin_wasm_local_entry_t, count))) {
118 			return 0;
119 		}
120 	}
121 	ut32 j = 0;
122 	while (r_buf_tell (b) <= max && j < count) {
123 		if (!(consume_u32_r (b, max, (out ? &out->locals[j].count : NULL)))) {
124 			goto beach;
125 		}
126 		if (!(consume_s7_r (b, max, (out ? (st8 *)&out->locals[j].type : NULL)))) {
127 			goto beach;
128 		}
129 		j++;
130 	}
131 	if (j != count) {
132 		goto beach;
133 	}
134 	return j;
135 beach:
136 	R_FREE (out->locals);
137 	return 0;
138 }
139 
consume_limits_r(RBuffer * b,ut64 max,struct r_bin_wasm_resizable_limits_t * out)140 static size_t consume_limits_r(RBuffer *b, ut64 max, struct r_bin_wasm_resizable_limits_t *out) {
141 	r_return_val_if_fail (b && out, 0);
142 	if (max >= r_buf_size (b) || r_buf_tell (b) > max || !out) {
143 		return 0;
144 	}
145 	ut32 i = r_buf_tell (b);
146 	if (!(consume_u7_r (b, max, &out->flags))) {
147 		return 0;
148 	}
149 	if (!(consume_u32_r (b, max, &out->initial))) {
150 		return 0;
151 	}
152 	if (out->flags && (!(consume_u32_r (b, max, &out->maximum)))) {
153 		return 0;
154 	}
155 	return (size_t)R_ABS (r_buf_tell (b) - i);
156 }
157 
158 // Utils
r_bin_wasm_get_sections_by_id(RList * sections,ut8 id)159 static RList *r_bin_wasm_get_sections_by_id(RList *sections, ut8 id) {
160 	RList *ret = r_list_newf (NULL);
161 	if (ret) {
162 		RBinWasmSection *sec;
163 		RListIter *iter;
164 		r_list_foreach (sections, iter, sec) {
165 			if (sec->id == id) {
166 				r_list_append (ret, sec);
167 			}
168 		}
169 	}
170 	return ret;
171 }
172 
173 #if 0
174 const char *r_bin_wasm_valuetype_to_string (r_bin_wasm_value_type_t type) {
175 	switch (type) {
176 	case R_BIN_WASM_VALUETYPE_i32:
177 		return "i32";
178 	case R_BIN_WASM_VALUETYPE_i64:
179 		return "i62";
180 	case R_BIN_WASM_VALUETYPE_f32:
181 		return "f32";
182 	case R_BIN_WASM_VALUETYPE_f64:
183 		return "f64";
184 	case R_BIN_WASM_VALUETYPE_ANYFUNC:
185 		return "ANYFUNC";
186 	case R_BIN_WASM_VALUETYPE_FUNC:
187 		return "FUNC";
188 	default:
189 		return "<?>";
190 	}
191 }
192 
193 static char *r_bin_wasm_type_entry_to_string(RBinWasmTypeEntry *ptr) {
194 	if (!ptr) {
195 		return NULL;
196 	}
197 	char *buf = (char*)calloc (ptr->param_count, 5);
198 	if (!buf) {
199 		return NULL;
200 	}
201 	int p;
202 	for (p = 0; p < ptr->param_count; p++) {
203 		strcat (buf, r_bin_wasm_valuetype_to_string (ptr->param_types[p]));
204 		if (p < ptr->param_count - 1) {
205 			strcat (buf, ", ");
206 		}
207 	}
208 	snprintf (ptr->to_str, R_BIN_WASM_STRING_LENGTH, "(%s) -> (%s)",
209 		(ptr->param_count > 0? buf: ""),
210 		(ptr->return_count == 1? r_bin_wasm_valuetype_to_string (ptr->return_type): ""));
211 	free (buf);
212 	return ptr->to_str;
213 }
214 #endif
215 
216 // Free
r_bin_wasm_free_types(RBinWasmTypeEntry * ptr)217 static void r_bin_wasm_free_types(RBinWasmTypeEntry *ptr) {
218 	if (ptr) {
219 		free (ptr->param_types);
220 		free (ptr);
221 	}
222 }
223 
r_bin_wasm_free_codes(RBinWasmCodeEntry * ptr)224 static void r_bin_wasm_free_codes(RBinWasmCodeEntry *ptr) {
225 	if (ptr) {
226 		free (ptr->locals);
227 		free (ptr->name);
228 		free (ptr);
229 	}
230 }
231 
232 // Parsing
get_entries_from_section(RBinWasmObj * bin,RBinWasmSection * sec,ParseEntryFcn parse_entry,RListFree free_entry)233 static RList *get_entries_from_section(RBinWasmObj *bin, RBinWasmSection *sec, ParseEntryFcn parse_entry, RListFree free_entry) {
234 	r_return_val_if_fail (sec && bin, NULL);
235 
236 	RList *ret = r_list_newf (free_entry);
237 	if (!ret) {
238 		return NULL;
239 	}
240 	RBuffer *b = bin->buf;
241 	r_buf_seek (b, sec->payload_data, R_BUF_SET);
242 	ut32 r = 0;
243 	ut64 max = r_buf_tell (b) + sec->payload_len - 1;
244 	if (!(max < r_buf_size (b))) {
245 		goto beach;
246 	}
247 	while (r_buf_tell (b) <= max && r < sec->count) {
248 		void *entry = parse_entry (b, max);
249 		if (!entry) {
250 			goto beach;
251 		}
252 
253 		if (!r_list_append (ret, entry)) {
254 			free_entry (entry);
255 			// should this jump to beach?
256 		}
257 		r++;
258 	}
259 	return ret;
260 beach:
261 	eprintf ("[wasm] error: beach reading entries for section %s\n", sec->name);
262 	return ret;
263 }
264 
parse_type_entry(RBuffer * b,ut64 max)265 static void *parse_type_entry(RBuffer *b, ut64 max) {
266 	RBinWasmTypeEntry *ptr = R_NEW0 (RBinWasmTypeEntry);
267 	if (!ptr) {
268 		return NULL;
269 	}
270 	if (!(consume_u7_r (b, max, &ptr->form))) {
271 		goto beach;
272 	}
273 	// check valid type?
274 	if (!(consume_u32_r (b, max, &ptr->param_count))) {
275 		goto beach;
276 	}
277 	ut32 count = ptr ? ptr->param_count : 0;
278 	if (!(r_buf_tell (b) + count <= max)) {
279 		goto beach;
280 	}
281 	if (count > 0) {
282 		if (!(ptr->param_types = R_NEWS0 (r_bin_wasm_value_type_t, count))) {
283 			goto beach;
284 		}
285 	}
286 	ut32 j;
287 	for (j = 0; j < count; j++) {
288 		if (!(consume_s7_r (b, max, (st8 *)&ptr->param_types[j]))) {
289 			goto beach;
290 		}
291 	}
292 	if (!(consume_u1_r (b, max, (ut8 *)&ptr->return_count))) {
293 		goto beach;
294 	}
295 	if (ptr->return_count > 1) {
296 		goto beach;
297 	}
298 	if (ptr->return_count == 1) {
299 		if (!(consume_s7_r (b, max, (st8 *)&ptr->return_type))) {
300 			goto beach;
301 		}
302 	}
303 	return ptr;
304 
305 beach:
306 	r_bin_wasm_free_types (ptr);
307 	return NULL;
308 }
309 
parse_import_entry(RBuffer * b,ut64 max)310 static void *parse_import_entry(RBuffer *b, ut64 max) {
311 	RBinWasmImportEntry *ptr = R_NEW0 (RBinWasmImportEntry);
312 	if (!ptr) {
313 		return NULL;
314 	}
315 	if (!(consume_u32_r (b, max, &ptr->module_len))) {
316 		goto beach;
317 	}
318 	max = R_MIN (max, ptr->module_len);
319 	if (consume_str_r (b, max, ptr->module_len, ptr->module_str) < ptr->module_len) {
320 		goto beach;
321 	}
322 	if (!(consume_u32_r (b, max, &ptr->field_len))) {
323 		goto beach;
324 	}
325 	if (consume_str_r (b, max, ptr->field_len, ptr->field_str) < ptr->field_len) {
326 		goto beach;
327 	}
328 	if (!(consume_u7_r (b, max, &ptr->kind))) {
329 		goto beach;
330 	}
331 	switch (ptr->kind) {
332 	case 0: // Function
333 		if (!(consume_u32_r (b, max, &ptr->type_f))) {
334 			goto beach;
335 		}
336 		break;
337 	case 1: // Table
338 		if (!(consume_s7_r (b, max, (st8 *)&ptr->type_t.elem_type))) {
339 			goto beach;
340 		}
341 		if (!(consume_limits_r (b, max, &ptr->type_t.limits))) {
342 			goto beach;
343 		}
344 		break;
345 	case 2: // Memory
346 		if (!(consume_limits_r (b, max, &ptr->type_m.limits))) {
347 			goto beach;
348 		}
349 		break;
350 	case 3: // Global
351 		if (!(consume_s7_r (b, max, (st8 *)&ptr->type_g.content_type))) {
352 			goto beach;
353 		}
354 		if (!(consume_u1_r (b, max, (ut8 *)&ptr->type_g.mutability))) {
355 			goto beach;
356 		}
357 		break;
358 	default:
359 		goto beach;
360 	}
361 	return ptr;
362 
363 beach:
364 	free (ptr);
365 	return NULL;
366 }
367 
parse_export_entry(RBuffer * b,ut64 max)368 static void *parse_export_entry(RBuffer *b, ut64 max) {
369 	RBinWasmExportEntry *ptr = R_NEW0 (RBinWasmExportEntry);
370 	if (!ptr) {
371 		return NULL;
372 	}
373 	if (!(consume_u32_r (b, max, &ptr->field_len))) {
374 		goto beach;
375 	}
376 	if (consume_str_r (b, max, ptr->field_len, ptr->field_str) < ptr->field_len) {
377 		goto beach;
378 	}
379 	if (!(consume_u7_r (b, max, &ptr->kind))) {
380 		goto beach;
381 	}
382 	if (!(consume_u32_r (b, max, &ptr->index))) {
383 		goto beach;
384 	}
385 	return ptr;
386 beach:
387 	free (ptr);
388 	return NULL;
389 }
390 
parse_code_entry(RBuffer * b,ut64 max)391 static void *parse_code_entry(RBuffer *b, ut64 max) {
392 	RBinWasmCodeEntry *ptr = R_NEW0 (RBinWasmCodeEntry);
393 	if (!ptr) {
394 		return NULL;
395 	}
396 	if (!(consume_u32_r (b, max, &ptr->body_size))) {
397 		goto beach;
398 	}
399 	ut32 j = r_buf_tell (b);
400 	if (!(r_buf_tell (b) + ptr->body_size - 1 <= max)) {
401 		goto beach;
402 	}
403 	if (!(consume_u32_r (b, max, &ptr->local_count))) {
404 		goto beach;
405 	}
406 	if (consume_locals_r (b, max, ptr) < ptr->local_count) {
407 		goto beach;
408 	}
409 	ptr->code = r_buf_tell (b);
410 	ptr->len = ptr->body_size - ptr->code + j;
411 	r_buf_seek (b, ptr->len - 1, R_BUF_CUR); // consume bytecode
412 	r_buf_read (b, &ptr->byte, 1);
413 	if (ptr->byte != R_BIN_WASM_END_OF_CODE) {
414 		goto beach;
415 	}
416 	return ptr;
417 
418 beach:
419 	r_bin_wasm_free_codes (ptr);
420 	return NULL;
421 }
422 
parse_data_entry(RBuffer * b,ut64 max)423 static void *parse_data_entry(RBuffer *b, ut64 max) {
424 	RBinWasmDataEntry *ptr = R_NEW0 (RBinWasmDataEntry);
425 	if (!ptr) {
426 		return NULL;
427 	}
428 	if (!(consume_u32_r (b, max, &ptr->index))) {
429 		goto beach;
430 	}
431 	if (!(ptr->offset.len = consume_init_expr_r (b, max, R_BIN_WASM_END_OF_CODE, NULL))) {
432 		goto beach;
433 	}
434 	if (!(consume_u32_r (b, max, &ptr->size))) {
435 		goto beach;
436 	}
437 	ptr->data = r_buf_tell (b);
438 	r_buf_seek (b, ptr->size, R_BUF_CUR);
439 	return ptr;
440 
441 beach:
442 	free (ptr);
443 	return NULL;
444 }
445 
parse_namemap(RBuffer * b,ut64 max,RIDStorage * map,ut32 * count)446 static bool parse_namemap(RBuffer *b, ut64 max, RIDStorage *map, ut32 *count) {
447 	size_t i;
448 	if (!(consume_u32_r (b, max, count))) {
449 		return false;
450 	}
451 
452 	for (i = 0; i < *count; i++) {
453 		RBinWasmName*name = R_NEW0 (RBinWasmName);
454 		if (!name) {
455 			return false;
456 		}
457 
458 		ut32 idx;
459 		if (!(consume_u32_r (b, max, &idx))) {
460             		R_FREE (name);
461 			return false;
462 		}
463 
464 		if (!(consume_u32_r (b, max, &name->len))) {
465 			R_FREE (name);
466 			return false;
467 		}
468 		name->name = malloc (name->len + 1);
469 		if (!name->name) {
470 			R_FREE (name);
471 			return false;
472 		}
473 		if (!(consume_str_r (b, R_MIN (max, name->len),
474 			name->len, (char *)name->name))) {
475 			R_FREE (name);
476 			return false;
477 		}
478 		name->name[name->len] = 0;
479 
480 		if (!r_id_storage_add (map, name, &idx)) {
481 			R_FREE (name);
482 			return false;
483 		};
484 	}
485 
486 	return true;
487 }
488 
parse_custom_name_entry(RBuffer * b,ut64 max)489 static void *parse_custom_name_entry(RBuffer *b, ut64 max) {
490 	RBinWasmCustomNameEntry *ptr = NULL;
491 	size_t i;
492 	if (!(ptr = R_NEW0 (RBinWasmCustomNameEntry))) {
493 		return NULL;
494 	}
495 
496 	if (!(consume_u7_r (b, max, &ptr->type))) {
497 		goto beach;
498 	};
499 
500 	if (!(consume_u32_r (b, max, &ptr->size))) {
501 		goto beach;
502 	};
503 
504 	switch (ptr->type) {
505 	case R_BIN_WASM_NAMETYPE_Module:
506 		ptr->mod_name = R_NEW0 (struct r_bin_wasm_name_t);
507 		if (!ptr->mod_name) {
508 			goto beach;
509 		}
510 		if (!(consume_u32_r (b, max, &ptr->mod_name->len))) {
511 			goto beach;
512 		}
513 		ptr->mod_name->name = malloc (ptr->mod_name->len + 1);
514 		if (!(consume_str_r (b, R_MIN (max, ptr->mod_name->len),
515 			ptr->mod_name->len, (char *)ptr->mod_name->name))) {
516 			goto beach;
517 		}
518 		ptr->mod_name->name[ptr->mod_name->len] = 0;
519 		break;
520 	case R_BIN_WASM_NAMETYPE_Function:
521 		ptr->func = R_NEW0 (RBinWasmCustomNameFunctionNames);
522 		if (!ptr->func) {
523 			goto beach;
524 		}
525 
526 		ptr->func->names = r_id_storage_new (0, UT32_MAX);
527 
528 		if (!ptr->func->names) {
529 			goto beach;
530 		}
531 
532 		if (!parse_namemap (b, max, ptr->func->names, &ptr->func->count)) {
533 			goto beach;
534 		}
535 		break;
536 	case R_BIN_WASM_NAMETYPE_Local:
537 		ptr->local = R_NEW0 (RBinWasmCustomNameLocalNames);
538 		if (!ptr->local) {
539 			goto beach;
540 		}
541 		if (!(consume_u32_r (b, max, &ptr->local->count))) {
542 			free (ptr->local);
543 			goto beach;
544 		}
545 
546 		ptr->local->locals = r_list_new ();
547 
548 		for (i = 0; i < ptr->local->count; i++) {
549 			RBinWasmCustomNameLocalName *local_name = R_NEW0 (RBinWasmCustomNameLocalName);
550 			if (!local_name) {
551 				free (ptr->local);
552 				free (ptr);
553 				return NULL;
554 			}
555 
556 			if (!(consume_u32_r (b, max, &local_name->index))) {
557 				r_list_free (ptr->local->locals);
558 				free (ptr->local);
559 				free (local_name);
560 				goto beach;
561 			}
562 
563 			local_name->names = r_id_storage_new (0, UT32_MAX);
564 			if (!local_name->names) {
565 				r_list_free (ptr->local->locals);
566 				free (ptr->local);
567 				free (local_name);
568 				goto beach;
569 			}
570 
571 			if (!parse_namemap (b, max, local_name->names, &local_name->names_count)) {
572 				r_id_storage_free (local_name->names);
573 				r_list_free (ptr->local->locals);
574 				free (ptr->local);
575 				free (local_name);
576 				goto beach;
577 			}
578 
579 			if (!r_list_append (ptr->local->locals, local_name)) {
580 				free (local_name);
581 				goto beach;
582 			};
583 		}
584 		break;
585 	}
586 
587 	return ptr;
588 beach:
589 	free (ptr);
590 	return NULL;
591 }
592 
parse_memory_entry(RBuffer * b,ut64 max)593 static void *parse_memory_entry(RBuffer *b, ut64 max) {
594 	RBinWasmMemoryEntry *ptr = R_NEW0 (RBinWasmMemoryEntry);
595 	if (!ptr) {
596 		return NULL;
597 	}
598 	if (!(consume_limits_r (b, max, &ptr->limits))) {
599 		goto beach;
600 	}
601 	return ptr;
602 
603 beach:
604 	free (ptr);
605 	return NULL;
606 }
607 
parse_table_entry(RBuffer * b,ut64 max)608 static void *parse_table_entry(RBuffer *b, ut64 max) {
609 	RBinWasmTableEntry *ptr = R_NEW0 (RBinWasmTableEntry);
610 	if (!ptr) {
611 		return NULL;
612 	}
613 	if (!(consume_s7_r (b, max, (st8 *)&ptr->element_type))) {
614 		goto beach;
615 	}
616 	if (!(consume_limits_r (b, max, &ptr->limits))) {
617 		goto beach;
618 	}
619 	return ptr;
620 
621 beach:
622 	free (ptr);
623 	return NULL;
624 }
625 
parse_global_entry(RBuffer * b,ut64 max)626 static void *parse_global_entry(RBuffer *b, ut64 max) {
627 	RBinWasmGlobalEntry *ptr = R_NEW0 (RBinWasmGlobalEntry);
628 	if (!ptr) {
629 		return NULL;
630 	}
631 	if (!(consume_u7_r (b, max, (ut8 *)&ptr->content_type))) {
632 		goto beach;
633 	}
634 	if (!(consume_u1_r (b, max, &ptr->mutability))) {
635 		goto beach;
636 	}
637 	if (!(consume_init_expr_r (b, max, R_BIN_WASM_END_OF_CODE, NULL))) {
638 		goto beach;
639 	}
640 	return ptr;
641 
642 beach:
643 	free (ptr);
644 	return NULL;
645 }
646 
parse_element_entry(RBuffer * b,ut64 max)647 static void *parse_element_entry(RBuffer *b, ut64 max) {
648 	RBinWasmElementEntry *ptr = R_NEW0 (RBinWasmElementEntry);
649 	if (!ptr) {
650 		return NULL;
651 	}
652 	if (!(consume_u32_r (b, max, &ptr->index))) {
653 		goto beach;
654 	}
655 	if (!(consume_init_expr_r (b, max, R_BIN_WASM_END_OF_CODE, NULL))) {
656 		goto beach;
657 	}
658 	if (!(consume_u32_r (b, max, &ptr->num_elem))) {
659 		goto beach;
660 	}
661 	ut32 j = 0;
662 	while (r_buf_tell (b) <= max && j < ptr->num_elem) {
663 		// TODO: allocate space and fill entry
664 		if (!(consume_u32_r (b, max, NULL))) {
665 			goto beach;
666 		}
667 	}
668 	return ptr;
669 
670 beach:
671 	free (ptr);
672 	return NULL;
673 }
674 
r_bin_wasm_get_type_entries(RBinWasmObj * bin,RBinWasmSection * sec)675 static RList *r_bin_wasm_get_type_entries(RBinWasmObj *bin, RBinWasmSection *sec) {
676 	return get_entries_from_section (bin, sec, parse_type_entry, (RListFree)r_bin_wasm_free_types);
677 }
678 
r_bin_wasm_get_import_entries(RBinWasmObj * bin,RBinWasmSection * sec)679 static RList *r_bin_wasm_get_import_entries(RBinWasmObj *bin, RBinWasmSection *sec) {
680 	return get_entries_from_section (bin, sec, parse_import_entry, (RListFree)free);
681 }
682 
r_bin_wasm_get_export_entries(RBinWasmObj * bin,RBinWasmSection * sec)683 static RList *r_bin_wasm_get_export_entries(RBinWasmObj *bin, RBinWasmSection *sec) {
684 	return get_entries_from_section (bin, sec, parse_export_entry, (RListFree)free);
685 }
686 
r_bin_wasm_get_code_entries(RBinWasmObj * bin,RBinWasmSection * sec)687 static RList *r_bin_wasm_get_code_entries(RBinWasmObj *bin, RBinWasmSection *sec) {
688 	return get_entries_from_section (bin, sec, parse_code_entry, (RListFree)r_bin_wasm_free_codes);
689 }
690 
r_bin_wasm_get_data_entries(RBinWasmObj * bin,RBinWasmSection * sec)691 static RList *r_bin_wasm_get_data_entries(RBinWasmObj *bin, RBinWasmSection *sec) {
692 	return get_entries_from_section (bin, sec, parse_data_entry, (RListFree)free);
693 }
694 
r_bin_wasm_get_start(RBinWasmObj * bin,RBinWasmSection * sec)695 static RBinWasmStartEntry *r_bin_wasm_get_start(RBinWasmObj *bin, RBinWasmSection *sec) {
696 	RBinWasmStartEntry *ptr;
697 
698 	if (!(ptr = R_NEW0 (RBinWasmStartEntry))) {
699 		return NULL;
700 	}
701 
702 	RBuffer *b = bin->buf;
703 	r_buf_seek (b, sec->payload_data, R_BUF_SET);
704 	ut64 max = r_buf_tell (b) + sec->payload_len - 1;
705 	if (!(max < r_buf_size (b))) {
706 		goto beach;
707 	}
708 	if (!(consume_u32_r (b, max, &ptr->index))) {
709 		goto beach;
710 	}
711 	return ptr;
712 beach:
713 	eprintf ("[wasm] header parsing error.\n");
714 	free (ptr);
715 	return NULL;
716 }
717 
r_bin_wasm_get_memory_entries(RBinWasmObj * bin,RBinWasmSection * sec)718 static RList *r_bin_wasm_get_memory_entries(RBinWasmObj *bin, RBinWasmSection *sec) {
719 	return get_entries_from_section (bin, sec, parse_memory_entry, (RListFree)free);
720 }
721 
r_bin_wasm_get_table_entries(RBinWasmObj * bin,RBinWasmSection * sec)722 static RList *r_bin_wasm_get_table_entries(RBinWasmObj *bin, RBinWasmSection *sec) {
723 	return get_entries_from_section (bin, sec, parse_table_entry, (RListFree)free);
724 }
725 
r_bin_wasm_get_global_entries(RBinWasmObj * bin,RBinWasmSection * sec)726 static RList *r_bin_wasm_get_global_entries(RBinWasmObj *bin, RBinWasmSection *sec) {
727 	return get_entries_from_section (bin, sec, parse_global_entry, (RListFree)free);
728 }
729 
r_bin_wasm_get_element_entries(RBinWasmObj * bin,RBinWasmSection * sec)730 static RList *r_bin_wasm_get_element_entries(RBinWasmObj *bin, RBinWasmSection *sec) {
731 	return get_entries_from_section (bin, sec, parse_element_entry, (RListFree)free);
732 }
733 
r_bin_wasm_get_custom_name_entries(RBinWasmObj * bin,RBinWasmSection * sec)734 static RList *r_bin_wasm_get_custom_name_entries(RBinWasmObj *bin, RBinWasmSection *sec) {
735 	RList *ret = r_list_new ();
736 
737 	RBuffer *buf = bin->buf;
738 
739 	r_buf_seek (buf, sec->payload_data, R_BUF_SET);
740 	ut64 max = sec->payload_data + sec->payload_len - 1;
741 
742 	if (max > r_buf_size (buf)) {
743 		goto beach;
744 	}
745 
746 	while (r_buf_tell (buf) < max) {
747 		RBinWasmCustomNameEntry *nam = parse_custom_name_entry (buf, max);
748 
749 		if (!nam) {
750 			goto beach;
751 		}
752 
753 		if (!r_list_append (ret, nam)) {
754 			goto beach;
755 		}
756 	}
757 
758 	return ret;
759 beach:
760 	r_list_free (ret);
761 	return NULL;
762 }
763 
764 // Public functions
r_bin_wasm_init(RBinFile * bf,RBuffer * buf)765 RBinWasmObj *r_bin_wasm_init(RBinFile *bf, RBuffer *buf) {
766 	RBinWasmObj *bin = R_NEW0 (RBinWasmObj);
767 	if (!bin) {
768 		return NULL;
769 	}
770 	bin->buf = r_buf_ref (buf);
771 	bin->size = (ut32)r_buf_size (bf->buf);
772 	bin->g_sections = r_bin_wasm_get_sections (bin);
773 	// TODO: recursive invocation more natural with streamed parsing
774 	// but dependency problems when sections are disordered (against spec)
775 
776 	bin->g_types = r_bin_wasm_get_types (bin);
777 	bin->g_imports = r_bin_wasm_get_imports (bin);
778 	bin->g_exports = r_bin_wasm_get_exports (bin);
779 	bin->g_tables = r_bin_wasm_get_tables (bin);
780 	bin->g_memories = r_bin_wasm_get_memories (bin);
781 	bin->g_globals = r_bin_wasm_get_globals (bin);
782 	bin->g_codes = r_bin_wasm_get_codes (bin);
783 	bin->g_datas = r_bin_wasm_get_datas (bin);
784 
785 	bin->g_names = r_bin_wasm_get_custom_names (bin);
786 
787 	// entrypoint from Start section
788 	bin->entrypoint = r_bin_wasm_get_entrypoint (bin);
789 
790 	return bin;
791 }
792 
r_bin_wasm_destroy(RBinFile * bf)793 void r_bin_wasm_destroy(RBinFile *bf) {
794 	RBinWasmObj *bin;
795 
796 	if (!bf || !bf->o || !bf->o->bin_obj) {
797 		return;
798 	}
799 
800 	bin = bf->o->bin_obj;
801 	r_buf_free (bin->buf);
802 
803 	r_list_free (bin->g_sections);
804 	r_list_free (bin->g_types);
805 
806 	r_list_free (bin->g_imports);
807 	r_list_free (bin->g_exports);
808 	r_list_free (bin->g_tables);
809 	r_list_free (bin->g_memories);
810 	r_list_free (bin->g_globals);
811 	r_list_free (bin->g_codes);
812 	r_list_free (bin->g_datas);
813 
814 	RListIter *iter;
815 	RBinWasmCustomNameEntry *nam;
816 	r_list_foreach (bin->g_names, iter, nam) {
817 		switch (nam->type) {
818 		case R_BIN_WASM_NAMETYPE_Module:
819 			R_FREE (nam->mod_name);
820 			break;
821 		case R_BIN_WASM_NAMETYPE_Function:
822 			if (nam->func) {
823 				r_id_storage_free (nam->func->names);
824 			}
825 			break;
826 		case R_BIN_WASM_NAMETYPE_Local:
827 			if (nam->local && nam->local->locals) {
828 				RListIter *iter;
829 				RBinWasmCustomNameLocalName *local;
830 				r_list_foreach (nam->local->locals, iter, local) {
831 					if (local->names) {
832 						r_id_storage_free (local->names);
833 					}
834 				}
835 
836 				r_list_free (nam->local->locals);
837 			}
838 			break;
839 		}
840 	}
841 	r_list_free (bin->g_names);
842 
843 	free (bin->g_start);
844 	free (bin);
845 	bf->o->bin_obj = NULL;
846 }
847 
r_bin_wasm_get_sections(RBinWasmObj * bin)848 RList *r_bin_wasm_get_sections(RBinWasmObj *bin) {
849 	RList *ret = NULL;
850 	RBinWasmSection *ptr = NULL;
851 
852 	if (!bin) {
853 		return NULL;
854 	}
855 	if (bin->g_sections) {
856 		return bin->g_sections;
857 	}
858 	if (!(ret = r_list_newf ((RListFree)free))) {
859 		return NULL;
860 	}
861 	RBuffer *b = bin->buf;
862 	ut64 max = r_buf_size (b) - 1;
863 	r_buf_seek (b, 8, R_BUF_SET);
864 	while (r_buf_tell (b) <= max) {
865 		if (!(ptr = R_NEW0 (RBinWasmSection))) {
866 			return ret;
867 		}
868 		if (!(consume_u7_r (b, max, &ptr->id))) {
869 			goto beach;
870 		}
871 		if (!(consume_u32_r (b, max, &ptr->size))) {
872 			goto beach;
873 		}
874 		// against spec. TODO: choose criteria for parsing
875 		if (ptr->size < 1) {
876 			goto beach;
877 			// free (ptr);
878 			// continue;
879 		}
880 		if (!(r_buf_tell (b) + (ut64)ptr->size - 1 <= max)) {
881 			goto beach;
882 		}
883 		ptr->count = 0;
884 		ptr->offset = r_buf_tell (b);
885 		switch (ptr->id) {
886 		case R_BIN_WASM_SECTION_CUSTOM:
887 			// eprintf("custom section: 0x%x, ", (ut32)b->cur);
888 			if (!(consume_u32_r (b, max, &ptr->name_len))) {
889 				goto beach;
890 			}
891 			ptr->name = malloc (ptr->name_len + 1);
892 			if (consume_str_r (b, R_MIN (ptr->name_len, max),
893 				ptr->name_len, (char *)ptr->name) < ptr->name_len) {
894 				goto beach;
895 			}
896 			break;
897 		case R_BIN_WASM_SECTION_TYPE:
898 			// eprintf("section type: 0x%x, ", (ut32)b->cur);
899 			ptr->name = strdup ("type");
900 			ptr->name_len = 4;
901 			break;
902 		case R_BIN_WASM_SECTION_IMPORT:
903 			// eprintf("section import: 0x%x, ", (ut32)b->cur);
904 			ptr->name = strdup ("import");
905 			ptr->name_len = 6;
906 			break;
907 		case R_BIN_WASM_SECTION_FUNCTION:
908 			// eprintf("section function: 0x%x, ", (ut32)b->cur);
909 			ptr->name = strdup ("function");
910 			ptr->name_len = 8;
911 			break;
912 		case R_BIN_WASM_SECTION_TABLE:
913 			// eprintf("section table: 0x%x, ", (ut32)b->cur);
914 			ptr->name = strdup ("table");
915 			ptr->name_len = 5;
916 			break;
917 		case R_BIN_WASM_SECTION_MEMORY:
918 			// eprintf("section memory: 0x%x, ", (ut32)b->cur);
919 			ptr->name = strdup ("memory");
920 			ptr->name_len = 6;
921 			break;
922 		case R_BIN_WASM_SECTION_GLOBAL:
923 			// eprintf("section global: 0x%x, ", (ut32)b->cur);
924 			ptr->name = strdup ("global");
925 			ptr->name_len = 6;
926 			break;
927 		case R_BIN_WASM_SECTION_EXPORT:
928 			// eprintf("section export: 0x%x, ", (ut32)b->cur);
929 			ptr->name = strdup ("export");
930 			ptr->name_len = 6;
931 			break;
932 		case R_BIN_WASM_SECTION_START:
933 			// eprintf("section start: 0x%x\n", (ut32)b->cur);
934 			ptr->name = strdup ("start");
935 			ptr->name_len = 5;
936 			break;
937 		case R_BIN_WASM_SECTION_ELEMENT:
938 			// eprintf("section element: 0x%x, ", (ut32)b->cur);
939 			ptr->name = strdup ("element");
940 			ptr->name_len = 7;
941 			break;
942 		case R_BIN_WASM_SECTION_CODE:
943 			// eprintf("section code: 0x%x, ", (ut32)b->cur);
944 			ptr->name = strdup ("code");
945 			ptr->name_len = 4;
946 			break;
947 		case R_BIN_WASM_SECTION_DATA:
948 			// eprintf("section data: 0x%x, ", (ut32)b->cur);
949 			ptr->name = strdup ("data");
950 			ptr->name_len = 4;
951 			break;
952 		default:
953 			eprintf ("[wasm] error: unkown section id: %d\n", ptr->id);
954 			r_buf_seek (b, ptr->size - 1, R_BUF_CUR);
955 			continue;
956 		}
957 		if (ptr->id != R_BIN_WASM_SECTION_START && ptr->id != R_BIN_WASM_SECTION_CUSTOM) {
958 			if (!(consume_u32_r (b, max, &ptr->count))) {
959 				goto beach;
960 			}
961 			// eprintf("count %d\n", ptr->count);
962 		}
963 		ptr->payload_data = r_buf_tell (b);
964 		ptr->payload_len = ptr->size - (ptr->payload_data - ptr->offset);
965 		if (ptr->payload_len > ptr->size) {
966 			goto beach;
967 		}
968 		r_buf_seek (b, ptr->payload_len, R_BUF_CUR);
969 		if (!r_list_append (ret, ptr)) {
970 			free (ptr);
971 			// should it jump to beach?
972 		}
973 		ptr = NULL;
974 	}
975 	bin->g_sections = ret;
976 	return ret;
977 beach:
978 	eprintf ("[wasm] error: beach sections\n");
979 	free (ptr);
980 	return ret;
981 }
982 
r_bin_wasm_get_entrypoint(RBinWasmObj * bin)983 ut32 r_bin_wasm_get_entrypoint(RBinWasmObj *bin) {
984 	RList *secs = NULL;
985 	RBinWasmStartEntry *start = NULL;
986 	RBinWasmSection *sec = NULL;
987 	RBinWasmCodeEntry *func = NULL;
988 
989 	if (!bin || !bin->g_sections) {
990 		return 0;
991 	}
992 	if (bin->entrypoint) {
993 		return bin->entrypoint;
994 	}
995 	if (bin->g_start) {
996 		start = bin->g_start;
997 	} else if (!(secs = r_bin_wasm_get_sections_by_id (bin->g_sections, R_BIN_WASM_SECTION_START))) {
998 		return 0;
999 	} else if (!(sec = (RBinWasmSection *)r_list_first (secs))) {
1000 		r_list_free (secs);
1001 		return 0;
1002 	} else {
1003 		start = r_bin_wasm_get_start (bin, sec);
1004 		bin->g_start = start;
1005 	}
1006 	if (!start) {
1007 		r_list_free (secs);
1008 		return 0;
1009 	}
1010 	// FIX: entrypoint can be also an import
1011 	if (!bin->g_codes) {
1012 		r_list_free (secs);
1013 		return 0;
1014 	}
1015 	func = r_list_get_n (bin->g_codes, start->index);
1016 	r_list_free (secs);
1017 	return (ut32) (func ? func->code : 0);
1018 }
1019 
r_bin_wasm_get_imports(RBinWasmObj * bin)1020 RList *r_bin_wasm_get_imports(RBinWasmObj *bin) {
1021 	RBinWasmSection *import = NULL;
1022 	RList *imports = NULL;
1023 
1024 	if (!bin || !bin->g_sections) {
1025 		return NULL;
1026 	}
1027 	if (bin->g_imports) {
1028 		return bin->g_imports;
1029 	}
1030 	if (!(imports = r_bin_wasm_get_sections_by_id (bin->g_sections, R_BIN_WASM_SECTION_IMPORT))) {
1031 		return r_list_new ();
1032 	}
1033 	// support for multiple import sections against spec
1034 	if (!(import = (RBinWasmSection *)r_list_first (imports))) {
1035 		r_list_free (imports);
1036 		return r_list_new ();
1037 	}
1038 	bin->g_imports = r_bin_wasm_get_import_entries (bin, import);
1039 	r_list_free (imports);
1040 	return bin->g_imports;
1041 }
1042 
r_bin_wasm_get_exports(RBinWasmObj * bin)1043 RList *r_bin_wasm_get_exports(RBinWasmObj *bin) {
1044 	r_return_val_if_fail (bin, NULL);
1045 	RBinWasmSection *export = NULL;
1046 	RList *exports = NULL;
1047 
1048 	if (!bin->g_sections) {
1049 		return NULL;
1050 	}
1051 	if (bin->g_exports) {
1052 		return bin->g_exports;
1053 	}
1054 	if (!(exports = r_bin_wasm_get_sections_by_id (bin->g_sections, R_BIN_WASM_SECTION_EXPORT))) {
1055 		return r_list_new ();
1056 	}
1057 	// support for multiple export sections against spec
1058 	if (!(export = (RBinWasmSection *)r_list_first (exports))) {
1059 		r_list_free (exports);
1060 		return r_list_new ();
1061 	}
1062 	bin->g_exports = r_bin_wasm_get_export_entries (bin, export);
1063 	r_list_free (exports);
1064 	return bin->g_exports;
1065 }
1066 
r_bin_wasm_get_types(RBinWasmObj * bin)1067 RList *r_bin_wasm_get_types(RBinWasmObj *bin) {
1068 	RBinWasmSection *type = NULL;
1069 	RList *types = NULL;
1070 
1071 	if (!bin || !bin->g_sections) {
1072 		return NULL;
1073 	}
1074 	if (bin->g_types) {
1075 		return bin->g_types;
1076 	}
1077 	if (!(types = r_bin_wasm_get_sections_by_id (bin->g_sections, R_BIN_WASM_SECTION_TYPE))) {
1078 		return r_list_new ();
1079 	}
1080 	// support for multiple export sections against spec
1081 	if (!(type = (RBinWasmSection *)r_list_first (types))) {
1082 		r_list_free (types);
1083 		return r_list_new ();
1084 	}
1085 	bin->g_types = r_bin_wasm_get_type_entries (bin, type);
1086 	r_list_free (types);
1087 	return bin->g_types;
1088 }
1089 
r_bin_wasm_get_tables(RBinWasmObj * bin)1090 RList *r_bin_wasm_get_tables(RBinWasmObj *bin) {
1091 	RBinWasmSection *table = NULL;
1092 	RList *tables = NULL;
1093 
1094 	if (!bin || !bin->g_sections) {
1095 		return NULL;
1096 	}
1097 	if (bin->g_tables) {
1098 		return bin->g_tables;
1099 	}
1100 	if (!(tables = r_bin_wasm_get_sections_by_id (bin->g_sections, R_BIN_WASM_SECTION_TABLE))) {
1101 		return r_list_new ();
1102 	}
1103 	// support for multiple export sections against spec
1104 	if (!(table = (RBinWasmSection *)r_list_first (tables))) {
1105 		r_list_free (tables);
1106 		return r_list_new ();
1107 	}
1108 	bin->g_tables = r_bin_wasm_get_table_entries (bin, table);
1109 	r_list_free (tables);
1110 	return bin->g_tables;
1111 }
1112 
r_bin_wasm_get_memories(RBinWasmObj * bin)1113 RList *r_bin_wasm_get_memories(RBinWasmObj *bin) {
1114 	RBinWasmSection *memory;
1115 	RList *memories;
1116 
1117 	if (!bin || !bin->g_sections) {
1118 		return NULL;
1119 	}
1120 
1121 	if (bin->g_memories) {
1122 		return bin->g_memories;
1123 	}
1124 
1125 	if (!(memories = r_bin_wasm_get_sections_by_id (bin->g_sections, R_BIN_WASM_SECTION_MEMORY))) {
1126 		return r_list_new ();
1127 	}
1128 
1129 	// support for multiple export sections against spec
1130 	if (!(memory = (RBinWasmSection *)r_list_first (memories))) {
1131 		r_list_free (memories);
1132 		return r_list_new ();
1133 	}
1134 
1135 	bin->g_memories = r_bin_wasm_get_memory_entries (bin, memory);
1136 	r_list_free (memories);
1137 	return bin->g_memories;
1138 }
1139 
r_bin_wasm_get_globals(RBinWasmObj * bin)1140 RList *r_bin_wasm_get_globals(RBinWasmObj *bin) {
1141 	RBinWasmSection *global = NULL;
1142 	RList *globals = NULL;
1143 
1144 	if (!bin || !bin->g_sections) {
1145 		return NULL;
1146 	}
1147 	if (bin->g_globals) {
1148 		return bin->g_globals;
1149 	}
1150 	if (!(globals = r_bin_wasm_get_sections_by_id (bin->g_sections, R_BIN_WASM_SECTION_GLOBAL))) {
1151 		return r_list_new ();
1152 	}
1153 	// support for multiple export sections against spec
1154 	if (!(global = (RBinWasmSection *)r_list_first (globals))) {
1155 		r_list_free (globals);
1156 		return r_list_new ();
1157 	}
1158 	bin->g_globals = r_bin_wasm_get_global_entries (bin, global);
1159 	r_list_free (globals);
1160 	return bin->g_globals;
1161 }
1162 
r_bin_wasm_get_elements(RBinWasmObj * bin)1163 RList *r_bin_wasm_get_elements(RBinWasmObj *bin) {
1164 	RBinWasmSection *element = NULL;
1165 	RList *elements = NULL;
1166 
1167 	if (!bin || !bin->g_sections) {
1168 		return NULL;
1169 	}
1170 	if (bin->g_elements) {
1171 		return bin->g_elements;
1172 	}
1173 	if (!(elements = r_bin_wasm_get_sections_by_id (bin->g_sections, R_BIN_WASM_SECTION_ELEMENT))) {
1174 		return r_list_new ();
1175 	}
1176 	// support for multiple export sections against spec
1177 	if (!(element = (RBinWasmSection *)r_list_first (elements))) {
1178 		r_list_free (elements);
1179 		return r_list_new ();
1180 	}
1181 	bin->g_elements = r_bin_wasm_get_element_entries (bin, element);
1182 	r_list_free (elements);
1183 	return bin->g_elements;
1184 }
1185 
r_bin_wasm_get_codes(RBinWasmObj * bin)1186 RList *r_bin_wasm_get_codes(RBinWasmObj *bin) {
1187 	RBinWasmSection *code = NULL;
1188 	;
1189 	RList *codes = NULL;
1190 
1191 	if (!bin || !bin->g_sections) {
1192 		return NULL;
1193 	}
1194 	if (bin->g_codes) {
1195 		return bin->g_codes;
1196 	}
1197 	if (!(codes = r_bin_wasm_get_sections_by_id (bin->g_sections, R_BIN_WASM_SECTION_CODE))) {
1198 		return r_list_new ();
1199 	}
1200 	// support for multiple export sections against spec
1201 	if (!(code = (RBinWasmSection *)r_list_first (codes))) {
1202 		r_list_free (codes);
1203 		return r_list_new ();
1204 	}
1205 	bin->g_codes = r_bin_wasm_get_code_entries (bin, code);
1206 	r_list_free (codes);
1207 	return bin->g_codes;
1208 }
1209 
r_bin_wasm_get_datas(RBinWasmObj * bin)1210 RList *r_bin_wasm_get_datas(RBinWasmObj *bin) {
1211 	RBinWasmSection *data = NULL;
1212 	RList *datas = NULL;
1213 
1214 	if (!bin || !bin->g_sections) {
1215 		return NULL;
1216 	}
1217 	if (bin->g_datas) {
1218 		return bin->g_datas;
1219 	}
1220 	if (!(datas = r_bin_wasm_get_sections_by_id (bin->g_sections, R_BIN_WASM_SECTION_DATA))) {
1221 		return r_list_new ();
1222 	}
1223 	// support for multiple export sections against spec
1224 	if (!(data = (RBinWasmSection *)r_list_first (datas))) {
1225 		r_list_free (datas);
1226 		return r_list_new ();
1227 	}
1228 	bin->g_datas = r_bin_wasm_get_data_entries (bin, data);
1229 	r_list_free (datas);
1230 	return bin->g_datas;
1231 }
1232 
r_bin_wasm_get_custom_names(RBinWasmObj * bin)1233 RList *r_bin_wasm_get_custom_names(RBinWasmObj *bin) {
1234 	RList *customs = NULL;
1235 
1236 	r_return_val_if_fail (bin && bin->g_sections, NULL);
1237 
1238 	if (bin->g_names) {
1239 		return bin->g_names;
1240 	}
1241 	if (!(customs = r_bin_wasm_get_sections_by_id (bin->g_sections, R_BIN_WASM_SECTION_CUSTOM))) {
1242 		return r_list_new ();
1243 	}
1244 	// support for multiple "name" sections against spec
1245 	RBinWasmSection *cust = (RBinWasmSection *)r_list_first (customs);
1246 	if (!cust || !cust->name) {
1247 		r_list_free (customs);
1248 		return r_list_new ();
1249 	}
1250 	if (strcmp (cust->name, "name")) {
1251 		r_list_free (customs);
1252 		return r_list_new ();
1253 	}
1254 	bin->g_names = r_bin_wasm_get_custom_name_entries (bin, cust);
1255 	r_list_free (customs);
1256 	return bin->g_names;
1257 }
1258 
r_bin_wasm_get_function_name(RBinWasmObj * bin,ut32 idx)1259 const char *r_bin_wasm_get_function_name(RBinWasmObj *bin, ut32 idx) {
1260 	if (!(bin && bin->g_names)) {
1261 		return NULL;
1262 	};
1263 
1264 	RListIter *iter;
1265 	RBinWasmCustomNameEntry *nam;
1266 	r_list_foreach (bin->g_names, iter, nam) {
1267 		if (nam->type == R_BIN_WASM_NAMETYPE_Function) {
1268 			struct r_bin_wasm_name_t *n = NULL;
1269 
1270 			if ((n = r_id_storage_get (nam->func->names, idx))) {
1271 				return (const char *)n->name;
1272 			}
1273 		}
1274 	}
1275 
1276 	return NULL;
1277 }
1278