179 lines
3.9 KiB
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, §ion))
|
|
{
|
|
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;
|
|
}
|