diff options
| author | Xavier Del Campo Romero <xavi92@disroot.org> | 2025-11-02 18:21:49 +0100 |
|---|---|---|
| committer | Xavier Del Campo Romero <xavi92@disroot.org> | 2025-11-12 00:47:10 +0100 |
| commit | b16e2f67e7d392890c6835f98ca9b2a7bb44fe2e (patch) | |
| tree | cf07afb610395dd182e1f243ffccf2a55a13effe /instr.cpp | |
Diffstat (limited to 'instr.cpp')
| -rw-r--r-- | instr.cpp | 623 |
1 files changed, 623 insertions, 0 deletions
diff --git a/instr.cpp b/instr.cpp new file mode 100644 index 0000000..db4f79b --- /dev/null +++ b/instr.cpp @@ -0,0 +1,623 @@ +#include "instr.h" +#include <QString> +#include <QVector> +#include <stdio.h> + +static int imm_none(FILE *const f, QString &instr) +{ + return 0; +} + +static int instr_sig(FILE *const f, QString &instr) +{ + varint7 sig; + + if (read_varint7(f, &sig)) + return -1; + + instr = QString::number(sig); + return 0; +} + +static int imm_readvaruint1(FILE *const f, QString &instr) +{ + varuint1 v; + + if (read_varuint1(f, &v)) + return -1; + + instr = QString::number(v); + return 0; +} + +static int imm_varuint32(FILE *const f, QString &instr) +{ + varuint32 v; + + if (read_varuint32(f, &v)) + return -1; + + instr = QString::number(v); + return 0; +} + +static int imm_varint32(FILE *const f, QString &instr) +{ + varint32 v; + + if (read_varint32(f, &v)) + return -1; + + instr = QString::number(v); + return 0; +} + +static int imm_varint64(FILE *const f, QString &instr) +{ + varint64 v; + + if (read_varint64(f, &v)) + return -1; + + instr = QString::number(v); + return 0; +} + +static int imm_memory(FILE *const f, QString &instr) +{ + varuint32 flags, offset; + + if (read_varuint32(f, &flags) + || read_varuint32(f, &offset)) + return -1; + + instr = "flags=0x" + QString::number(flags, 16) + + ", offset=0x" + QString::number(offset, 16); + return 0; +} + +static int imm_uint32(FILE *const f, QString &instr) +{ + uint32_t v; + + if (!fread(&v, sizeof v, 1, f)) + return -1; + + instr = QString::number(v); + return 0; +} + +static int imm_uint64(FILE *const f, QString &instr) +{ + uint64_t v; + + if (!fread(&v, sizeof v, 1, f)) + return -1; + + instr = QString::number(v); + return 0; +} + +static int imm_table(FILE *const f, QString &instr) +{ + varuint32 table_count; + + if (read_varuint32(f, &table_count)) + { + fprintf(stderr, "%s: read_varuint32 failed\n", __func__); + return -1; + } + + instr = "count=" + QString::number(table_count) + ": ["; + + for (varuint32 i = 0; i < table_count; i++) + { + varuint32 v; + + if (read_varuint32(f, &v)) + { + fprintf(stderr, "%s: read_varuint32 %lu failed\n", __func__, + (unsigned long)i); + return -1; + } + + instr += QString::number(v); + + if (i + 1 < table_count) + instr += ", "; + } + + varuint32 default_target; + + instr += "], default_target="; + + if (read_varuint32(f, &default_target)) + { + fprintf(stderr, "%s: read_varuint32 failed\n", __func__); + return -1; + } + + instr += QString::number(default_target); + return 0; +} + +static int imm_call_indirect(FILE *const f, QString &instr) +{ + varuint32 type_index, reserved; + + if (read_varuint32(f, &type_index)) + { + fprintf(stderr, "%s: read_varuint32 failed\n", __func__); + return -1; + } + else if (read_varuint32(f, &reserved)) + { + fprintf(stderr, "%s: read_varuint1 failed\n", __func__); + return -1; + } + else if (reserved) + { + fprintf(stderr, "%s: expected zero for reserved field\n", __func__); + return -1; + } + + instr = QString::number(type_index); + return 0; +} + +static int imm_extra(FILE *const f, QString &instr) +{ + uint8_t v; + + if (!fread(&v, sizeof v, 1, f)) + return -1; + + instr = QString::number(v); + return 0; +} + +enum op +{ + OP_UNREACHABLE, + OP_NOP, + OP_BLOCK, + OP_LOOP, + OP_IF, + OP_ELSE, + OP_END = 0xb, + OP_BR, + OP_BR_IF, + OP_BR_TABLE, + OP_RETURN, + OP_CALL, + OP_CALL_INDIRECT, + OP_DROP = 0x1a, + OP_SELECT, + OP_GET_LOCAL = 0x20, + OP_SET_LOCAL, + OP_TEE_LOCAL, + OP_GET_GLOBAL, + OP_SET_GLOBAL, + OP_I32_LOAD = 0x28, + OP_I64_LOAD, + OP_F32_LOAD, + OP_F64_LOAD, + OP_I32_LOAD8_S, + OP_I32_LOAD8_U, + OP_I32_LOAD16_S, + OP_I32_LOAD16_U, + OP_I64_LOAD8_S, + OP_I64_LOAD8_U, + OP_I64_LOAD16_S, + OP_I64_LOAD16_U, + OP_I64_LOAD32_S, + OP_I64_LOAD32_U, + OP_I32_STORE, + OP_I64_STORE, + OP_F32_STORE, + OP_F64_STORE, + OP_I32_STORE8, + OP_I32_STORE16, + OP_I64_STORE8, + OP_I64_STORE16, + OP_I64_STORE32, + OP_CURRENT_MEMORY, + OP_GROW_MEMORY, + OP_I32_CONST, + OP_I64_CONST, + OP_F32_CONST, + OP_F64_CONST, + OP_I32_EQZ, + OP_I32_EQ, + OP_I32_NE, + OP_I32_LT_S, + OP_I32_LT_U, + OP_I32_GT_S, + OP_I32_GT_U, + OP_I32_LE_S, + OP_I32_LE_U, + OP_I32_GE_S, + OP_I32_GE_U, + OP_I64_EQZ, + OP_I64_EQ, + OP_I64_NE, + OP_I64_LT_S, + OP_I64_LT_U, + OP_I64_GT_S, + OP_I64_GT_U, + OP_I64_LE_S, + OP_I64_LE_U, + OP_I64_GE_S, + OP_I64_GE_U, + OP_F32_EQ, + OP_F32_NE, + OP_F32_LT, + OP_F32_GT, + OP_F32_LE, + OP_F32_GE, + OP_F64_EQ, + OP_F64_NE, + OP_F64_LT, + OP_F64_GT, + OP_F64_LE, + OP_F64_GE, + OP_I32_CLZ, + OP_I32_CTZ, + OP_I32_POPCNT, + OP_I32_ADD, + OP_I32_SUB, + OP_I32_MUL, + OP_I32_DIV_S, + OP_I32_DIV_U, + OP_I32_REM_S, + OP_I32_REM_U, + OP_I32_AND, + OP_I32_OR, + OP_I32_XOR, + OP_I32_SHL, + OP_I32_SHR_S, + OP_I32_SHR_U, + OP_I32_ROTL, + OP_I32_ROTR, + OP_I64_CLZ, + OP_I64_CTZ, + OP_I64_POPCNT, + OP_I64_ADD, + OP_I64_SUB, + OP_I64_MUL, + OP_I64_DIV_S, + OP_I64_DIV_U, + OP_I64_REM_S, + OP_I64_REM_U, + OP_I64_AND, + OP_I64_OR, + OP_I64_XOR, + OP_I64_SHL, + OP_I64_SHR_S, + OP_I64_SHR_U, + OP_I64_ROTL, + OP_I64_ROTR, + OP_F32_ABS, + OP_F32_NEG, + OP_F32_CEIL, + OP_F32_FLOOR, + OP_F32_TRUNC, + OP_F32_NEAREST, + OP_F32_SQRT, + OP_F32_ADD, + OP_F32_SUB, + OP_F32_MUL, + OP_F32_DIV, + OP_F32_MIN, + OP_F32_MAX, + OP_F32_COPYSIGN, + OP_F64_ABS, + OP_F64_NEG, + OP_F64_CEIL, + OP_F64_FLOOR, + OP_F64_TRUNC, + OP_F64_NEAREST, + OP_F64_SQRT, + OP_F64_ADD, + OP_F64_SUB, + OP_F64_MUL, + OP_F64_DIV, + OP_F64_MIN, + OP_F64_MAX, + OP_F64_COPYSIGN, + OP_I32_WRAP_I64, + OP_I32_TRUNC_S_F32, + OP_I32_TRUNC_U_F32, + OP_I32_TRUNC_S_F64, + OP_I32_TRUNC_U_F64, + OP_I64_EXTEND_S_I32, + OP_I64_EXTEND_U_I32, + OP_I64_TRUNC_S_F32, + OP_I64_TRUNC_U_F32, + OP_I64_TRUNC_S_F64, + OP_I64_TRUNC_U_F64, + OP_F32_CONVERT_S_I32, + OP_F32_CONVERT_U_I32, + OP_F32_CONVERT_S_I64, + OP_F32_CONVERT_U_I64, + OP_F32_DEMOTE_F64, + OP_F64_CONVERT_S_I32, + OP_F64_CONVERT_U_I32, + OP_F64_CONVERT_S_I64, + OP_F64_CONVERT_U_I64, + OP_F64_PROMOTE_F32, + OP_I32_REINTERPRET_F32, + OP_I64_REINTERPRET_F64, + OP_F32_REINTERPRET_I32, + OP_F64_REINTERPRET_I64, + OP_EXTRA = 0xfc, +}; + +#define OPS \ + X(OP_UNREACHABLE, "unreachable", imm_none) \ + X(OP_NOP, "nop", imm_none) \ + X(OP_BLOCK, "block", instr_sig) \ + X(OP_LOOP, "loop", instr_sig) \ + X(OP_IF, "if", instr_sig) \ + X(OP_ELSE, "else", imm_none) \ + X(OP_END, "end", imm_none) \ + X(OP_BR, "br", imm_varuint32) \ + X(OP_BR_IF, "br_if", imm_varuint32) \ + X(OP_BR_TABLE, "br_table", imm_table) \ + X(OP_RETURN, "return", imm_none) \ + X(OP_CALL, "call", imm_varuint32) \ + X(OP_CALL_INDIRECT, "call_indirect", imm_call_indirect) \ + X(OP_DROP, "drop", imm_none) \ + X(OP_SELECT, "select", imm_none) \ + X(OP_GET_LOCAL, "get_local", imm_varuint32) \ + X(OP_SET_LOCAL, "set_local", imm_varuint32) \ + X(OP_TEE_LOCAL, "tee_local", imm_varuint32) \ + X(OP_GET_GLOBAL, "get_global", imm_varuint32) \ + X(OP_SET_GLOBAL, "set_global", imm_varuint32) \ + X(OP_I32_LOAD, "i32_load", imm_memory) \ + X(OP_I64_LOAD, "i64_load", imm_memory) \ + X(OP_F32_LOAD, "f32_load", imm_memory) \ + X(OP_F64_LOAD, "f64_load", imm_memory) \ + X(OP_I32_LOAD8_S, "i32_load8_s", imm_memory) \ + X(OP_I32_LOAD8_U, "i32_load8_u", imm_memory) \ + X(OP_I32_LOAD16_S, "i32_load16_s", imm_memory) \ + X(OP_I32_LOAD16_U, "i32_load16_u", imm_memory) \ + X(OP_I64_LOAD8_S, "i64_load8_s", imm_memory) \ + X(OP_I64_LOAD8_U, "i64_load8_u", imm_memory) \ + X(OP_I64_LOAD16_S, "i64_load16_s", imm_memory) \ + X(OP_I64_LOAD16_U, "i64_load16_u", imm_memory) \ + X(OP_I64_LOAD32_S, "i64_load32_s", imm_memory) \ + X(OP_I64_LOAD32_U, "i64_load32_u", imm_memory) \ + X(OP_I32_STORE, "i32_store", imm_memory) \ + X(OP_I64_STORE, "i64_store", imm_memory) \ + X(OP_F32_STORE, "f32_store", imm_memory) \ + X(OP_F64_STORE, "f64_store", imm_memory) \ + X(OP_I32_STORE8, "i32_store8", imm_memory) \ + X(OP_I32_STORE16, "i32_store16", imm_memory) \ + X(OP_I64_STORE8, "i64_store8", imm_memory) \ + X(OP_I64_STORE16, "i64_store16", imm_memory) \ + X(OP_I64_STORE32, "i64_store32", imm_memory) \ + X(OP_CURRENT_MEMORY, "current_memory", imm_readvaruint1) \ + X(OP_GROW_MEMORY, "grow_memory", imm_readvaruint1) \ + X(OP_I32_CONST, "i32_const", imm_varint32) \ + X(OP_I64_CONST, "i64_const", imm_varint64) \ + X(OP_F32_CONST, "f32_const", imm_uint32) \ + X(OP_F64_CONST, "f64_const", imm_uint64) \ + X(OP_I32_EQZ, "i32_eqz", imm_none) \ + X(OP_I32_EQ, "i32_eq", imm_none) \ + X(OP_I32_NE, "i32_ne", imm_none) \ + X(OP_I32_LT_S, "i32_lt_s", imm_none) \ + X(OP_I32_LT_U, "i32_lt_u", imm_none) \ + X(OP_I32_GT_S, "i32_gt_s", imm_none) \ + X(OP_I32_GT_U, "i32_gt_u", imm_none) \ + X(OP_I32_LE_S, "i32_le_s", imm_none) \ + X(OP_I32_LE_U, "i32_le_u", imm_none) \ + X(OP_I32_GE_S, "i32_ge_s", imm_none) \ + X(OP_I32_GE_U, "i32_ge_u", imm_none) \ + X(OP_I64_EQZ, "i64_eqz", imm_none) \ + X(OP_I64_EQ, "i64_eq", imm_none) \ + X(OP_I64_NE, "i64_ne", imm_none) \ + X(OP_I64_LT_S, "i64_lt_s", imm_none) \ + X(OP_I64_LT_U, "i64_lt_u", imm_none) \ + X(OP_I64_GT_S, "i64_gt_s", imm_none) \ + X(OP_I64_GT_U, "i64_gt_u", imm_none) \ + X(OP_I64_LE_S, "i64_le_s", imm_none) \ + X(OP_I64_LE_U, "i64_le_u", imm_none) \ + X(OP_I64_GE_S, "i64_ge_s", imm_none) \ + X(OP_I64_GE_U, "i64_ge_u", imm_none) \ + X(OP_F32_EQ, "f32_eq", imm_none) \ + X(OP_F32_NE, "f32_ne", imm_none) \ + X(OP_F32_LT, "f32_lt", imm_none) \ + X(OP_F32_GT, "f32_gt", imm_none) \ + X(OP_F32_LE, "f32_le", imm_none) \ + X(OP_F32_GE, "f32_ge", imm_none) \ + X(OP_F64_EQ, "f64_eq", imm_none) \ + X(OP_F64_NE, "f64_ne", imm_none) \ + X(OP_F64_LT, "f64_lt", imm_none) \ + X(OP_F64_GT, "f64_gt", imm_none) \ + X(OP_F64_LE, "f64_le", imm_none) \ + X(OP_F64_GE, "f64_ge", imm_none) \ + X(OP_I32_CLZ, "i32_clz", imm_none) \ + X(OP_I32_CTZ, "i32_ctz", imm_none) \ + X(OP_I32_POPCNT, "i32_popcnt", imm_none) \ + X(OP_I32_ADD, "i32_add", imm_none) \ + X(OP_I32_SUB, "i32_sub", imm_none) \ + X(OP_I32_MUL, "i32_mul", imm_none) \ + X(OP_I32_DIV_S, "i32_div_s", imm_none) \ + X(OP_I32_DIV_U, "i32_div_u", imm_none) \ + X(OP_I32_REM_S, "i32_rem_s", imm_none) \ + X(OP_I32_REM_U, "i32_rem_u", imm_none) \ + X(OP_I32_AND, "i32_and", imm_none) \ + X(OP_I32_OR, "i32_or", imm_none) \ + X(OP_I32_XOR, "i32_xor", imm_none) \ + X(OP_I32_SHL, "i32_shl", imm_none) \ + X(OP_I32_SHR_S, "i32_shr_s", imm_none) \ + X(OP_I32_SHR_U, "i32_shr_u", imm_none) \ + X(OP_I32_ROTL, "i32_rotl", imm_none) \ + X(OP_I32_ROTR, "i32_rotr", imm_none) \ + X(OP_I64_CLZ, "i64_clz", imm_none) \ + X(OP_I64_CTZ, "i64_ctz", imm_none) \ + X(OP_I64_POPCNT, "i64_popcnt", imm_none) \ + X(OP_I64_ADD, "i64_add", imm_none) \ + X(OP_I64_SUB, "i64_sub", imm_none) \ + X(OP_I64_MUL, "i64_mul", imm_none) \ + X(OP_I64_DIV_S, "i64_div_s", imm_none) \ + X(OP_I64_DIV_U, "i64_div_u", imm_none) \ + X(OP_I64_REM_S, "i64_rem_s", imm_none) \ + X(OP_I64_REM_U, "i64_rem_u", imm_none) \ + X(OP_I64_AND, "i64_and", imm_none) \ + X(OP_I64_OR, "i64_or", imm_none) \ + X(OP_I64_XOR, "i64_xor", imm_none) \ + X(OP_I64_SHL, "i64_shl", imm_none) \ + X(OP_I64_SHR_S, "i64_shr_s", imm_none) \ + X(OP_I64_SHR_U, "i64_shr_u", imm_none) \ + X(OP_I64_ROTL, "i64_rotl", imm_none) \ + X(OP_I64_ROTR, "i64_rotr", imm_none) \ + X(OP_F32_ABS, "f32_abs", imm_none) \ + X(OP_F32_NEG, "f32_neg", imm_none) \ + X(OP_F32_CEIL, "f32_ceil", imm_none) \ + X(OP_F32_FLOOR, "f32_floor", imm_none) \ + X(OP_F32_TRUNC, "f32_trunc", imm_none) \ + X(OP_F32_NEAREST, "f32_nearest", imm_none) \ + X(OP_F32_SQRT, "f32_sqrt", imm_none) \ + X(OP_F32_ADD, "f32_add", imm_none) \ + X(OP_F32_SUB, "f32_sub", imm_none) \ + X(OP_F32_MUL, "f32_mul", imm_none) \ + X(OP_F32_DIV, "f32_div", imm_none) \ + X(OP_F32_MIN, "f32_min", imm_none) \ + X(OP_F32_MAX, "f32_max", imm_none) \ + X(OP_F32_COPYSIGN, "f32_copysign", imm_none) \ + X(OP_F64_ABS, "f64_abs", imm_none) \ + X(OP_F64_NEG, "f64_neg", imm_none) \ + X(OP_F64_CEIL, "f64_ceil", imm_none) \ + X(OP_F64_FLOOR, "f64_floor", imm_none) \ + X(OP_F64_TRUNC, "f64_trunc", imm_none) \ + X(OP_F64_NEAREST, "f64_nearest", imm_none) \ + X(OP_F64_SQRT, "f64_sqrt", imm_none) \ + X(OP_F64_ADD, "f64_add", imm_none) \ + X(OP_F64_SUB, "f64_sub", imm_none) \ + X(OP_F64_MUL, "f64_mul", imm_none) \ + X(OP_F64_DIV, "f64_div", imm_none) \ + X(OP_F64_MIN, "f64_min", imm_none) \ + X(OP_F64_MAX, "f64_max", imm_none) \ + X(OP_F64_COPYSIGN, "f64_copysign", imm_none) \ + X(OP_I32_WRAP_I64, "i32_wrap_i64", imm_none) \ + X(OP_I32_TRUNC_S_F32, "i32_trunc_s_f32", imm_none) \ + X(OP_I32_TRUNC_U_F32, "i32_trunc_u_f32", imm_none) \ + X(OP_I32_TRUNC_S_F64, "i32_trunc_s_f64", imm_none) \ + X(OP_I32_TRUNC_U_F64, "i32_trunc_u_f64", imm_none) \ + X(OP_I64_EXTEND_S_I32, "i64_extend_s_i32", imm_none) \ + X(OP_I64_EXTEND_U_I32, "i64_extend_u_i32", imm_none) \ + X(OP_I64_TRUNC_S_F32, "i64_trunc_s_f32", imm_none) \ + X(OP_I64_TRUNC_U_F32, "i64_trunc_u_f32", imm_none) \ + X(OP_I64_TRUNC_S_F64, "i64_trunc_s_f64", imm_none) \ + X(OP_I64_TRUNC_U_F64, "i64_trunc_u_f64", imm_none) \ + X(OP_F32_CONVERT_S_I32, "f32_convert_s_i32", imm_none) \ + X(OP_F32_CONVERT_U_I32, "f32_convert_u_i32", imm_none) \ + X(OP_F32_CONVERT_S_I64, "f32_convert_s_i64", imm_none) \ + X(OP_F32_CONVERT_U_I64, "f32_convert_u_i64", imm_none) \ + X(OP_F32_DEMOTE_F64, "f32_demote_f64", imm_none) \ + X(OP_F64_CONVERT_S_I32, "f64_convert_s_i32", imm_none) \ + X(OP_F64_CONVERT_U_I32, "f64_convert_u_i32", imm_none) \ + X(OP_F64_CONVERT_S_I64, "f64_convert_s_i64", imm_none) \ + X(OP_F64_CONVERT_U_I64, "f64_convert_u_i64", imm_none) \ + X(OP_F64_PROMOTE_F32, "f64_promote_f32", imm_none) \ + X(OP_I32_REINTERPRET_F32, "i32_reinterpret_f32", imm_none) \ + X(OP_I64_REINTERPRET_F64, "i64_reinterpret_f64", imm_none) \ + X(OP_F32_REINTERPRET_I32, "f32_reinterpret_i32", imm_none) \ + X(OP_F64_REINTERPRET_I64, "f64_reinterpret_i64", imm_none) \ + X(OP_EXTRA, "extra", imm_extra) + + +struct opcode +{ + enum op op; + const char *s; + int (*read)(FILE *f, QString &); +}; + +static const opcode opcodes[] = +{ +#define X(x, y, z) {x, y, z}, + OPS +#undef X +}; + +int WasmInstr::parse(FILE *const f, WasmInstr &i, QString &error, + bool *const end) +{ + quint8 opcode; + const long start = ftell(f); + + if (start < 0) + { + error = QString("ftell(3) failed: ") + strerror(errno); + return -1; + } + else if (!fread(&opcode, sizeof opcode, 1, f)) + { + error = "fread(3) failed, ferror(3)=" + + QString::number(ferror(f)) + ", feof(3)=" + + QString::number(feof(f)); + return -1; + } + + for (const auto &o : opcodes) + if (opcode == o.op) + { + QString imm; + + if (o.read(f, imm)) + return -1; + else if (end) + *end = opcode == OP_END; + + i.instr = QString(o.s) + " " + imm; + i.address = start; + return 0; + } + + error = "Unknown opcode at offset 0x" + QString::number(start, 16) + +": 0x" + QString::number(opcode, 16); + return -1; +} + +int WasmInstr::parse(FILE *const f, varuint32 maxlen, + QVector<WasmInstr> &vinstr, QString &error) +{ + while (maxlen) + { + WasmInstr i; + + const long start = ftell(f); + + if (start < 0) + { + error = QString("ftell(3) failed: ") + strerror(errno); + return -1; + } + else if (parse(f, i, error)) + return -1; + + const long end = ftell(f); + + if (end < 0) + { + error = QString("ftell(3) failed: ") + strerror(errno); + return -1; + } + + const unsigned long consumed = end - start; + + if (consumed > maxlen) + { + error = "Function body exceeds expected size"; + return -1; + } + + maxlen -= consumed; + vinstr.push_back(i); + } + + return 0; +} |
