disasm.c (9431B)
1 /* Public disassembler API. */ 2 3 #include <kit/disasm.h> 4 #include <stdint.h> 5 #include <string.h> 6 7 #include "arch/arch.h" 8 #include "core/core.h" 9 #include "core/heap.h" 10 #include "core/pool.h" 11 #include "core/slice.h" 12 #include "core/strbuf.h" 13 #include "obj/obj.h" 14 15 #define DASM_ANN_CAP 128u 16 17 ObjBuilder* kit_objfile_builder(const KitObjFile* f); 18 19 /* The iterator holds its own private Compiler so the arch decoder has a 20 * pool to mint strings from without needing a caller-provided KitCompiler. */ 21 struct KitDisasmIter { 22 Compiler compiler; 23 const KitContext* ctx; 24 Heap* heap; 25 ArchDisasm* arch; 26 const uint8_t* bytes; 27 size_t len; 28 size_t off; 29 uint64_t vaddr0; 30 const KitObjFile* annot; 31 ObjBuilder* annot_ob; 32 uint32_t annot_section; 33 char ann_buf[DASM_ANN_CAP]; 34 StrBuf ann; 35 }; 36 37 static Slice dasm_overlay(KitDisasmIter* it, uint64_t vaddr, uint32_t nbytes) { 38 ObjBuilder* obj = it->annot_ob; 39 if (!obj) return SLICE_LIT(""); 40 strbuf_reset(&it->ann); 41 42 u64 want = vaddr - it->vaddr0; 43 u64 end = want + nbytes; 44 u32 nrel = obj_reloc_total(obj); 45 for (u32 i = 0; i < nrel; ++i) { 46 const Reloc* r = obj_reloc_at(obj, i); 47 if (!r) continue; 48 if (it->annot_section != KIT_SECTION_NONE && 49 r->section_id != (ObjSecId)(it->annot_section + 1)) 50 continue; 51 if ((u64)r->offset < want || (u64)r->offset >= end) continue; 52 const ObjSym* sym = 53 (r->sym != OBJ_SYM_NONE) ? obj_symbol_get(obj, r->sym) : NULL; 54 if (sym && sym->name) { 55 Compiler* oc = obj_compiler(obj); 56 Slice nm = oc ? pool_slice(oc->global, sym->name) : SLICE_NULL; 57 if (nm.s) 58 strbuf_putn(&it->ann, nm.s, nm.len); 59 else 60 strbuf_puts(&it->ann, "<anon>"); 61 } else { 62 strbuf_puts(&it->ann, "<anon>"); 63 } 64 if (r->addend > 0) { 65 strbuf_puts(&it->ann, "+"); 66 strbuf_put_i64(&it->ann, r->addend); 67 } else if (r->addend < 0) { 68 strbuf_put_i64(&it->ann, r->addend); 69 } 70 /* Append the reloc kind in brackets so the annotation distinguishes 71 * HI20 vs LO12 vs CALL forms — useful for rv64 paired AUIPC/ADDI 72 * sequences and aa64 paired ADRP/ADD pages. */ 73 const char* kn = reloc_kind_name(r->kind); 74 if (kn && kn[0]) { 75 strbuf_puts(&it->ann, " ["); 76 strbuf_puts(&it->ann, kn); 77 strbuf_puts(&it->ann, "]"); 78 } 79 break; 80 } 81 return strbuf_slice(&it->ann); 82 } 83 84 static uint32_t dasm_find_section(const KitObjFile* f, const uint8_t* bytes, 85 size_t len) { 86 uint32_t nsec, i; 87 if (!f || !bytes) return KIT_SECTION_NONE; 88 nsec = kit_obj_nsections(f); 89 for (i = 0; i < nsec; ++i) { 90 const uint8_t* data = NULL; 91 size_t n = 0; 92 if (kit_obj_section_data(f, i, &data, &n) != KIT_OK) continue; 93 if (data == bytes && n == len) return i; 94 } 95 return KIT_SECTION_NONE; 96 } 97 98 KitStatus kit_disasm_iter_new(const KitDisasmContext* dctx, 99 const uint8_t* bytes, size_t len, uint64_t vaddr, 100 const KitObjFile* annot, KitDisasmIter** out) { 101 Heap* h; 102 KitDisasmIter* it; 103 if (!out) return KIT_INVALID; 104 if (!dctx) return KIT_INVALID; 105 if (!bytes && len > 0) return KIT_INVALID; 106 if (!dctx->context.heap) return KIT_INVALID; 107 h = dctx->context.heap; 108 it = (KitDisasmIter*)h->alloc(h, sizeof(*it), _Alignof(KitDisasmIter)); 109 if (!it) return KIT_NOMEM; 110 memset(it, 0, sizeof(*it)); 111 it->ctx = &dctx->context; 112 it->heap = h; 113 if (!dctx->target) { 114 h->free(h, it, sizeof(*it)); 115 return KIT_INVALID; 116 } 117 { 118 KitStatus st = compiler_init(&it->compiler, dctx->target, &dctx->context); 119 if (st != KIT_OK) { 120 h->free(h, it, sizeof(*it)); 121 return st; 122 } 123 } 124 it->arch = arch_disasm_new(&it->compiler); 125 if (!it->arch) { 126 compiler_fini(&it->compiler); 127 h->free(h, it, sizeof(*it)); 128 return KIT_UNSUPPORTED; 129 } 130 it->bytes = bytes; 131 it->len = len; 132 it->off = 0; 133 it->vaddr0 = vaddr; 134 it->annot = annot; 135 it->annot_ob = annot ? kit_objfile_builder(annot) : NULL; 136 it->annot_section = dasm_find_section(annot, bytes, len); 137 strbuf_init(&it->ann, it->ann_buf, sizeof it->ann_buf); 138 *out = it; 139 return KIT_OK; 140 } 141 142 KitIterResult kit_disasm_iter_next(KitDisasmIter* it, KitInsn* out) { 143 if (!it || !out) return KIT_ITER_ERROR; 144 if (it->off >= it->len) return KIT_ITER_END; 145 uint64_t vaddr = it->vaddr0 + (uint64_t)it->off; 146 u32 n = arch_disasm_decode(it->arch, it->bytes + it->off, it->len - it->off, 147 vaddr, out); 148 if (n == 0) { 149 if (it->off >= it->len) return KIT_ITER_END; 150 n = (u32)(it->len - it->off); 151 if (n > 4) n = 4; 152 out->vaddr = vaddr; 153 out->bytes = it->bytes + it->off; 154 out->nbytes = n; 155 out->mnemonic = SLICE_LIT("(truncated)"); 156 out->operands = SLICE_LIT(""); 157 out->annotation = SLICE_LIT(""); 158 it->off += n; 159 return KIT_ITER_ITEM; 160 } 161 out->annotation = dasm_overlay(it, vaddr, n); 162 it->off += n; 163 return KIT_ITER_ITEM; 164 } 165 166 void kit_disasm_iter_free(KitDisasmIter* it) { 167 Heap* h; 168 if (!it) return; 169 arch_disasm_free(it->arch); 170 compiler_fini(&it->compiler); 171 h = it->heap; 172 h->free(h, it, sizeof(*it)); 173 } 174 175 static KitStatus w_str(KitWriter* w, const char* s) { 176 return kit_writer_write(w, s, slice_from_cstr(s).len); 177 } 178 179 static KitStatus w_slice(KitWriter* w, Slice s) { 180 return kit_writer_write(w, s.s, s.len); 181 } 182 183 static KitStatus w_hex(KitWriter* w, u64 v, u32 width) { 184 static const char H[] = "0123456789abcdef"; 185 char buf[17]; 186 u32 i; 187 if (width > 16) width = 16; 188 for (i = 0; i < width; ++i) { 189 buf[width - 1 - i] = H[(v >> (4 * i)) & 0xfu]; 190 } 191 buf[width] = '\0'; 192 return kit_writer_write(w, buf, width); 193 } 194 195 static KitStatus w_hex_padded(KitWriter* w, u64 v, u32 minwidth) { 196 static const char H[] = "0123456789abcdef"; 197 char buf[24]; 198 u32 i = sizeof(buf); 199 u32 nch; 200 KitStatus st; 201 if (v == 0) { 202 buf[--i] = '0'; 203 } else { 204 while (v) { 205 buf[--i] = H[v & 0xfu]; 206 v >>= 4; 207 } 208 } 209 nch = (u32)(sizeof(buf) - i); 210 while (nch < minwidth) { 211 st = kit_writer_write(w, " ", 1); 212 if (st != KIT_OK) return st; 213 ++nch; 214 } 215 return kit_writer_write(w, buf + i, sizeof(buf) - i); 216 } 217 218 static Slice dasm_sym_at(const KitObjFile* f, uint32_t section_idx, 219 uint64_t offset) { 220 KitObjSymIter* si = NULL; 221 Slice found = SLICE_NULL; 222 KitObjSymInfo s; 223 if (kit_obj_symiter_new((KitObjFile*)f, &si) != KIT_OK) return SLICE_NULL; 224 for (;;) { 225 KitIterResult r = kit_obj_symiter_next(si, &s); 226 if (r != KIT_ITER_ITEM) break; 227 if (s.section != section_idx) continue; 228 if (s.value != offset) continue; 229 if (!s.name.len) continue; 230 if (s.name.s[0] == '$') continue; 231 found = s.name; 232 if (s.kind == KIT_SK_FUNC) break; 233 } 234 kit_obj_symiter_free(si); 235 return found; 236 } 237 238 KitStatus kit_disasm_obj(const KitContext* ctx, const KitObjFile* f, 239 KitWriter* out) { 240 uint32_t nsec, i; 241 KitDisasmContext dctx; 242 KitTarget* target = NULL; 243 KitTargetOptions topts; 244 KitStatus st; 245 if (!ctx || !f || !out) return KIT_INVALID; 246 memset(&topts, 0, sizeof topts); 247 topts.spec = kit_obj_target(f); 248 st = kit_target_new(ctx, &topts, &target); 249 if (st != KIT_OK) return st; 250 dctx.target = target; 251 dctx.context = *ctx; 252 nsec = kit_obj_nsections(f); 253 for (i = 0; i < nsec; ++i) { 254 KitObjSecInfo s; 255 const uint8_t* data = NULL; 256 size_t n = 0; 257 KitDisasmIter* it = NULL; 258 Slice head; 259 260 if (kit_obj_section(f, i, &s) != KIT_OK) continue; 261 if (s.kind != KIT_SEC_TEXT) continue; 262 if (kit_obj_section_data(f, i, &data, &n) != KIT_OK) continue; 263 if (!data || !n) continue; 264 265 w_str(out, "Disassembly of section "); 266 w_slice(out, s.name.len ? s.name : SLICE_LIT(".text")); 267 w_str(out, ":\n\n"); 268 269 st = kit_disasm_iter_new(&dctx, data, n, 0, f, &it); 270 if (st != KIT_OK) { 271 kit_target_free(target); 272 return st; 273 } 274 for (;;) { 275 KitInsn ins; 276 KitIterResult r = kit_disasm_iter_next(it, &ins); 277 if (r != KIT_ITER_ITEM) break; 278 head = dasm_sym_at(f, i, ins.vaddr); 279 if (head.len) { 280 w_hex(out, ins.vaddr, 16); 281 w_str(out, " <"); 282 w_slice(out, head); 283 w_str(out, ">:\n"); 284 } 285 w_hex_padded(out, ins.vaddr, 8); 286 w_str(out, ":\t"); 287 if (ins.nbytes == 4) { 288 uint32_t w = (uint32_t)ins.bytes[0] | ((uint32_t)ins.bytes[1] << 8) | 289 ((uint32_t)ins.bytes[2] << 16) | 290 ((uint32_t)ins.bytes[3] << 24); 291 w_hex(out, w, 8); 292 w_str(out, " \t"); 293 } else { 294 uint32_t k; 295 for (k = 0; k < ins.nbytes; ++k) { 296 w_hex(out, ins.bytes[k], 2); 297 } 298 w_str(out, " \t"); 299 } 300 w_slice(out, ins.mnemonic); 301 if (ins.operands.len) { 302 w_str(out, "\t"); 303 w_slice(out, ins.operands); 304 } 305 if (ins.annotation.len) { 306 w_str(out, " ; "); 307 w_slice(out, ins.annotation); 308 } 309 w_str(out, "\n"); 310 } 311 kit_disasm_iter_free(it); 312 } 313 st = kit_writer_status(out); 314 kit_target_free(target); 315 return st; 316 } 317 318 KitStatus kit_disasm_obj_bytes(const KitContext* ctx, const KitSlice* bytes, 319 KitWriter* out) { 320 KitObjFile* f = NULL; 321 KitStatus st; 322 if (!ctx || !bytes || !out) return KIT_INVALID; 323 st = kit_obj_open(ctx, SLICE_NULL, bytes, &f); 324 if (st != KIT_OK) return st; 325 st = kit_disasm_obj(ctx, f, out); 326 kit_obj_free(f); 327 return st; 328 }