aboutsummaryrefslogtreecommitdiff
path: root/read_instr.c
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi92@disroot.org>2025-11-15 23:13:20 +0100
committerXavier Del Campo Romero <xavi92@disroot.org>2025-11-15 23:13:20 +0100
commit690cfd848c81550aa96d1643eaf57ef28d7841fe (patch)
treefa38d8e3555e2fad816bca88b39561acf433952a /read_instr.c
parent7fd2847cc5b45acbf8b6f0ca6608355f3fd277eb (diff)
Support br_tableHEADmaster
Diffstat (limited to 'read_instr.c')
-rw-r--r--read_instr.c253
1 files changed, 165 insertions, 88 deletions
diff --git a/read_instr.c b/read_instr.c
index 907069d..465529f 100644
--- a/read_instr.c
+++ b/read_instr.c
@@ -26,89 +26,127 @@
#include <stdlib.h>
#include <string.h>
-static int imm_none(FILE *const f, varuint32 *v)
+struct imm
+{
+ enum {IMM_VARUINT32, IMM_TABLE} type;
+
+ union
+ {
+ varuint32 varuint32;
+
+ struct imm_table
+ {
+ varuint32 target_count, *targets;
+ } table;
+ } u;
+};
+
+static void free_imm(struct imm *const imm)
+{
+ switch (imm->type)
+ {
+ case IMM_VARUINT32:
+ break;
+
+ case IMM_TABLE:
+ {
+ struct imm_table *const t = &imm->u.table;
+
+ free(t->targets);
+ }
+ break;
+ }
+}
+
+static int imm_none(FILE *const f, struct imm *const imm)
{
return 0;
}
-static int instr_sig(FILE *const f, varuint32 *v)
+static int instr_sig(FILE *const f, struct imm *const imm)
{
return read_varint7(f, &(varint7){0});
}
-static int imm_readvaruint1(FILE *const f, varuint32 *v)
+static int imm_readvaruint1(FILE *const f, struct imm *const imm)
{
return read_varuint1(f, &(varuint1){0});
}
-static int imm_varuint32(FILE *const f, varuint32 *v)
+static int imm_varuint32(FILE *const f, struct imm *const imm)
{
- return read_varuint32(f, v);
+ imm->type = IMM_VARUINT32;
+ return read_varuint32(f, &imm->u.varuint32);
}
-static int imm_varuint64(FILE *const f, varuint32 *v)
+static int imm_varuint64(FILE *const f, struct imm *const imm)
{
return read_varuint64(f, &(varuint64){0});
}
-static int imm_varint32(FILE *const f, varuint32 *v)
+static int imm_varint32(FILE *const f, struct imm *const imm)
{
return read_varint32(f, &(varint32){0});
}
-static int imm_varint64(FILE *const f, varuint32 *v)
+static int imm_varint64(FILE *const f, struct imm *const imm)
{
return read_varint64(f, &(varint64){0});
}
-static int imm_memory(FILE *const f, varuint32 *v)
+static int imm_memory(FILE *const f, struct imm *const imm)
{
return read_varuint32(f, &(varuint32){0})
|| read_varuint32(f, &(varuint32){0});
}
-static int imm_uint32(FILE *const f, varuint32 *d)
+static int imm_uint32(FILE *const f, struct imm *const imm)
{
uint32_t v;
return !fread(&v, sizeof v, 1, f);
}
-static int imm_uint64(FILE *const f, varuint32 *d)
+static int imm_uint64(FILE *const f, struct imm *const imm)
{
uint64_t v;
return !fread(&v, sizeof v, 1, f);
}
-static int imm_table(FILE *const f, varuint32 *v)
+static int imm_table(FILE *const f, struct imm *const imm)
{
- varuint32 table_count;
+ struct imm table = {.type = IMM_TABLE};
+ struct imm_table *const t = &table.u.table;
- if (read_varuint32(f, &table_count))
+ if (read_varuint32(f, &t->target_count))
{
fprintf(stderr, "%s: read_varuint32 failed\n", __func__);
- return -1;
+ goto failure;
+ }
+ else if (!(t->targets = malloc((t->target_count + 1) * sizeof *t->targets)))
+ {
+ fprintf(stderr, "%s: malloc(3): %s\n", __func__, strerror(errno));
+ goto failure;
}
- for (varuint32 i = 0; i < table_count; i++)
- if (read_varuint32(f, &(varuint32){0}))
+ for (varuint32 i = 0; i < (t->target_count + 1); i++)
+ if (read_varuint32(f, &t->targets[i]))
{
fprintf(stderr, "%s: read_varuint32 %lu failed\n", __func__,
(unsigned long)i);
- return -1;
+ goto failure;
}
- if (read_varuint32(f, &(varuint32){0}))
- {
- fprintf(stderr, "%s: read_varuint32 failed\n", __func__);
- return -1;
- }
-
+ *imm = table;
return 0;
+
+failure:
+ free_imm(&table);
+ return -1;
}
-static int imm_call_indirect(FILE *const f, varuint32 *v)
+static int imm_call_indirect(FILE *const f, struct imm *const imm)
{
varuint32 reserved;
@@ -131,7 +169,7 @@ static int imm_call_indirect(FILE *const f, varuint32 *v)
return 0;
}
-static int imm_extra(FILE *const f, varuint32 *v)
+static int imm_extra(FILE *const f, struct imm *const imm)
{
uint8_t b;
@@ -313,7 +351,7 @@ static int imm_extra(FILE *const f, varuint32 *v)
X(OP_F64_REINTERPRET_I64, imm_none) \
X(OP_EXTRA, imm_extra)
-static int (*const table[])(FILE *, varuint32 *) =
+static int (*const table[])(FILE *, struct imm *) =
{
#define X(x, y) [x] = y,
OPS
@@ -538,6 +576,19 @@ static int add_cbranch(const uint8_t op, struct lo *const lo,
return 0;
}
+static int add_brtable(struct lo *const lo, const struct blocks *const b,
+ const struct imm_table *const t, const unsigned level, FILE *const f)
+{
+ for (varuint32 i = 0; i < (t->target_count + 1); i++)
+ if (add_branch(OP_BR_TABLE, lo, b, t->targets[i], level, f))
+ {
+ fprintf(stderr, "%s: add_branch failed\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
static int set_end(struct lo *const lo, const struct blocks *const b,
const unsigned level, FILE *const f)
{
@@ -633,77 +684,103 @@ static void free_blocks(struct blocks *const b)
}
}
-int read_instr(FILE *const f, struct parse *const p)
+static int read_one(struct lo *const lo, struct blocks *const b,
+ unsigned *const level, FILE *const f)
{
+ int ret = -1;
+ size_t n;
uint8_t op;
+ struct imm imm = {0};
+ const long offset = ftell(f);
+
+ if (offset < 0)
+ {
+ fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno));
+ goto end;
+ }
+ else if (!(n = fread(&op, sizeof op, 1, f)))
+ {
+ fprintf(stderr, "%s: fread(3) failed, ferror(3)=%d, feof(3)=%d\n",
+ __func__, ferror(f), feof(f));
+ goto end;
+ }
+ else if (op >= sizeof table / sizeof *table || !table[op])
+ {
+ fprintf(stderr, "%s: invalid or unsupported opcode %#" PRIx8 ", "
+ "offset=%#lx\n", __func__, op, offset);
+ goto end;
+ }
+ else if (table[op](f, &imm))
+ {
+ fprintf(stderr, "%s: failed to read opcode %#" PRIx8 "\n",
+ __func__, op);
+ goto end;
+ }
+ else if (scoped(op) && add_block(b, op, ++(*level), f))
+ {
+ fprintf(stderr, "%s: add_block failed\n", __func__);
+ goto end;
+ }
+ else if (branch(op) && add_branch(op, lo, b, imm.u.varuint32, *level, f))
+ {
+ fprintf(stderr, "%s: add_branch failed\n", __func__);
+ goto end;
+ }
+ else if (cbranch(op) && add_cbranch(op, lo, b, *level, f))
+ {
+ fprintf(stderr, "%s: add_cbranch failed\n", __func__);
+ goto end;
+ }
+ else if (op == OP_BR_TABLE && add_brtable(lo, b, &imm.u.table, *level, f))
+ {
+ fprintf(stderr, "%s: add_brtable failed\n", __func__);
+ goto end;
+ }
+ else if (op == OP_ELSE && set_else(lo, b, *level, f))
+ {
+ fprintf(stderr, "%s: set_else failed\n", __func__);
+ goto end;
+ }
+ else if (op == OP_END)
+ {
+ if (*level)
+ {
+ if (set_end(lo, b, *level, f))
+ {
+ fprintf(stderr, "%s: set_end failed\n", __func__);
+ goto end;
+ }
+
+ (*level)--;
+ }
+ else
+ {
+ ret = 1;
+ goto end;
+ }
+ }
+
+ ret = 0;
+
+end:
+ free_imm(&imm);
+ return ret;
+}
+
+int read_instr(FILE *const f, struct parse *const p)
+{
unsigned level = 0;
struct lo lo = {0};
struct blocks b = {0};
for (;;)
{
- size_t n;
- varuint32 relative_depth;
- const long offset = ftell(f);
+ const int n = read_one(&lo, &b, &level, f);
- if (offset < 0)
- {
- fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno));
+ if (n < 0)
goto failure;
- }
- else if (!(n = fread(&op, sizeof op, 1, f)))
- {
- fprintf(stderr, "%s: fread(3) failed, ferror(3)=%d, feof(3)=%d\n",
- __func__, ferror(f), feof(f));
- goto failure;
- }
- else if (op >= sizeof table / sizeof *table || !table[op])
- {
- fprintf(stderr, "%s: invalid or unsupported opcode %#" PRIx8 ", "
- "offset=%#lx\n", __func__, op, offset);
- goto failure;
- }
- else if (table[op](f, &relative_depth))
- {
- fprintf(stderr, "%s: failed to read opcode %#" PRIx8 "\n",
- __func__, op);
- goto failure;
- }
- else if (scoped(op) && add_block(&b, op, ++level, f))
- {
- fprintf(stderr, "%s: add_block failed\n", __func__);
- goto failure;
- }
- else if (branch(op) && add_branch(op, &lo, &b, relative_depth, level, f))
- {
- fprintf(stderr, "%s: add_branch failed\n", __func__);
- goto failure;
- }
- else if (cbranch(op) && add_cbranch(op, &lo, &b, level, f))
- {
- fprintf(stderr, "%s: add_cbranch failed\n", __func__);
- goto failure;
- }
- else if (op == OP_ELSE && set_else(&lo, &b, level, f))
- {
- fprintf(stderr, "%s: set_else failed\n", __func__);
- goto failure;
- }
- else if (op == OP_END)
- {
- if (level)
- {
- if (set_end(&lo, &b, level, f))
- {
- fprintf(stderr, "%s: set_end failed\n", __func__);
- return -1;
- }
-
- level--;
- }
- else
- break;
- }
+ else if (n)
+ break;
}
if (append_lo(&lo, p))