nanowasm/src/load.c

179 lines
3.9 KiB
C

/*
* 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 <nw/log.h>
#include <nanowasm/nw.h>
#include <nw/sections.h>
#include <nw/types.h>
#include <errno.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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))
{
LOG("%s: fread(3) failed, feof=%d, ferror=%d\n",
__func__, feof(f), ferror(f));
return -1;
}
else if (memcmp(magic, m, sizeof magic))
{
LOG("%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))
{
LOG("%s: fread(3) failed, feof=%d, ferror=%d\n", __func__, feof(f),
ferror(f));
return -1;
}
else if (memcmp(version, v, sizeof version))
{
LOG("%s: wrong version\n", __func__);
return -1;
}
return 0;
}
static int load_section(const struct nw_mod_cfg *const cfg,
struct nw_mod *const m, FILE *const f)
{
static int (*const fn[])(const struct section *, struct nw_mod *,
unsigned long) =
{
section_custom_check,
section_type_check,
section_import_check,
section_function_check,
section_table_check,
section_memory_check,
section_global_check,
section_export_check,
section_start_check,
section_element_check,
section_code_check,
section_data_check
};
const struct section s =
{
.cfg = cfg,
.f = f
};
varuint7 section;
varuint32 len;
int ret;
if (varuint7_read(f, &section))
{
if (feof(f))
return 0;
LOG("%s: varuint7_read failed\n", __func__);
return 1;
}
else if (section >= sizeof fn / sizeof *fn)
{
LOG("%s: invalid section %u\n", __func__, (unsigned)section);
return 1;
}
else if (varuint32_read(f, &len))
{
LOG("%s: varuint32_read failed\n", __func__);
return 1;
}
else if ((ret = fn[section](&s, m, len)))
LOG("%s: failed to load section %u\n", __func__, (unsigned)section);
return ret;
}
static int load_sections(const struct nw_mod_cfg *const cfg,
struct nw_mod *const m, FILE *const f)
{
while (!feof(f))
if (load_section(cfg, m, f))
{
LOG("%s: load_section failed\n", __func__);
return -1;
}
return 0;
}
static int load(const struct nw_mod_cfg *const cfg, struct nw_mod *const m,
FILE *const f)
{
if (check_magic(f))
{
LOG("%s: load_magic failed\n", __func__);
return -1;
}
else if (check_version(f))
{
LOG("%s: check_version failed\n", __func__);
return -1;
}
else if (load_sections(cfg, m, f))
{
LOG("%s: load_sections failed\n", __func__);
return -1;
}
return 0;
}
int nw_load(const struct nw_mod_cfg *const cfg, struct nw_mod *const m)
{
int ret = -1;
FILE *const f = fopen(cfg->path, "rb");
*m = (const struct nw_mod){.cfg = *cfg};
if (!f)
{
LOG("%s: fopen(3) %s: %s\n", __func__, cfg->path, strerror(errno));
goto end;
}
else if (load(cfg, m, f))
{
LOG("%s: load failed\n", __func__);
goto end;
}
ret = 0;
end:
if (f && fclose(f))
{
LOG("%s: fclose(3) %s: %s\n", __func__, cfg->path, strerror(errno));
ret = -1;
}
return ret;
}