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