nanowasm/src/search.c

182 lines
4.2 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/search.h>
#include <nw/log.h>
#include <nw/fstring.h>
#include <nw/sections.h>
#include <nanowasm/nw.h>
#include <nw/types.h>
#include <errno.h>
#include <stdint.h>
#include <string.h>
static int ensure_export(const char *const fn,
const struct nw_mod *const m, FILE *const f, varuint32 *const out)
{
if (!m->sections.export)
{
LOG("%s: export section not found", __func__);
return -1;
}
else if (fseek(f, m->sections.export, SEEK_SET))
{
LOG("%s: fseek(3): %s\n", __func__, strerror(errno));
return -1;
}
varuint32 count;
if (varuint32_read(f, &count))
{
LOG("%s: varuint32_read failed\n", __func__);
return -1;
}
for (varuint32 i = 0; i < count; i++)
{
varuint32 len;
bool found = false;
if (varuint32_read(f, &len))
{
LOG("%s: varuint32_read failed\n", __func__);
return -1;
}
else if (len != strlen(fn))
{
if (fseek(f, len, SEEK_CUR))
{
LOG("%s: fseek(3): %s\n", __func__, strerror(errno));
return -1;
}
}
else if (!fstrcmp(fn, f, false))
found = true;
uint8_t kind;
if (!fread(&kind, sizeof kind, 1, f))
{
LOG("%s: fread(3) failed: feof=%d, ferror=%d\n", __func__,
feof(f), ferror(f));
return -1;
}
varuint32 index;
if (varuint32_read(f, &index))
{
LOG("%s: varuint32_read failed\n", __func__);
return -1;
}
else if (found)
{
if (kind != NW_KIND_FUNCTION)
{
LOG("%s: expected kind %d, got %d\n", __func__,
NW_KIND_FUNCTION, kind);
return -1;
}
*out = index;
return 0;
}
}
return -1;
}
static int get_function_index(const struct nw_mod *const m,
const varuint32 index, varuint32 *const findex)
{
const size_t n = m->cfg.n_imports;
if (index < n)
{
LOG("%s: index (%lu) must be greater than number of imports (%zu)\n",
__func__, (unsigned long)index, n);
return -1;
}
*findex = index - n;
return 0;
}
static int get_fn_start(const struct nw_mod *const m, FILE *const f,
const varuint32 index, struct search_fn *const out)
{
const struct section s =
{
.cfg = &m->cfg,
.f = f
};
struct section_function sf;
struct section_code c;
if (section_function(&s, m, index, &sf))
{
LOG("%s: section_function failed\n", __func__);
return -1;
}
else if (section_code(&s, m, index, &c))
{
LOG("%s: section_code failed\n", __func__);
return -1;
}
out->start = c.start;
out->index = index;
return 0;
}
int search_exported_fn(const char *const fn, const struct nw_mod *const m,
FILE *const f, struct search_fn *const out)
{
varuint32 index, findex;
if (ensure_export(fn, m, f, &index))
{
LOG("%s: %s not an exported function\n", __func__, fn);
return -1;
}
else if (get_function_index(m, index, &findex))
{
LOG("%s: get_function_index failed\n", __func__);
return -1;
}
else if (get_fn_start(m, f, findex, out))
{
LOG("%s: get_fn_start %s failed\n", __func__, fn);
return -1;
}
return 0;
}
int search_fn(const varuint32 index, const struct nw_mod *const m,
FILE *const f, struct search_fn *const out)
{
varuint32 findex;
if (get_function_index(m, index, &findex))
{
LOG("%s: get_function_index failed\n", __func__);
return -1;
}
else if (get_fn_start(m, f, findex, out))
{
LOG("%s: get_fn_start failed\n", __func__);
return -1;
}
return 0;
}