/* * nanowasm, a tiny WebAssembly/Wasm interpreter * Copyright (C) 2023-2024 Xavier Del Campo Romero * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include #include #include #include #include #include static int io_read(void *const buf, const size_t n, void *const user) { FILE *const f = user; const size_t r = fread(buf, 1, 1, f); if (!r && ferror(f)) { fprintf(stderr, "%s: ferror\n", __func__); return -1; } return r; } static enum nw_state io_seek(const long offset, const enum nw_whence whence, void *const user) { static const int trans[] = { [NW_SEEK_END] = SEEK_END, [NW_SEEK_CUR] = SEEK_CUR, [NW_SEEK_SET] = SEEK_SET }; if (fseek(user, offset, trans[whence])) { fprintf(stderr, "%s: fseek(3): %s\n", __func__, strerror(errno)); return NW_FATAL; } return NW_OK; } static enum nw_state io_tell(long *const out, void *const user) { const long offset = ftell(user); if (offset < 0) { fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno)); return NW_FATAL; } *out = offset; return NW_OK; } static int io_eof(void *const user) { FILE *const f = user; return feof(f); } int main(int argc, char *argv[]) { int ret = EXIT_FAILURE; FILE *f = NULL; if (argc != 2) { fprintf(stderr, "%s \n", *argv); goto end; } const char *const path = argv[1]; if (!(f = fopen(path, "rb"))) { fprintf(stderr, "%s: fopen(3) %s: %s\n", __func__, path, strerror(errno)); goto end; } static const struct nw_import imports[] = { { .kind = NW_KIND_FUNCTION, .module = "wasi_snapshot_preview1", .field = "proc_exit" } }; const struct nw_io_cfg io = { .read = io_read, .seek = io_seek, .tell = io_tell, .eof = io_eof, .user = f }; const struct nw_mod_cfg cfg = { .imports = imports, .n_imports = sizeof imports / sizeof *imports, .io = io }; struct nw_mod m; nw_init(&m, &cfg); again: switch (nw_load(&m)) { case NW_OK: break; case NW_AGAIN: goto again; case NW_FATAL: fprintf(stderr, "%s: nw_load failed\n", __func__); goto end; } const struct nw_inst_cfg icfg = { .interp_cfg = { .global = NW_BUF(1), .heap = NW_BUF(1), .stack = NW_BUF(128), .io = io, .m = &m } }; struct nw_inst inst; if (nw_start(&icfg, &inst)) { fprintf(stderr, "%s: nw_start failed\n", __func__); goto end; } again2: switch (nw_run(&inst)) { case NW_OK: break; case NW_AGAIN: goto again2; case NW_FATAL: fprintf(stderr, "%s: nw_run failed: %s\n", __func__, nw_exception(&inst)); goto end; } ret = EXIT_SUCCESS; end: if (f && fclose(f)) { fprintf(stderr, "%s: fclose(3) %s: %s\n", __func__, path, strerror(errno)); goto end; } return ret; }