aboutsummaryrefslogtreecommitdiff
path: root/src/section
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi.dcr@tutanota.com>2023-11-26 22:43:30 +0100
committerXavier Del Campo Romero <xavi.dcr@tutanota.com>2023-12-29 23:36:21 +0100
commit52c18e60929b64285d4bb333f87482d954c9b2e0 (patch)
tree836ab3a01d160f45cda4f5a28522fc0bf471011c /src/section
First commitfirst-step
Diffstat (limited to 'src/section')
-rw-r--r--src/section/CMakeLists.txt15
-rw-r--r--src/section/code.c235
-rw-r--r--src/section/common.c35
-rw-r--r--src/section/custom.c17
-rw-r--r--src/section/data.c8
-rw-r--r--src/section/element.c8
-rw-r--r--src/section/export.c147
-rw-r--r--src/section/function.c80
-rw-r--r--src/section/global.c110
-rw-r--r--src/section/import.c188
-rw-r--r--src/section/memory.c81
-rw-r--r--src/section/start.c8
-rw-r--r--src/section/table.c96
-rw-r--r--src/section/type.c126
14 files changed, 1154 insertions, 0 deletions
diff --git a/src/section/CMakeLists.txt b/src/section/CMakeLists.txt
new file mode 100644
index 0000000..62d9cef
--- /dev/null
+++ b/src/section/CMakeLists.txt
@@ -0,0 +1,15 @@
+target_sources(${PROJECT_NAME} PRIVATE
+ code.c
+ common.c
+ custom.c
+ data.c
+ element.c
+ export.c
+ function.c
+ global.c
+ import.c
+ memory.c
+ start.c
+ table.c
+ type.c
+)
diff --git a/src/section/code.c b/src/section/code.c
new file mode 100644
index 0000000..6e131e7
--- /dev/null
+++ b/src/section/code.c
@@ -0,0 +1,235 @@
+#include <opcodes.h>
+#include <interp.h>
+#include <sections.h>
+#include <wasm_types.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <string.h>
+
+static int check_body(FILE *const f, const unsigned long n)
+{
+ unsigned long rem = n;
+
+ while (rem)
+ {
+ const long before = ftell(f);
+ uint8_t byte;
+
+ if (before < 0)
+ {
+ fprintf(stderr, "%s: ftell(3) before: %s\n", __func__,
+ strerror(errno));
+ return -1;
+ }
+ else if (!fread(&byte, sizeof byte, 1, f))
+ {
+ fprintf(stderr, "%s: fread(3) failed, feof=%d, ferror=%d\n",
+ __func__, feof(f), ferror(f));
+ return -1;
+ }
+ else if (rem == 1 && byte != OP_END)
+ {
+ fprintf(stderr, "%s: unexpected opcode %#" PRIx8 " at body end\n",
+ __func__, byte);
+ return -1;
+ }
+ else if (interp_check_opcode(byte, f))
+ {
+ fprintf(stderr, "%s: interp_check_opcode failed\n", __func__);
+ return -1;
+ }
+
+ const long after = ftell(f);
+
+ if (after < 0)
+ {
+ fprintf(stderr, "%s: ftell(3) after: %s\n", __func__,
+ strerror(errno));
+ return -1;
+ }
+
+ rem -= after - before;
+ }
+
+ return 0;
+}
+
+static int check_type(FILE *const f)
+{
+ varint7 type;
+
+ if (varint7_read(f, &type))
+ {
+ fprintf(stderr, "%s: varint7_read failed\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int check_local(FILE *const f)
+{
+ varuint32 count;
+
+ if (varuint32_read(f, &count))
+ {
+ fprintf(stderr, "%s: varuint32_read failed\n", __func__);
+ return -1;
+ }
+ else if (check_type(f))
+ {
+ fprintf(stderr, "%s: check_type failed\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int check_locals(FILE *const f)
+{
+ varuint32 local_count;
+
+ if (varuint32_read(f, &local_count))
+ {
+ fprintf(stderr, "%s: varuint32_read local_count failed\n", __func__);
+ return -1;
+ }
+
+ for (varuint32 i = 0; i < local_count; i++)
+ if (check_local(f))
+ {
+ fprintf(stderr, "%s: check_local failed\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int check_function_body(FILE *const f)
+{
+ varuint32 body_size;
+
+ if (varuint32_read(f, &body_size))
+ {
+ fprintf(stderr, "%s: varuint32_read body_size failed\n", __func__);
+ return -1;
+ }
+
+ const long start = ftell(f);
+
+ if (start < 0)
+ {
+ fprintf(stderr, "%s: ftell(3) start: %s\n", __func__, strerror(errno));
+ return -1;
+ }
+ else if (check_locals(f))
+ {
+ fprintf(stderr, "%s: check_locals failed\n", __func__);
+ return -1;
+ }
+
+ const long end = ftell(f);
+
+ if (end < 0)
+ {
+ fprintf(stderr, "%s: ftell(3) end: %s\n", __func__, strerror(errno));
+ return -1;
+ }
+
+ const unsigned long consumed = end - start;
+
+ if (consumed > body_size)
+ {
+ fprintf(stderr, "%s: exceeded function body size\n", __func__);
+ return -1;
+ }
+ else if (check_body(f, body_size - consumed))
+ {
+ fprintf(stderr, "%s: check_body failed\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int check_function_bodies(FILE *const f)
+{
+ varuint32 count;
+
+ if (varuint32_read(f, &count))
+ {
+ fprintf(stderr, "%s: varuint32_read failed\n", __func__);
+ return -1;
+ }
+
+ for (varuint32 i = 0; i < count; i++)
+ if (check_function_body(f))
+ {
+ fprintf(stderr, "%s: check_function_body failed\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int check(FILE *const f, const unsigned long len)
+{
+ const long start = ftell(f);
+
+ if (start < 0)
+ {
+ fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+ else if (check_function_bodies(f))
+ {
+ fprintf(stderr, "%s: check_function_bodies failed\n", __func__);
+ return -1;
+ }
+
+ const long end = ftell(f);
+
+ if (end < 0)
+ {
+ fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+
+ const unsigned long size = end - start;
+
+ if (size != len)
+ {
+ fprintf(stderr, "%s: size exceeded (%lu expected, got %lu)\n",
+ __func__, len, size);
+ return -1;
+ }
+
+ return 0;
+}
+
+int section_code(struct wasmfs *const w, FILE *const f,
+ const unsigned long len)
+{
+ if (w->sections.code)
+ {
+ fprintf(stderr, "%s: ignoring duplicate section\n", __func__);
+ return 0;
+ }
+
+ const long offset = ftell(f);
+
+ if (offset < 0)
+ {
+ fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+ else if (check(f, len))
+ {
+ fprintf(stderr, "%s: check failed\n", __func__);
+ return -1;
+ }
+
+ w->sections.code = offset;
+ return 0;
+}
diff --git a/src/section/common.c b/src/section/common.c
new file mode 100644
index 0000000..58ddddb
--- /dev/null
+++ b/src/section/common.c
@@ -0,0 +1,35 @@
+#include <sections.h>
+#include <wasm_types.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+int check_resizable_limits(FILE *const f)
+{
+ varuint1 flags;
+ varuint32 initial;
+
+ if (varuint1_read(f, &flags))
+ {
+ fprintf(stderr, "%s: varuint1_read failed\n", __func__);
+ return -1;
+ }
+ else if (varuint32_read(f, &initial))
+ {
+ fprintf(stderr, "%s: varuint32_read failed\n", __func__);
+ return -1;
+ }
+
+ if (flags)
+ {
+ varuint32 maximum;
+
+ if (varuint32_read(f, &maximum))
+ {
+ fprintf(stderr, "%s: varuint32_read failed\n", __func__);
+ return -1;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/section/custom.c b/src/section/custom.c
new file mode 100644
index 0000000..9544f17
--- /dev/null
+++ b/src/section/custom.c
@@ -0,0 +1,17 @@
+#include <sections.h>
+#include <wasm_types.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+int section_custom(struct wasmfs *const w, FILE *const f,
+ const unsigned long len)
+{
+ if (fseek(f, len, SEEK_CUR))
+ {
+ fprintf(stderr, "%s: fseek(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/section/data.c b/src/section/data.c
new file mode 100644
index 0000000..5a04d7b
--- /dev/null
+++ b/src/section/data.c
@@ -0,0 +1,8 @@
+#include <sections.h>
+#include <wasm_types.h>
+
+int section_data(struct wasmfs *const w, FILE *const f,
+ const unsigned long len)
+{
+ return -1;
+}
diff --git a/src/section/element.c b/src/section/element.c
new file mode 100644
index 0000000..370a952
--- /dev/null
+++ b/src/section/element.c
@@ -0,0 +1,8 @@
+#include <sections.h>
+#include <wasm_types.h>
+
+int section_element(struct wasmfs *const w, FILE *const f,
+ const unsigned long len)
+{
+ return -1;
+}
diff --git a/src/section/export.c b/src/section/export.c
new file mode 100644
index 0000000..9ca8de5
--- /dev/null
+++ b/src/section/export.c
@@ -0,0 +1,147 @@
+#include <sections.h>
+#include <wasm_types.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+static int check_string(FILE *const f)
+{
+ varuint32 len;
+
+ if (varuint32_read(f, &len))
+ {
+ fprintf(stderr, "%s: varuint32_read failed\n", __func__);
+ return -1;
+ }
+
+ for (varuint32 i = 0; i < len; i++)
+ {
+ uint8_t byte;
+
+ if (!fread(&byte, sizeof byte, 1, f))
+ {
+ fprintf(stderr, "%s: fread(3) failed, feof=%d, ferror=%d\n",
+ __func__, feof(f), ferror(f));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int check_kind(FILE *const f)
+{
+ varuint32 type;
+
+ if (varuint32_read(f, &type))
+ {
+ fprintf(stderr, "%s: varuint32_read failed\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int check_index(FILE *const f)
+{
+ varuint32 index;
+
+ if (varuint32_read(f, &index))
+ {
+ fprintf(stderr, "%s: varuint32_read failed\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int check_export_entry(FILE *const f)
+{
+ if (check_string(f))
+ {
+ fprintf(stderr, "%s: check_string failed\n", __func__);
+ return -1;
+ }
+ else if (check_kind(f))
+ {
+ fprintf(stderr, "%s: check_kind failed\n", __func__);
+ return -1;
+ }
+ else if (check_index(f))
+ {
+ fprintf(stderr, "%s: check_index failed\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int check(FILE *const f, const unsigned long len)
+{
+ const long start = ftell(f);
+ varuint32 count;
+
+ if (start < 0)
+ {
+ fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+ else if (varuint32_read(f, &count))
+ {
+ fprintf(stderr, "%s: varuint32_read failed\n", __func__);
+ return -1;
+ }
+
+ for (varuint32 i = 0; i < count; i++)
+ if (check_export_entry(f))
+ {
+ fprintf(stderr, "%s: check_export_entry failed\n", __func__);
+ return -1;
+ }
+
+ const long end = ftell(f);
+
+ if (end < 0)
+ {
+ fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+
+ const unsigned long size = end - start;
+
+ if (size != len)
+ {
+ fprintf(stderr, "%s: size exceeded (%lu expected, got %lu)\n",
+ __func__, len, size);
+ return -1;
+ }
+
+ return 0;
+}
+
+int section_export(struct wasmfs *const w, FILE *const f,
+ const unsigned long len)
+{
+ if (w->sections.export)
+ {
+ fprintf(stderr, "%s: ignoring duplicate section\n", __func__);
+ return 0;
+ }
+
+ const long offset = ftell(f);
+
+ if (offset < 0)
+ {
+ fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+ else if (check(f, len))
+ {
+ fprintf(stderr, "%s: check failed\n", __func__);
+ return -1;
+ }
+
+ w->sections.export = offset;
+ return 0;
+}
diff --git a/src/section/function.c b/src/section/function.c
new file mode 100644
index 0000000..f03971c
--- /dev/null
+++ b/src/section/function.c
@@ -0,0 +1,80 @@
+#include <sections.h>
+#include <wasm_types.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+static int check(FILE *const f, const unsigned long len)
+{
+ const long start = ftell(f);
+
+ if (start < 0)
+ {
+ fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+
+ varuint32 count;
+
+ if (varuint32_read(f, &count))
+ {
+ fprintf(stderr, "%s: varuint32_read count failed\n", __func__);
+ return -1;
+ }
+
+ for (varuint32 i = 0; i < count; i++)
+ {
+ varuint32 type;
+
+ if (varuint32_read(f, &type))
+ {
+ fprintf(stderr, "%s: varuint32_read type failed\n", __func__);
+ return -1;
+ }
+ }
+
+ const long end = ftell(f);
+
+ if (end < 0)
+ {
+ fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+
+ const unsigned long size = end - start;
+
+ if (size != len)
+ {
+ fprintf(stderr, "%s: size exceeded (%lu expected, got %lu)\n",
+ __func__, len, size);
+ return -1;
+ }
+
+ return 0;
+}
+
+int section_function(struct wasmfs *const w, FILE *const f,
+ const unsigned long len)
+{
+ if (w->sections.function)
+ {
+ fprintf(stderr, "%s: ignoring duplicate section\n", __func__);
+ return 0;
+ }
+
+ const long offset = ftell(f);
+
+ if (offset < 0)
+ {
+ fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+ else if (check(f, len))
+ {
+ fprintf(stderr, "%s: check failed\n", __func__);
+ return -1;
+ }
+
+ w->sections.function = offset;
+ return 0;
+}
diff --git a/src/section/global.c b/src/section/global.c
new file mode 100644
index 0000000..5616e21
--- /dev/null
+++ b/src/section/global.c
@@ -0,0 +1,110 @@
+#include <sections.h>
+#include <interp.h>
+#include <wasm_types.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+struct global_type
+{
+ varint7 value_type;
+ varuint1 mutability;
+};
+
+static int check_global_type(FILE *const f, struct global_type *const g)
+{
+ if (varint7_read(f, &g->value_type))
+ {
+ fprintf(stderr, "%s: varint7_read failed\n", __func__);
+ return -1;
+ }
+ else if (varuint1_read(f, &g->mutability))
+ {
+ fprintf(stderr, "%s: varuint1_read failed\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int check(FILE *const f, const unsigned long len)
+{
+ int ret = -1;
+ struct global_type g;
+ struct interp *i = NULL;
+ const long start = ftell(f);
+ const struct interp_cfg cfg =
+ {
+ .f = f
+ };
+
+ if (start < 0)
+ {
+ fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+ else if (check_global_type(f, &g))
+ {
+ fprintf(stderr, "%s: check_global_type\n", __func__);
+ goto end;
+ }
+ else if (!(i = interp_alloc(&cfg)))
+ {
+ fprintf(stderr, "%s: interp_alloc failed\n", __func__);
+ goto end;
+ }
+ else if (interp_run_limited(i, &interp_initexpr_set))
+ {
+ fprintf(stderr, "%s: interp_run failed\n", __func__);
+ goto end;
+ }
+
+ const long end = ftell(f);
+
+ if (end < 0)
+ {
+ fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+
+ const unsigned long size = end - start;
+
+ if (size != len)
+ {
+ fprintf(stderr, "%s: size exceeded (%lu expected, got %lu)\n",
+ __func__, len, size);
+ return -1;
+ }
+
+ ret = 0;
+
+end:
+ interp_free(i);
+ return ret;
+}
+
+int section_global(struct wasmfs *const w, FILE *const f,
+ const unsigned long len)
+{
+ if (w->sections.global)
+ {
+ fprintf(stderr, "%s: ignoring duplicate section\n", __func__);
+ return 0;
+ }
+
+ const long offset = ftell(f);
+
+ if (offset < 0)
+ {
+ fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+ else if (check(f, len))
+ {
+ fprintf(stderr, "%s: check failed\n", __func__);
+ return -1;
+ }
+
+ w->sections.global = offset;
+ return 0;
+}
diff --git a/src/section/import.c b/src/section/import.c
new file mode 100644
index 0000000..06df4e1
--- /dev/null
+++ b/src/section/import.c
@@ -0,0 +1,188 @@
+#include <sections.h>
+#include <wasm_types.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+static int check_string(FILE *const f)
+{
+ varuint32 len;
+
+ if (varuint32_read(f, &len))
+ {
+ fprintf(stderr, "%s: varuint32_read failed\n", __func__);
+ return -1;
+ }
+
+ for (varuint32 i = 0; i < len; i++)
+ {
+ uint8_t byte;
+
+ if (!fread(&byte, sizeof byte, 1, f))
+ {
+ fprintf(stderr, "%s: fread(3) failed, feof=%d, ferror=%d\n",
+ __func__, feof(f), ferror(f));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int check_function_kind(FILE *const f)
+{
+ varuint32 type;
+
+ if (varuint32_read(f, &type))
+ {
+ fprintf(stderr, "%s: varuint32_read failed\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int check_table_kind(FILE *const f)
+{
+ varint7 type;
+
+ if (varint7_read(f, &type))
+ {
+ fprintf(stderr, "%s: varint7_read failed\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int check_memory_kind(FILE *const f)
+{
+ /* TODO. */
+ return -1;
+}
+
+static int check_global_kind(FILE *const f)
+{
+ /* TODO. */
+ return -1;
+}
+
+static int check_import_entry(FILE *const f)
+{
+ if (check_string(f))
+ {
+ fprintf(stderr, "%s: check_string module failed\n", __func__);
+ return -1;
+ }
+ else if (check_string(f))
+ {
+ fprintf(stderr, "%s: check_string field failed\n", __func__);
+ return -1;
+ }
+
+ uint8_t kind;
+
+ enum
+ {
+ FUNCTION,
+ TABLE,
+ MEMORY,
+ GLOBAL
+ };
+
+ if (!fread(&kind, sizeof kind, 1, f))
+ {
+ fprintf(stderr, "%s: fread(3) failed, feof=%d, ferror=%d\n",
+ __func__, feof(f), ferror(f));
+ return -1;
+ }
+
+ static int (*const fn[])(FILE *) =
+ {
+ [FUNCTION] = check_function_kind,
+ [TABLE] = check_table_kind,
+ [MEMORY] = check_memory_kind,
+ [GLOBAL] = check_global_kind
+ };
+
+ if (kind >= sizeof fn / sizeof *fn)
+ {
+ fprintf(stderr, "%s: unexpected kind %#" PRIx8 "\n", __func__, kind);
+ return -1;
+ }
+
+ return fn[kind](f);
+}
+
+static int check(FILE *const f, const unsigned long len)
+{
+ const long start = ftell(f);
+
+ if (start < 0)
+ {
+ fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+
+ varuint32 count;
+
+ if (varuint32_read(f, &count))
+ {
+ fprintf(stderr, "%s: varuint32_read failed\n", __func__);
+ return -1;
+ }
+
+ for (varuint32 i = 0; i < count; i++)
+ if (check_import_entry(f))
+ {
+ fprintf(stderr, "%s: check_import_entry failed\n", __func__);
+ return -1;
+ }
+
+ const long end = ftell(f);
+
+ if (end < 0)
+ {
+ fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+
+ const unsigned long size = end - start;
+
+ if (size != len)
+ {
+ fprintf(stderr, "%s: size exceeded (%lu expected, got %lu)\n",
+ __func__, len, size);
+ return -1;
+ }
+
+ return 0;
+}
+
+int section_import(struct wasmfs *const w, FILE *const f,
+ const unsigned long len)
+{
+ if (w->sections.import)
+ {
+ fprintf(stderr, "%s: ignoring duplicate section\n", __func__);
+ return 0;
+ }
+
+ const long offset = ftell(f);
+
+ if (offset < 0)
+ {
+ fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+ else if (check(f, len))
+ {
+ fprintf(stderr, "%s: check failed\n", __func__);
+ return -1;
+ }
+
+ w->sections.import = offset;
+ return 0;
+}
diff --git a/src/section/memory.c b/src/section/memory.c
new file mode 100644
index 0000000..aba461a
--- /dev/null
+++ b/src/section/memory.c
@@ -0,0 +1,81 @@
+#include <sections.h>
+#include <wasm_types.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+static int check_memory_type(FILE *const f)
+{
+ return check_resizable_limits(f);
+}
+
+static int check(FILE *const f, const unsigned long len)
+{
+ const long start = ftell(f);
+
+ if (start < 0)
+ {
+ fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+
+ varuint32 count;
+
+ if (varuint32_read(f, &count))
+ {
+ fprintf(stderr, "%s: varuint32_read failed\n", __func__);
+ return -1;
+ }
+
+ for (varuint32 i = 0; i < count; i++)
+ if (check_memory_type(f))
+ {
+ fprintf(stderr, "%s: check_memory_type failed\n", __func__);
+ return -1;
+ }
+
+ const long end = ftell(f);
+
+ if (end < 0)
+ {
+ fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+
+ const unsigned long size = end - start;
+
+ if (size != len)
+ {
+ fprintf(stderr, "%s: size exceeded (%lu expected, got %lu)\n",
+ __func__, len, size);
+ return -1;
+ }
+
+ return 0;
+}
+
+int section_memory(struct wasmfs *const w, FILE *const f,
+ const unsigned long len)
+{
+ if (w->sections.memory)
+ {
+ fprintf(stderr, "%s: ignoring duplicate section\n", __func__);
+ return 0;
+ }
+
+ const long offset = ftell(f);
+
+ if (offset < 0)
+ {
+ fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+ else if (check(f, len))
+ {
+ fprintf(stderr, "%s: check failed\n", __func__);
+ return -1;
+ }
+
+ w->sections.memory = offset;
+ return 0;
+}
diff --git a/src/section/start.c b/src/section/start.c
new file mode 100644
index 0000000..821525d
--- /dev/null
+++ b/src/section/start.c
@@ -0,0 +1,8 @@
+#include <sections.h>
+#include <wasm_types.h>
+
+int section_start(struct wasmfs *const w, FILE *const f,
+ const unsigned long len)
+{
+ return -1;
+}
diff --git a/src/section/table.c b/src/section/table.c
new file mode 100644
index 0000000..9f793c7
--- /dev/null
+++ b/src/section/table.c
@@ -0,0 +1,96 @@
+#include <sections.h>
+#include <wasm_types.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+static int check_table_type(FILE *const f)
+{
+ enum {ANYFUNC = 0x70};
+ varint7 elem_type;
+
+ if (varint7_read(f, &elem_type))
+ {
+ fprintf(stderr, "%s: varint7_read failed\n", __func__);
+ return -1;
+ }
+ else if (elem_type != ANYFUNC)
+ {
+ fprintf(stderr, "%s: expected %x, got %x", __func__, ANYFUNC,
+ (int)elem_type);
+ return -1;
+ }
+
+ return check_resizable_limits(f);
+}
+
+static int check(FILE *const f, const unsigned long len)
+{
+ const long start = ftell(f);
+
+ if (start < 0)
+ {
+ fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+
+ varuint32 count;
+
+ if (varuint32_read(f, &count))
+ {
+ fprintf(stderr, "%s: varuint32_read failed\n", __func__);
+ return -1;
+ }
+
+ for (varuint32 i = 0; i < count; i++)
+ if (check_table_type(f))
+ {
+ fprintf(stderr, "%s: check_table_type failed\n", __func__);
+ return -1;
+ }
+
+ const long end = ftell(f);
+
+ if (end < 0)
+ {
+ fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+
+ const unsigned long size = end - start;
+
+ if (size != len)
+ {
+ fprintf(stderr, "%s: size exceeded (%lu expected, got %lu)\n",
+ __func__, len, size);
+ return -1;
+ }
+
+ return 0;
+}
+
+int section_table(struct wasmfs *const w, FILE *const f,
+ const unsigned long len)
+{
+ if (w->sections.table)
+ {
+ fprintf(stderr, "%s: ignoring duplicate section\n", __func__);
+ return 0;
+ }
+
+ const long offset = ftell(f);
+
+ if (offset < 0)
+ {
+ fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+ else if (check(f, len))
+ {
+ fprintf(stderr, "%s: check failed\n", __func__);
+ return -1;
+ }
+
+ w->sections.table = offset;
+ return 0;
+}
diff --git a/src/section/type.c b/src/section/type.c
new file mode 100644
index 0000000..fad2208
--- /dev/null
+++ b/src/section/type.c
@@ -0,0 +1,126 @@
+#include <sections.h>
+#include <wasm_types.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+static int check_value_type(FILE *const f)
+{
+ varint7 value_type;
+
+ if (varint7_read(f, &value_type))
+ {
+ fprintf(stderr, "%s: varint7_read failed\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int check_func_type(FILE *const f)
+{
+ varint7 form;
+ varuint32 param_count;
+
+ if (varint7_read(f, &form))
+ {
+ fprintf(stderr, "%s: varint7_read failed\n", __func__);
+ return -1;
+ }
+ else if (varuint32_read(f, &param_count))
+ {
+ fprintf(stderr, "%s: varuint32_read failed\n", __func__);
+ return -1;
+ }
+
+ for (varuint32 i = 0; i < param_count; i++)
+ if (check_value_type(f))
+ {
+ fprintf(stderr, "%s: check_value_type failed\n", __func__);
+ return -1;
+ }
+
+ varuint1 return_count;
+
+ if (varuint1_read(f, &return_count))
+ {
+ fprintf(stderr, "%s: varuint1_read failed\n", __func__);
+ return -1;
+ }
+ else if (return_count && check_value_type(f))
+ {
+ fprintf(stderr, "%s: check_value_type 2 failed\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int check(FILE *const f, const unsigned long len)
+{
+ const long start = ftell(f);
+ varuint32 count;
+
+ if (start < 0)
+ {
+ fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+ else if (varuint32_read(f, &count))
+ {
+ fprintf(stderr, "%s: varuint32_read failed\n", __func__);
+ return -1;
+ }
+
+ for (varuint32 i = 0; i < count; i++)
+ if (check_func_type(f))
+ {
+ fprintf(stderr, "%s: check_func_type failed\n", __func__);
+ return -1;
+ }
+
+ const long end = ftell(f);
+
+ if (end < 0)
+ {
+ fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+
+ const unsigned long size = end - start;
+
+ if (size != len)
+ {
+ fprintf(stderr, "%s: size exceeded (%lu expected, got %lu)\n",
+ __func__, len, size);
+ return -1;
+ }
+
+ return 0;
+}
+
+int section_type(struct wasmfs *const w, FILE *const f,
+ const unsigned long len)
+{
+ if (w->sections.type)
+ {
+ fprintf(stderr, "%s: ignoring duplicate section\n", __func__);
+ return 0;
+ }
+
+ const long offset = ftell(f);
+
+ if (offset < 0)
+ {
+ fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+ else if (check(f, len))
+ {
+ fprintf(stderr, "%s: check failed\n", __func__);
+ return -1;
+ }
+
+ w->sections.type = offset;
+ return 0;
+}