disasm.c (4628B)
1 /* AArch64 disassembler implementation. 2 * 3 * Decodes one 4-byte instruction word per call into a KitInsn whose 4 * string fields point into iterator-owned StrBufs. The decoder shares 5 * the aa64_isa.{h,c} descriptor table with the encoder: aa64_disasm_find 6 * matches the word; aa64_print_operands renders operand text via the 7 * format's unpack + per-format pretty-printer. Mnemonic rewriting (the 8 * one bit the printer can't own, because b.cond rolls cond into the 9 * "operand" text) happens here. */ 10 11 #include "arch/aa64/disasm.h" 12 13 #include <string.h> 14 15 #include "arch/aa64/isa.h" 16 #include "core/heap.h" 17 #include "core/strbuf.h" 18 19 /* Enough for any aarch64 mnemonic-with-suffix ("b.cond" → "b.le", etc.). */ 20 #define AA64_DASM_MNEM_CAP 16u 21 /* Operand text. The widest cases (LDP X, X, [SP, #-imm]!) fit easily. */ 22 #define AA64_DASM_OPS_CAP 96u 23 /* Annotation overlay (symbol + addend). */ 24 #define AA64_DASM_ANN_CAP 96u 25 26 typedef struct AA64Disasm { 27 ArchDisasm base; 28 Compiler* c; 29 Heap* heap; 30 char mnem_buf[AA64_DASM_MNEM_CAP]; 31 char ops_buf[AA64_DASM_OPS_CAP]; 32 char ann_buf[AA64_DASM_ANN_CAP]; 33 StrBuf mnem; 34 StrBuf ops; 35 StrBuf ann; 36 } AA64Disasm; 37 38 static void aa64_write_mnemonic(AA64Disasm* d, const AA64InsnDesc* desc, 39 u32 word) { 40 strbuf_reset(&d->mnem); 41 if (desc->fmt == AA64_FMT_BR_COND) { 42 /* Synthesize "b.<cond>" so the operands buffer can hold just the 43 * target. Matches GNU as / objdump conventions. */ 44 u32 cond = word & 0xfu; 45 strbuf_puts(&d->mnem, "b."); 46 strbuf_puts(&d->mnem, aa64_cond_name(cond)); 47 return; 48 } 49 if (desc->fmt == AA64_FMT_BITFIELD) { 50 /* SBFM/UBFM disassemble to their preferred aliases when the 51 * fields match; aa64_print_operands renders the matching operands. */ 52 u32 shift, lsb, width; 53 const char* alias = aa64_bitfield_shift_alias(word, &shift); 54 if (!alias) alias = aa64_bitfield_extend_alias(word); 55 if (!alias) alias = aa64_bitfield_extract_alias(word, &lsb, &width); 56 (void)lsb; 57 (void)width; 58 if (alias) { 59 strbuf_puts(&d->mnem, alias); 60 return; 61 } 62 } 63 strbuf_put_slice(&d->mnem, desc->mnemonic); 64 } 65 66 static void aa64_write_operands(AA64Disasm* d, const AA64InsnDesc* desc, 67 u32 word, u64 vaddr) { 68 strbuf_reset(&d->ops); 69 if (desc->fmt == AA64_FMT_BR_COND) { 70 /* aa64_print_operands prints "<cond> <target>"; we already lifted 71 * the cond into the mnemonic, so skip the dispatcher and inline 72 * just the target. */ 73 AA64BrCond f = aa64_brcond_unpack(word); 74 i64 ofs = (i64)((u64)f.imm19 & 0x7ffffu); 75 /* sign-extend 19 bits */ 76 if (ofs & 0x40000) ofs |= ~(i64)0x7ffff; 77 ofs *= 4; 78 if (vaddr) { 79 strbuf_put_hex_u64(&d->ops, vaddr + (u64)ofs); 80 } else { 81 strbuf_puts(&d->ops, "#"); 82 strbuf_put_i64(&d->ops, ofs); 83 } 84 return; 85 } 86 aa64_print_operands(&d->ops, desc, word, vaddr); 87 } 88 89 static u32 aa64_read_u32_le(const u8* b) { 90 return (u32)b[0] | ((u32)b[1] << 8) | ((u32)b[2] << 16) | ((u32)b[3] << 24); 91 } 92 93 static void aa64_write_unknown(AA64Disasm* d, u32 word) { 94 strbuf_reset(&d->mnem); 95 strbuf_puts(&d->mnem, ".inst"); 96 strbuf_reset(&d->ops); 97 strbuf_put_hex_u64(&d->ops, (u64)word); 98 } 99 100 static u32 aa64_decode(ArchDisasm* base, const u8* bytes, size_t len, u64 vaddr, 101 KitInsn* out) { 102 AA64Disasm* d = (AA64Disasm*)base; 103 if (len < 4u) return 0; 104 u32 word = aa64_read_u32_le(bytes); 105 const AA64InsnDesc* desc = aa64_disasm_find(word); 106 if (desc) { 107 aa64_write_mnemonic(d, desc, word); 108 aa64_write_operands(d, desc, word, vaddr); 109 } else { 110 aa64_write_unknown(d, word); 111 } 112 /* Annotation overlay is owned by the public iterator (kit_disasm_iter_*). 113 * The arch-level decoder leaves it empty. */ 114 strbuf_reset(&d->ann); 115 out->vaddr = vaddr; 116 out->bytes = bytes; 117 out->nbytes = 4; 118 out->mnemonic = strbuf_slice(&d->mnem); 119 out->operands = strbuf_slice(&d->ops); 120 out->annotation = strbuf_slice(&d->ann); 121 return 4; 122 } 123 124 static void aa64_destroy(ArchDisasm* base) { 125 AA64Disasm* d = (AA64Disasm*)base; 126 d->heap->free(d->heap, d, sizeof(*d)); 127 } 128 129 ArchDisasm* aa64_disasm_new(Compiler* c) { 130 Heap* h = (Heap*)c->ctx->heap; 131 AA64Disasm* d = (AA64Disasm*)h->alloc(h, sizeof(*d), _Alignof(AA64Disasm)); 132 if (!d) return NULL; 133 memset(d, 0, sizeof(*d)); 134 d->c = c; 135 d->heap = h; 136 d->base.decode = aa64_decode; 137 d->base.destroy = aa64_destroy; 138 strbuf_init(&d->mnem, d->mnem_buf, sizeof d->mnem_buf); 139 strbuf_init(&d->ops, d->ops_buf, sizeof d->ops_buf); 140 strbuf_init(&d->ann, d->ann_buf, sizeof d->ann_buf); 141 return &d->base; 142 }