#include #include #include #include #include #include #include #include #include static int failed_read(FILE *const f) { return fprintf(stderr, "%s: fread(3) failed, feof=%d, ferror=%d\n", __func__, feof(f), ferror(f)); } static int check_magic(FILE *const f) { static const uint8_t m[] = {'\0', 'a', 's', 'm'}; uint8_t magic[sizeof m]; if (!fread(magic, sizeof magic, 1, f)) { failed_read(f); return -1; } else if (memcmp(magic, m, sizeof magic)) { fprintf(stderr, "%s: wrong magic bytes\n", __func__); return -1; } return 0; } static int check_version(FILE *const f) { static const uint8_t v[] = {1, 0, 0, 0}; uint8_t version[sizeof v]; if (!fread(version, sizeof version, 1, f)) { failed_read(f); return -1; } else if (memcmp(version, v, sizeof version)) { fprintf(stderr, "%s: wrong version\n", __func__); return -1; } return 0; } static int load_section(struct wasmfs *const w, FILE *const f) { enum { CUSTOM, TYPE, IMPORT, FUNCTION, TABLE, MEMORY, GLOBAL, EXPORT, START, ELEMENT, CODE, DATA }; static int (*const fn[])(struct wasmfs *, FILE *, unsigned long) = { [CUSTOM] = section_custom, [TYPE] = section_type, [IMPORT] = section_import, [FUNCTION] = section_function, [TABLE] = section_table, [MEMORY] = section_memory, [GLOBAL] = section_global, [EXPORT] = section_export, [START] = section_start, [ELEMENT] = section_element, [CODE] = section_code, [DATA] = section_data }; varuint7 section; varuint32 len; int ret; if (varuint7_read(f, §ion)) { if (feof(f)) return 0; fprintf(stderr, "%s: varuint7_read failed\n", __func__); return 1; } else if (section >= sizeof fn / sizeof *fn) { fprintf(stderr, "%s: invalid section %u\n", __func__, (unsigned)section); return 1; } else if (varuint32_read(f, &len)) { fprintf(stderr, "%s: varuint32_read failed\n", __func__); return 1; } else if ((ret = fn[section](w, f, len))) fprintf(stderr, "%s: failed to load section %u\n", __func__, (unsigned)section); return ret; } static int load_sections(struct wasmfs *const w, FILE *const f) { while (!feof(f)) if (load_section(w, f)) { fprintf(stderr, "%s: load_section failed\n", __func__); return -1; } return 0; } static int load(struct wasmfs *const w, FILE *const f) { if (check_magic(f)) { fprintf(stderr, "%s: load_magic failed\n", __func__); return -1; } else if (check_version(f)) { fprintf(stderr, "%s: check_version failed\n", __func__); return -1; } else if (load_sections(w, f)) { fprintf(stderr, "%s: load_sections failed\n", __func__); return -1; } return 0; } struct wasmfs *wasmfs_load(const char *const path) { struct wasmfs *ret = NULL, *w = NULL; char *pathdup = NULL; FILE *const f = fopen(path, "rb"); const size_t sz = strlen(path) + 1; if (!f) { fprintf(stderr, "%s: fopen(3) %s: %s\n", __func__, path, strerror(errno)); goto end; } else if (!(w = malloc(sizeof *w))) { fprintf(stderr, "%s: malloc(3) w: %s\n", __func__, strerror(errno)); goto end; } else if (!(pathdup = malloc(sz))) { fprintf(stderr, "%s: malloc(3) pathdup: %s\n", __func__, strerror(errno)); goto end; } memcpy(pathdup, path, sz); *w = (const struct wasmfs) { .path = pathdup }; if (load(w, f)) { fprintf(stderr, "%s: load failed\n", __func__); goto end; } ret = w; end: if (f && fclose(f)) { fprintf(stderr, "%s: fclose(3) %s: %s\n", __func__, path, strerror(errno)); ret = NULL; } if (!ret) wasmfs_unload(w); return ret; }