kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

disasm.c (14847B)


      1 /* RV64 disassembler — descriptor-table driven.
      2  *
      3  * Decodes a 4-byte word by linear-scan over `rv64_insn_table` and
      4  * dispatches operand printing on the matched format. Compressed (RV64C)
      5  * instructions are 16-bit: a halfword whose low 2 bits are not 0b11
      6  * goes through the C-decode path; the iterator advances by 2 bytes.
      7  *
      8  * Unknown words/halfwords fall back to ".word"/".hword" placeholders. */
      9 
     10 #include "arch/riscv/disasm.h"
     11 
     12 #include <string.h>
     13 
     14 #include "arch/riscv/isa.h"
     15 #include "arch/riscv/variant.h"
     16 #include "core/heap.h"
     17 #include "core/strbuf.h"
     18 
     19 #define RV64_DASM_MNEM_CAP 16u
     20 #define RV64_DASM_OPS_CAP 96u
     21 #define RV64_DASM_ANN_CAP 64u
     22 #define RV64_ENCODING_UNKNOWN 0xffffffffu
     23 
     24 typedef struct Rv64InsnFormatter {
     25   ArchInsnFormatter base;
     26   Compiler* c;
     27   Heap* heap;
     28   char mnem_buf[RV64_DASM_MNEM_CAP];
     29   char ops_buf[RV64_DASM_OPS_CAP];
     30   char ann_buf[RV64_DASM_ANN_CAP];
     31   StrBuf mnem;
     32   StrBuf ops;
     33   StrBuf ann;
     34 } Rv64InsnFormatter;
     35 
     36 typedef struct Rv64Disasm {
     37   ArchDisasm base;
     38   Rv64InsnFormatter fmt;
     39 } Rv64Disasm;
     40 
     41 static KitStatus rv64_format_insn(ArchInsnFormatter*, const KitDecodedInsn*,
     42                                   KitInsn*);
     43 static void rv64_formatter_destroy(ArchInsnFormatter*);
     44 
     45 /* RV_AV_* mask of the arch being disassembled. Derived from the Compiler's
     46  * target; defaults (and any non-RISC-V kind) map to rv64 so the historical
     47  * decode path is byte-identical. */
     48 static u8 rv_av_for_compiler(Compiler* c) {
     49   const RiscvVariant* v = riscv_variant_for_kind(c->target.arch);
     50   return v->xlen == 32u ? (u8)RV_AV_RV32 : (u8)RV_AV_RV64;
     51 }
     52 
     53 static u32 rv_read_u32_le(const u8* b) {
     54   return (u32)b[0] | ((u32)b[1] << 8) | ((u32)b[2] << 16) | ((u32)b[3] << 24);
     55 }
     56 
     57 static u32 rv_read_u16_le(const u8* b) { return (u32)b[0] | ((u32)b[1] << 8); }
     58 
     59 static void rv_fmt_emit_fallback32(Rv64InsnFormatter* f, u32 word) {
     60   strbuf_reset(&f->mnem);
     61   strbuf_puts(&f->mnem, ".word");
     62   strbuf_reset(&f->ops);
     63   strbuf_put_hex_u64(&f->ops, (u64)word);
     64 }
     65 
     66 static void rv_fmt_emit_fallback16(Rv64InsnFormatter* f, u32 hw) {
     67   strbuf_reset(&f->mnem);
     68   strbuf_puts(&f->mnem, ".hword");
     69   strbuf_reset(&f->ops);
     70   strbuf_put_hex_u64(&f->ops, (u64)hw);
     71 }
     72 
     73 static u32 rv64_desc_encoding_id(const Rv64InsnDesc* desc) {
     74   u32 i;
     75   if (!desc) return RV64_ENCODING_UNKNOWN;
     76   for (i = 0; i < rv64_insn_table_n; ++i) {
     77     if (desc == &rv64_insn_table[i]) return i;
     78   }
     79   return RV64_ENCODING_UNKNOWN;
     80 }
     81 
     82 static u32 rv64_semantic_opcode(u32 word, u32 nbytes) {
     83   u32 op, funct3, funct7;
     84   if (nbytes != 4u) return RV64_DEC_UNKNOWN;
     85   if (word == rv_ecall()) return RV64_DEC_ECALL;
     86   if (word == rv_ebreak()) return RV64_DEC_EBREAK;
     87   op = word & 0x7fu;
     88   funct3 = (word >> 12) & 0x7u;
     89   funct7 = (word >> 25) & 0x7fu;
     90   if (op == RV_OP_IMM && funct3 == 0u) return RV64_DEC_ADDI;
     91   if (op == RV_OP && funct3 == 0u && funct7 == 0u) return RV64_DEC_ADD;
     92   if (op == RV_AUIPC) return RV64_DEC_AUIPC;
     93   if (op == RV_LOAD && funct3 == 3u) return RV64_DEC_LD;
     94   if (op == RV_STORE && funct3 == 3u) return RV64_DEC_SD;
     95   if (op == RV_JALR && funct3 == 0u) return RV64_DEC_JALR;
     96   return RV64_DEC_UNKNOWN;
     97 }
     98 
     99 static void rv_decop_none(KitDecodedOperand* o) {
    100   memset(o, 0, sizeof(*o));
    101   o->kind = KIT_DECOP_NONE;
    102   o->index_reg = REG_NONE;
    103 }
    104 
    105 static void rv_decop_reg(KitDecodedOperand* o, u32 reg, u8 width_bits) {
    106   rv_decop_none(o);
    107   o->kind = KIT_DECOP_REG;
    108   o->width_bits = width_bits;
    109   o->reg = reg;
    110 }
    111 
    112 static void rv_decop_imm(KitDecodedOperand* o, i64 imm) {
    113   rv_decop_none(o);
    114   o->kind = KIT_DECOP_IMM;
    115   o->imm = imm;
    116 }
    117 
    118 static void rv_decop_sysreg(KitDecodedOperand* o, u32 reg) {
    119   rv_decop_none(o);
    120   o->kind = KIT_DECOP_SYSREG;
    121   o->reg = reg;
    122 }
    123 
    124 static void rv_decop_mem(KitDecodedOperand* o, u32 base, i64 imm,
    125                          u8 width_bits) {
    126   rv_decop_none(o);
    127   o->kind = KIT_DECOP_MEM;
    128   o->width_bits = width_bits;
    129   o->reg = base;
    130   o->imm = imm;
    131 }
    132 
    133 static void rv_decop_pcrel(KitDecodedOperand* o, u64 pc, i64 disp) {
    134   rv_decop_none(o);
    135   o->kind = KIT_DECOP_PCREL;
    136   o->imm = (i64)(pc + (u64)disp);
    137 }
    138 
    139 static u8 rv_load_width_bits(u32 funct3) {
    140   switch (funct3 & 7u) {
    141     case 0:
    142     case 4:
    143       return 8;
    144     case 1:
    145     case 5:
    146       return 16;
    147     case 2:
    148     case 6:
    149       return 32;
    150     case 3:
    151       return 64;
    152     default:
    153       return 0;
    154   }
    155 }
    156 
    157 static u16 rv64_decode_flags(const Rv64InsnDesc* desc, u32 word) {
    158   u16 flags = 0;
    159   Rv64Format fmt;
    160   if (!desc) return 0;
    161   fmt = (Rv64Format)desc->fmt;
    162   switch (fmt) {
    163     case RV64_FMT_B:
    164     case RV64_FMT_CB:
    165     case RV64_FMT_CJ:
    166       flags |= KIT_DECODE_TERMINATOR | KIT_DECODE_BRANCH;
    167       break;
    168     case RV64_FMT_J:
    169       flags |= KIT_DECODE_TERMINATOR | KIT_DECODE_BRANCH;
    170       if (((word >> 7) & 0x1fu) == RV_RA) flags |= KIT_DECODE_CALL;
    171       break;
    172     case RV64_FMT_JALR: {
    173       u32 rd = (word >> 7) & 0x1fu;
    174       u32 rs1 = (word >> 15) & 0x1fu;
    175       flags |= KIT_DECODE_TERMINATOR | KIT_DECODE_BRANCH;
    176       if (rd == RV_RA) flags |= KIT_DECODE_CALL;
    177       if (rd == RV_ZERO && rs1 == RV_RA) flags |= KIT_DECODE_RET;
    178       break;
    179     }
    180     case RV64_FMT_CR: {
    181       /* CR holds c.jr/c.jalr (rs2==0, rd/rs1!=0) and c.mv/c.add (rs2!=0).
    182        * Dispatch on the encoding rather than the mnemonic string: only the
    183        * jr/jalr pair is a control transfer, and bit[12] selects c.jalr (which
    184        * links ra, so it is a call). */
    185       u32 hw = word & 0xffffu;
    186       u32 rs2 = (hw >> 2) & 0x1fu;    /* bits[6:2] */
    187       u32 rd_rs1 = (hw >> 7) & 0x1fu; /* bits[11:7] */
    188       if (rs2 == 0u && rd_rs1 != 0u) {
    189         flags |= KIT_DECODE_TERMINATOR | KIT_DECODE_BRANCH;
    190         if (((hw >> 12) & 1u) != 0u) flags |= KIT_DECODE_CALL; /* c.jalr */
    191       }
    192       break;
    193     }
    194     case RV64_FMT_SYSTEM:
    195       if (word == rv_ecall() || word == rv_ebreak())
    196         flags |= KIT_DECODE_TERMINATOR | KIT_DECODE_TRAP;
    197       break;
    198     case RV64_FMT_C_NONE:
    199       if ((word & 0xffffu) == 0x9002u)
    200         flags |= KIT_DECODE_TERMINATOR | KIT_DECODE_TRAP;
    201       break;
    202     case RV64_FMT_LOAD:
    203     case RV64_FMT_STORE:
    204     case RV64_FMT_FP_LOAD:
    205     case RV64_FMT_FP_STORE:
    206     case RV64_FMT_AMO:
    207     case RV64_FMT_LR:
    208     case RV64_FMT_CL:
    209     case RV64_FMT_CS:
    210     case RV64_FMT_CSS:
    211       flags |= KIT_DECODE_MEMORY;
    212       break;
    213     default:
    214       break;
    215   }
    216   return flags;
    217 }
    218 
    219 static void rv64_decode_operands(const Rv64InsnDesc* desc, u32 word, u64 pc,
    220                                  const RiscvVariant* variant,
    221                                  KitDecodedInsn* out) {
    222   Rv64Format fmt;
    223   if (!desc) return;
    224   fmt = (Rv64Format)desc->fmt;
    225   switch (fmt) {
    226     case RV64_FMT_R:
    227     case RV64_FMT_FP_R:
    228     case RV64_FMT_FP_RM: {
    229       Rv64R r = rv64_r_unpack(word);
    230       out->noperands = 3;
    231       rv_decop_reg(&out->operands[0], r.rd, 64);
    232       rv_decop_reg(&out->operands[1], r.rs1, 64);
    233       rv_decop_reg(&out->operands[2], r.rs2, 64);
    234       break;
    235     }
    236     case RV64_FMT_I: {
    237       Rv64I i = rv64_i_unpack(word);
    238       out->noperands = 3;
    239       rv_decop_reg(&out->operands[0], i.rd, 64);
    240       rv_decop_reg(&out->operands[1], i.rs1, 64);
    241       rv_decop_imm(&out->operands[2], rv64_sext(i.imm12, 12));
    242       break;
    243     }
    244     case RV64_FMT_I_SHIFT:
    245     case RV64_FMT_I_SHIFTW: {
    246       Rv64I i = rv64_i_unpack(word);
    247       /* SLLIW/SRLIW/SRAIW (I_SHIFTW) are always a 5-bit shamt. The plain
    248        * SLLI/SRLI/SRAI shamt is 6-bit on rv64 but 5-bit on rv32 (bit 25 is
    249        * funct7 there), so the mask follows variant->shamt_bits. */
    250       u32 shamt_mask = (fmt == RV64_FMT_I_SHIFTW || variant->shamt_bits == 5u)
    251                            ? 0x1fu
    252                            : 0x3fu;
    253       out->noperands = 3;
    254       rv_decop_reg(&out->operands[0], i.rd, 64);
    255       rv_decop_reg(&out->operands[1], i.rs1, 64);
    256       rv_decop_imm(&out->operands[2], (i64)(i.imm12 & shamt_mask));
    257       break;
    258     }
    259     case RV64_FMT_LOAD:
    260     case RV64_FMT_FP_LOAD: {
    261       Rv64I i = rv64_i_unpack(word);
    262       out->noperands = 2;
    263       rv_decop_reg(&out->operands[0], i.rd, 64);
    264       rv_decop_mem(&out->operands[1], i.rs1, rv64_sext(i.imm12, 12),
    265                    rv_load_width_bits(i.funct3));
    266       break;
    267     }
    268     case RV64_FMT_S:
    269     case RV64_FMT_STORE:
    270     case RV64_FMT_FP_STORE: {
    271       Rv64S s = rv64_s_unpack(word);
    272       out->noperands = 2;
    273       rv_decop_reg(&out->operands[0], s.rs2, 64);
    274       rv_decop_mem(&out->operands[1], s.rs1, rv64_sext(s.imm12, 12),
    275                    rv_load_width_bits(s.funct3));
    276       break;
    277     }
    278     case RV64_FMT_B: {
    279       Rv64B b = rv64_b_unpack(word);
    280       out->noperands = 3;
    281       rv_decop_reg(&out->operands[0], b.rs1, 64);
    282       rv_decop_reg(&out->operands[1], b.rs2, 64);
    283       rv_decop_pcrel(&out->operands[2], pc, rv64_sext(b.imm13, 13));
    284       break;
    285     }
    286     case RV64_FMT_U: {
    287       Rv64U u = rv64_u_unpack(word);
    288       out->noperands = 2;
    289       rv_decop_reg(&out->operands[0], u.rd, 64);
    290       rv_decop_imm(&out->operands[1], (i64)(i32)u.imm32_hi20);
    291       break;
    292     }
    293     case RV64_FMT_J: {
    294       Rv64J j = rv64_j_unpack(word);
    295       out->noperands = 2;
    296       rv_decop_reg(&out->operands[0], j.rd, 64);
    297       rv_decop_pcrel(&out->operands[1], pc, rv64_sext(j.imm21, 21));
    298       break;
    299     }
    300     case RV64_FMT_JALR: {
    301       Rv64I i = rv64_i_unpack(word);
    302       out->noperands = 2;
    303       rv_decop_reg(&out->operands[0], i.rd, 64);
    304       rv_decop_mem(&out->operands[1], i.rs1, rv64_sext(i.imm12, 12), 64);
    305       break;
    306     }
    307     case RV64_FMT_CSR: {
    308       Rv64I i = rv64_i_unpack(word);
    309       out->noperands = 3;
    310       rv_decop_reg(&out->operands[0], i.rd, 64);
    311       rv_decop_sysreg(&out->operands[1], i.imm12);
    312       rv_decop_reg(&out->operands[2], i.rs1, 64);
    313       break;
    314     }
    315     case RV64_FMT_CSRI: {
    316       Rv64I i = rv64_i_unpack(word);
    317       out->noperands = 3;
    318       rv_decop_reg(&out->operands[0], i.rd, 64);
    319       rv_decop_sysreg(&out->operands[1], i.imm12);
    320       rv_decop_imm(&out->operands[2], (i64)i.rs1);
    321       break;
    322     }
    323     default:
    324       break;
    325   }
    326 }
    327 
    328 static KitStatus rv64_decode_one(Compiler* c, const u8* bytes, size_t len,
    329                                  u64 pc, KitDecodedInsn* out) {
    330   const Rv64InsnDesc* desc;
    331   Rv64InsnDesc c_scratch;
    332   const RiscvVariant* variant;
    333   u8 av;
    334   u32 first_hw;
    335   u32 word;
    336   u32 encoding_id;
    337   if (!bytes || !out) return KIT_INVALID;
    338   if (len < 2u) return KIT_MALFORMED;
    339   variant = riscv_variant_for_kind(c->target.arch);
    340   av = rv_av_for_compiler(c);
    341   memset(out, 0, sizeof(*out));
    342   for (u32 i = 0; i < KIT_DECODE_MAX_OPERANDS; ++i)
    343     rv_decop_none(&out->operands[i]);
    344 
    345   first_hw = rv_read_u16_le(bytes);
    346   if ((first_hw & 3u) != 3u) {
    347     word = first_hw;
    348     desc = rv64_disasm_find_c(first_hw, av, &c_scratch);
    349     out->nbytes = 2;
    350   } else {
    351     if (len < 4u) return KIT_MALFORMED;
    352     word = rv_read_u32_le(bytes);
    353     desc = rv64_disasm_find(word, av);
    354     out->nbytes = 4;
    355   }
    356 
    357   encoding_id = rv64_desc_encoding_id(desc);
    358   out->pc = pc;
    359   out->bytes = bytes;
    360   out->encoding_id = encoding_id;
    361   out->opcode = rv64_semantic_opcode(word, out->nbytes);
    362   out->flags = rv64_decode_flags(desc, word);
    363   out->arch[0] = word;
    364   out->arch[1] = desc ? desc->fmt : 0xffu;
    365   rv64_decode_operands(desc, word, pc, variant, out);
    366   return KIT_OK;
    367 }
    368 
    369 static KitStatus rv64_decode_block(Compiler* c, const u8* bytes, size_t len,
    370                                    u64 pc, KitDecodedInsn* out, u32 cap,
    371                                    u32* n_out) {
    372   u32 n = 0;
    373   if (n_out) *n_out = 0;
    374   if (!bytes || !out || !n_out) return KIT_INVALID;
    375   while (n < cap && len > 0) {
    376     KitStatus st = rv64_decode_one(c, bytes, len, pc, &out[n]);
    377     if (st != KIT_OK) return n ? KIT_OK : st;
    378     bytes += out[n].nbytes;
    379     len -= out[n].nbytes;
    380     pc += out[n].nbytes;
    381     ++n;
    382     if (out[n - 1u].flags & KIT_DECODE_TERMINATOR) break;
    383   }
    384   *n_out = n;
    385   return KIT_OK;
    386 }
    387 
    388 static void rv64_formatter_init(Rv64InsnFormatter* f, Compiler* c, Heap* h) {
    389   memset(f, 0, sizeof(*f));
    390   f->c = c;
    391   f->heap = h;
    392   f->base.format = rv64_format_insn;
    393   f->base.destroy = rv64_formatter_destroy;
    394   strbuf_init(&f->mnem, f->mnem_buf, sizeof f->mnem_buf);
    395   strbuf_init(&f->ops, f->ops_buf, sizeof f->ops_buf);
    396   strbuf_init(&f->ann, f->ann_buf, sizeof f->ann_buf);
    397 }
    398 
    399 static KitStatus rv64_format_insn(ArchInsnFormatter* base,
    400                                   const KitDecodedInsn* insn, KitInsn* out) {
    401   Rv64InsnFormatter* f = (Rv64InsnFormatter*)base;
    402   const Rv64InsnDesc* desc;
    403   Rv64InsnDesc c_scratch;
    404   u32 word;
    405   if (!f || !insn || !out) return KIT_INVALID;
    406   word = (u32)insn->arch[0];
    407   {
    408     u8 av = rv_av_for_compiler(f->c);
    409     desc = insn->nbytes == 2u ? rv64_disasm_find_c(word, av, &c_scratch)
    410                               : rv64_disasm_find(word, av);
    411   }
    412   if (desc) {
    413     strbuf_reset(&f->mnem);
    414     strbuf_put_slice(&f->mnem, desc->mnemonic);
    415     strbuf_reset(&f->ops);
    416     rv64_print_operands(&f->ops, desc, word, insn->pc);
    417   } else if (insn->nbytes == 2u) {
    418     rv_fmt_emit_fallback16(f, word);
    419   } else {
    420     rv_fmt_emit_fallback32(f, word);
    421   }
    422 
    423   strbuf_reset(&f->ann);
    424   out->vaddr = insn->pc;
    425   out->bytes = insn->bytes;
    426   out->nbytes = insn->nbytes;
    427   out->mnemonic = strbuf_slice(&f->mnem);
    428   out->operands = strbuf_slice(&f->ops);
    429   out->annotation = strbuf_slice(&f->ann);
    430   return KIT_OK;
    431 }
    432 
    433 static void rv64_formatter_destroy(ArchInsnFormatter* base) {
    434   Rv64InsnFormatter* f = (Rv64InsnFormatter*)base;
    435   if (!f) return;
    436   f->heap->free(f->heap, f, sizeof(*f));
    437 }
    438 
    439 static ArchInsnFormatter* rv64_formatter_new(Compiler* c) {
    440   Heap* h = (Heap*)c->ctx->heap;
    441   Rv64InsnFormatter* f =
    442       (Rv64InsnFormatter*)h->alloc(h, sizeof(*f), _Alignof(Rv64InsnFormatter));
    443   if (!f) return NULL;
    444   rv64_formatter_init(f, c, h);
    445   return &f->base;
    446 }
    447 
    448 static u32 rv_decode(ArchDisasm* base, const u8* bytes, size_t len, u64 vaddr,
    449                      KitInsn* out) {
    450   Rv64Disasm* d = (Rv64Disasm*)base;
    451   KitDecodedInsn insn;
    452   KitStatus st = rv64_decode_one(d->fmt.c, bytes, len, vaddr, &insn);
    453   if (st != KIT_OK) return 0;
    454   st = rv64_format_insn(&d->fmt.base, &insn, out);
    455   if (st != KIT_OK) return 0;
    456   return insn.nbytes;
    457 }
    458 
    459 static void rv64_destroy(ArchDisasm* base) {
    460   Rv64Disasm* d = (Rv64Disasm*)base;
    461   d->fmt.heap->free(d->fmt.heap, d, sizeof(*d));
    462 }
    463 
    464 ArchDisasm* rv64_disasm_new(Compiler* c) {
    465   Heap* h = (Heap*)c->ctx->heap;
    466   Rv64Disasm* d = (Rv64Disasm*)h->alloc(h, sizeof(*d), _Alignof(Rv64Disasm));
    467   if (!d) return NULL;
    468   memset(d, 0, sizeof(*d));
    469   d->base.decode = rv_decode;
    470   d->base.destroy = rv64_destroy;
    471   rv64_formatter_init(&d->fmt, c, h);
    472   return &d->base;
    473 }
    474 
    475 const ArchDecodeOps rv64_decode_ops = {
    476     .min_insn_len = 2,
    477     .max_insn_len = 4,
    478     .decode_one = rv64_decode_one,
    479     .decode_block = rv64_decode_block,
    480     .formatter_new = rv64_formatter_new,
    481     .format = rv64_format_insn,
    482     .formatter_destroy = rv64_formatter_destroy,
    483 };