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 };