diff options
Diffstat (limited to 'read_instr.c')
| -rw-r--r-- | read_instr.c | 253 |
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)) |
