object_file.c (29612B)
1 /* Public KitObjFile reader. Wraps the internal read_/obj_ surface 2 * and exposes format-neutral object inspection. */ 3 4 #include <kit/object.h> 5 #include <setjmp.h> 6 #include <string.h> 7 8 #include "core/buf.h" 9 #include "core/core.h" 10 #include "core/heap.h" 11 #include "core/pool.h" 12 #include "core/slice.h" 13 #include "core/vec.h" 14 #include "obj/format.h" 15 #include "obj/obj.h" 16 17 struct KitObjFile { 18 Compiler compiler; 19 const KitContext* ctx; 20 KitTarget* resolved_target; 21 ObjBuilder* ob; 22 ObjFmt fmt; 23 KitTargetSpec target; 24 const u8** sec_data_cache; 25 u32* sec_data_size; 26 u32 sec_data_n; 27 }; 28 29 KitStatus kit_obj_open(const KitContext* ctx, KitSlice name, 30 const KitSlice* input, KitObjFile** out) { 31 Heap* h; 32 KitObjFile* f; 33 const ObjFormatImpl* impl; 34 KitTargetSpec target; 35 KitStatus st; 36 37 if (!out) return KIT_INVALID; 38 *out = NULL; 39 if (!ctx || !ctx->heap || !input) return KIT_INVALID; 40 if (!input->data && input->len > 0) return KIT_INVALID; 41 42 st = kit_detect_target(input->data, input->len, &target); 43 if (st != KIT_OK) return st; 44 impl = obj_format_lookup(target.obj); 45 if (!impl || !impl->read) return KIT_UNSUPPORTED; 46 47 h = ctx->heap; 48 f = (KitObjFile*)h->alloc(h, sizeof(*f), _Alignof(KitObjFile)); 49 if (!f) return KIT_NOMEM; 50 memset(f, 0, sizeof(*f)); 51 f->ctx = ctx; 52 f->fmt = target.obj; 53 f->target = target; 54 55 { 56 KitTargetOptions topts; 57 memset(&topts, 0, sizeof topts); 58 topts.spec = target; 59 st = kit_target_new(ctx, &topts, &f->resolved_target); 60 if (st != KIT_OK) { 61 h->free(h, f, sizeof(*f)); 62 return st; 63 } 64 } 65 st = compiler_init(&f->compiler, f->resolved_target, ctx); 66 if (st != KIT_OK) { 67 kit_target_free(f->resolved_target); 68 h->free(h, f, sizeof(*f)); 69 return st; 70 } 71 { 72 PanicFrame panic; 73 compiler_panic_push(&f->compiler, &panic); 74 if (setjmp(panic.env)) { 75 compiler_run_cleanups(&f->compiler); 76 compiler_panic_pop(&f->compiler, &panic); 77 compiler_fini(&f->compiler); 78 kit_target_free(f->resolved_target); 79 h->free(h, f, sizeof(*f)); 80 return KIT_MALFORMED; 81 } 82 f->ob = impl->read(&f->compiler, name.s, input->data, input->len); 83 compiler_panic_pop(&f->compiler, &panic); 84 } 85 if (!f->ob) { 86 compiler_fini(&f->compiler); 87 kit_target_free(f->resolved_target); 88 h->free(h, f, sizeof(*f)); 89 return KIT_MALFORMED; 90 } 91 *out = f; 92 return KIT_OK; 93 } 94 95 void kit_obj_free(KitObjFile* f) { 96 Heap* h; 97 if (!f) return; 98 h = f->ctx->heap; 99 if (f->sec_data_cache) { 100 u32 i; 101 for (i = 0; i < f->sec_data_n; ++i) { 102 if (f->sec_data_cache[i]) { 103 h->free(h, (void*)f->sec_data_cache[i], f->sec_data_size[i]); 104 } 105 } 106 h->free(h, f->sec_data_cache, sizeof(*f->sec_data_cache) * f->sec_data_n); 107 h->free(h, f->sec_data_size, sizeof(*f->sec_data_size) * f->sec_data_n); 108 } 109 if (f->ob) obj_free(f->ob); 110 compiler_fini(&f->compiler); 111 kit_target_free(f->resolved_target); 112 h->free(h, f, sizeof(*f)); 113 } 114 115 KitObjFmt kit_obj_fmt(const KitObjFile* f) { return f->fmt; } 116 117 /* Public object-format name <-> KitObjFmt mapping (objcopy/objdump bfdname 118 * spellings). Thin wrappers over the internal obj_format name registry. */ 119 KitStatus kit_obj_fmt_from_name(const char* name, KitObjFmt* out) { 120 return obj_format_fmt_from_name(name, out) ? KIT_OK : KIT_NOT_FOUND; 121 } 122 123 const char* kit_obj_fmt_name(KitObjFmt fmt) { return obj_format_fmt_name(fmt); } 124 125 KitTargetSpec kit_obj_target(const KitObjFile* f) { return f->target; } 126 127 uint32_t kit_obj_nsections(const KitObjFile* f) { 128 return obj_section_count(f->ob); 129 } 130 131 KitStatus kit_obj_section(const KitObjFile* f, KitObjSection idx, 132 KitObjSecInfo* out) { 133 const Section* sec; 134 if (!f || !out) return KIT_INVALID; 135 if (idx >= obj_section_count(f->ob)) return KIT_NOT_FOUND; 136 sec = obj_section_get(f->ob, (ObjSecId)(idx + 1)); 137 if (!sec) return KIT_NOT_FOUND; 138 out->name = 139 sec->name ? pool_slice(f->compiler.global, sec->name) : SLICE_LIT(""); 140 out->kind = (KitSecKind)sec->kind; 141 out->flags = (uint32_t)sec->flags; 142 out->size = sec->bss_size ? sec->bss_size : sec->bytes.total; 143 out->addr = sec->addr; 144 out->align = sec->align > 1u ? sec->align : 1u; 145 out->entsize = sec->entsize; 146 return KIT_OK; 147 } 148 149 KitStatus kit_obj_section_data(const KitObjFile* cf, KitObjSection idx, 150 const uint8_t** data_out, size_t* len_out) { 151 KitObjFile* f = (KitObjFile*)cf; 152 const Section* sec; 153 Heap* h; 154 u32 n; 155 u8* buf; 156 157 if (!f || !data_out || !len_out) return KIT_INVALID; 158 *data_out = NULL; 159 *len_out = 0; 160 161 n = obj_section_count(f->ob); 162 if (idx >= n) return KIT_NOT_FOUND; 163 164 sec = obj_section_get(f->ob, (ObjSecId)(idx + 1)); 165 if (!sec) return KIT_NOT_FOUND; 166 if (sec->bss_size || sec->bytes.total == 0) return KIT_OK; 167 168 h = f->ctx->heap; 169 170 if (!f->sec_data_cache) { 171 f->sec_data_cache = (const u8**)h->alloc(h, sizeof(*f->sec_data_cache) * n, 172 _Alignof(const u8*)); 173 if (!f->sec_data_cache) return KIT_NOMEM; 174 f->sec_data_size = 175 (u32*)h->alloc(h, sizeof(*f->sec_data_size) * n, _Alignof(u32)); 176 if (!f->sec_data_size) { 177 h->free(h, f->sec_data_cache, sizeof(*f->sec_data_cache) * n); 178 f->sec_data_cache = NULL; 179 return KIT_NOMEM; 180 } 181 { 182 u32 i; 183 for (i = 0; i < n; ++i) { 184 f->sec_data_cache[i] = NULL; 185 f->sec_data_size[i] = 0; 186 } 187 } 188 f->sec_data_n = n; 189 } 190 191 if (f->sec_data_cache[idx]) { 192 *data_out = f->sec_data_cache[idx]; 193 *len_out = f->sec_data_size[idx]; 194 return KIT_OK; 195 } 196 197 buf = (u8*)h->alloc(h, sec->bytes.total, 1); 198 if (!buf) return KIT_NOMEM; 199 buf_flatten(&sec->bytes, buf); 200 f->sec_data_cache[idx] = buf; 201 f->sec_data_size[idx] = sec->bytes.total; 202 *data_out = buf; 203 *len_out = sec->bytes.total; 204 return KIT_OK; 205 } 206 207 KitStatus kit_obj_section_format_flags(const KitObjFile* f, KitObjSection idx, 208 uint32_t* raw_type_out, 209 uint32_t* raw_flags_out) { 210 const Section* sec; 211 if (!f) return KIT_INVALID; 212 if (idx >= obj_section_count(f->ob)) return KIT_NOT_FOUND; 213 sec = obj_section_get(f->ob, (ObjSecId)(idx + 1)); 214 if (!sec) return KIT_NOT_FOUND; 215 if (raw_type_out) *raw_type_out = sec->ext_type; 216 if (raw_flags_out) *raw_flags_out = sec->ext_flags; 217 return KIT_OK; 218 } 219 220 KitStatus kit_obj_section_by_name(const KitObjFile* f, KitSlice name, 221 KitObjSection* out) { 222 u32 n, i; 223 if (!f || !out) return KIT_INVALID; 224 n = obj_section_count(f->ob); 225 for (i = 0; i < n; ++i) { 226 const Section* sec = obj_section_get(f->ob, (ObjSecId)(i + 1)); 227 if (!sec || !sec->name) continue; 228 if (slice_eq(pool_slice(f->compiler.global, sec->name), name)) { 229 *out = i; 230 return KIT_OK; 231 } 232 } 233 return KIT_NOT_FOUND; 234 } 235 236 int kit_obj_section_size_class(const KitObjSecInfo* sec) { 237 int exec, write; 238 if (!sec) return KIT_SEC_SIZE_NONE; 239 exec = (sec->flags & KIT_SF_EXEC) != 0; 240 write = (sec->flags & KIT_SF_WRITE) != 0; 241 if (!(sec->flags & KIT_SF_ALLOC)) return KIT_SEC_SIZE_NONE; 242 if (sec->kind == KIT_SEC_DEBUG) return KIT_SEC_SIZE_NONE; 243 if (sec->kind == KIT_SEC_TEXT || exec) return KIT_SEC_SIZE_TEXT; 244 if (sec->kind == KIT_SEC_BSS) return KIT_SEC_SIZE_BSS; 245 if (sec->kind == KIT_SEC_RODATA) return KIT_SEC_SIZE_DATA; 246 if (sec->kind == KIT_SEC_DATA || write) return KIT_SEC_SIZE_DATA; 247 return KIT_SEC_SIZE_DATA; 248 } 249 250 KitStatus kit_obj_size_totals(KitObjFile* f, bool include_common, 251 KitObjSizeTotals* out) { 252 u32 ns, i; 253 if (!f || !out) return KIT_INVALID; 254 out->text = 0; 255 out->data = 0; 256 out->bss = 0; 257 out->total = 0; 258 ns = obj_section_count(f->ob); 259 for (i = 0; i < ns; ++i) { 260 KitObjSecInfo sec; 261 if (kit_obj_section(f, i, &sec) != KIT_OK) continue; 262 switch (kit_obj_section_size_class(&sec)) { 263 case KIT_SEC_SIZE_TEXT: 264 out->text += sec.size; 265 break; 266 case KIT_SEC_SIZE_DATA: 267 out->data += sec.size; 268 break; 269 case KIT_SEC_SIZE_BSS: 270 out->bss += sec.size; 271 break; 272 default: 273 break; 274 } 275 } 276 if (include_common) { 277 KitObjSymIter* it = NULL; 278 if (kit_obj_symiter_new(f, &it) == KIT_OK) { 279 KitObjSymInfo si; 280 while (kit_obj_symiter_next(it, &si) == KIT_ITER_ITEM) { 281 if (si.kind == KIT_SK_COMMON) out->bss += si.size; 282 } 283 kit_obj_symiter_free(it); 284 } 285 } 286 out->total = out->text + out->data + out->bss; 287 return KIT_OK; 288 } 289 290 static void fill_syminfo(const KitObjFile* f, ObjSymId id, const ObjSym* sym, 291 KitObjSymInfo* out) { 292 out->name = 293 sym->name ? pool_slice(f->compiler.global, sym->name) : SLICE_LIT(""); 294 out->id = (id != OBJ_SYM_NONE) ? (KitObjSymbol)id : KIT_OBJ_SYMBOL_NONE; 295 out->bind = (KitSymBind)sym->bind; 296 out->kind = (KitSymKind)sym->kind; 297 out->section = sym->section_id != OBJ_SEC_NONE 298 ? (KitObjSection)(sym->section_id - 1) 299 : KIT_SECTION_NONE; 300 out->value = sym->value; 301 out->size = sym->size; 302 } 303 304 KitStatus kit_obj_symbol_by_name(const KitObjFile* f, KitSlice name, 305 KitObjSymInfo* out) { 306 ObjSymIter* it; 307 ObjSymEntry e; 308 if (!f || !out) return KIT_INVALID; 309 it = obj_symiter_new(f->ob); 310 if (!it) return KIT_NOMEM; 311 while (obj_symiter_next(it, &e)) { 312 if (!e.sym || !e.sym->name) continue; 313 if (slice_eq(pool_slice(f->compiler.global, e.sym->name), name)) { 314 fill_syminfo(f, e.id, e.sym, out); 315 obj_symiter_free(it); 316 return KIT_OK; 317 } 318 } 319 obj_symiter_free(it); 320 return KIT_NOT_FOUND; 321 } 322 323 struct KitObjSymIter { 324 const KitObjFile* file; 325 ObjSymIter* inner; /* .symtab walk; NULL when iterating the dynamic table */ 326 u32 dyn_idx; /* next index into obj_image dynsyms (dynamic mode) */ 327 int dynamic; 328 }; 329 330 /* Shared by kit_obj_symiter_new (.symtab) and kit_obj_dynsymiter_new 331 * (.dynsym). When dynamic, the inner ObjSymIter is unused and we walk the 332 * image's dynamic symbol table by index. */ 333 static KitStatus symiter_make(const KitObjFile* f, int dynamic, 334 KitObjSymIter** out) { 335 Heap* h; 336 KitObjSymIter* it; 337 if (!f || !out) return KIT_INVALID; 338 h = f->ctx->heap; 339 it = (KitObjSymIter*)h->alloc(h, sizeof(*it), _Alignof(KitObjSymIter)); 340 if (!it) return KIT_NOMEM; 341 it->file = f; 342 it->inner = NULL; 343 it->dyn_idx = 0; 344 it->dynamic = dynamic; 345 if (!dynamic) { 346 it->inner = obj_symiter_new(f->ob); 347 if (!it->inner) { 348 h->free(h, it, sizeof(*it)); 349 return KIT_NOMEM; 350 } 351 } 352 *out = it; 353 return KIT_OK; 354 } 355 356 KitStatus kit_obj_symiter_new(const KitObjFile* f, KitObjSymIter** out) { 357 return symiter_make(f, 0, out); 358 } 359 360 KitStatus kit_obj_dynsymiter_new(const KitObjFile* f, KitObjSymIter** out) { 361 return symiter_make(f, 1, out); 362 } 363 364 KitIterResult kit_obj_symiter_next(KitObjSymIter* it, KitObjSymInfo* out) { 365 ObjSymEntry entry; 366 if (!it || !out) return KIT_ITER_ERROR; 367 if (it->dynamic) { 368 const ObjImage* im = obj_image(it->file->ob); 369 const ObjImageSym* s; 370 if (it->dyn_idx >= obj_image_ndynsyms(im)) return KIT_ITER_END; 371 s = obj_image_dynsym(im, it->dyn_idx++); 372 out->name = pool_slice(it->file->compiler.global, s->name); 373 out->id = KIT_OBJ_SYMBOL_NONE; 374 out->bind = (KitSymBind)s->bind; 375 out->kind = (KitSymKind)s->kind; 376 out->section = s->section != OBJ_SEC_NONE ? (KitObjSection)(s->section - 1) 377 : KIT_SECTION_NONE; 378 out->value = s->value; 379 out->size = s->size; 380 return KIT_ITER_ITEM; 381 } 382 if (!obj_symiter_next(it->inner, &entry)) return KIT_ITER_END; 383 fill_syminfo(it->file, entry.id, entry.sym, out); 384 return KIT_ITER_ITEM; 385 } 386 387 void kit_obj_symiter_free(KitObjSymIter* it) { 388 Heap* h; 389 if (!it) return; 390 if (it->inner) obj_symiter_free(it->inner); 391 h = it->file->ctx->heap; 392 h->free(h, it, sizeof(*it)); 393 } 394 395 struct KitObjRelocIter { 396 KitObjFile* file; 397 u32 idx; 398 u32 total; 399 int dynamic; /* iterate obj_image dynamic relocs instead of section relocs */ 400 }; 401 402 static KitStatus reliter_make(KitObjFile* f, int dynamic, 403 KitObjRelocIter** out) { 404 Heap* h; 405 KitObjRelocIter* it; 406 if (!f || !out) return KIT_INVALID; 407 h = f->ctx->heap; 408 it = (KitObjRelocIter*)h->alloc(h, sizeof(*it), _Alignof(KitObjRelocIter)); 409 if (!it) return KIT_NOMEM; 410 it->file = f; 411 it->idx = 0; 412 it->dynamic = dynamic; 413 it->total = 414 dynamic ? obj_image_ndynrelocs(obj_image(f->ob)) : obj_reloc_total(f->ob); 415 *out = it; 416 return KIT_OK; 417 } 418 419 KitStatus kit_obj_reliter_new(KitObjFile* f, KitObjRelocIter** out) { 420 return reliter_make(f, 0, out); 421 } 422 423 KitStatus kit_obj_dynreliter_new(KitObjFile* f, KitObjRelocIter** out) { 424 return reliter_make(f, 1, out); 425 } 426 427 /* Format-specific canonical spelling of a reloc kind (e.g. "R_X86_64_PLT32", 428 * "R_AARCH64_CALL26", "R_RISCV_CALL"), or NULL when the format has no per-arch 429 * name table (callers fall back to the arch-neutral reloc_kind_name). 430 * 431 * Consulted for every ELF arch whose ObjElfArchOps carries a reloc_name table 432 * (x86_64 / aarch64 / riscv): the kit-canonical RelocKind is lowered to its 433 * ELF wire type via reloc_to, then named — matching binutils objdump's 434 * spelling. The Mach-O / COFF formats have no reloc_name table yet and keep 435 * the arch-neutral spelling. reloc_to maps unsupported kinds to wire type 0; 436 * only R_NONE legitimately names that slot, so anything else falling through 437 * to 0 is reported as "no per-arch name" (NULL) rather than the format's NONE 438 * spelling. */ 439 static const char* kit_obj_reloc_kind_name(KitArchKind arch, KitObjFmt fmt, 440 u32 kind) { 441 const ObjFormatImpl* impl; 442 const ObjElfArchOps* ops; 443 u32 wire; 444 if (fmt != KIT_OBJ_ELF) return NULL; 445 impl = obj_format_lookup(fmt); 446 if (!impl || !impl->elf_arch) return NULL; 447 ops = impl->elf_arch(arch); 448 if (!ops || !ops->reloc_to || !ops->reloc_name) return NULL; 449 wire = ops->reloc_to(kind); 450 if (wire == 0u && (RelocKind)kind != R_NONE) return NULL; 451 return ops->reloc_name(wire); 452 } 453 454 KitIterResult kit_obj_reliter_next(KitObjRelocIter* it, KitObjReloc* out) { 455 const Reloc* r; 456 const ObjSym* sym; 457 if (!it || !out) return KIT_ITER_ERROR; 458 if (it->idx >= it->total) return KIT_ITER_END; 459 460 if (it->dynamic) { 461 const ObjImageReloc* dr = 462 obj_image_dynreloc(obj_image(it->file->ob), it->idx++); 463 const char* kn; 464 out->section = 465 dr->section ? (KitObjSection)(dr->section - 1) : KIT_SECTION_NONE; 466 out->offset = dr->offset; 467 out->addend = dr->addend; 468 out->kind.arch = it->file->target.arch; 469 out->kind.obj_fmt = it->file->fmt; 470 out->kind.code = (uint32_t)dr->kind; 471 kn = 472 kit_obj_reloc_kind_name(it->file->target.arch, it->file->fmt, dr->kind); 473 if (!kn) kn = reloc_kind_name(dr->kind); 474 out->kind_name = kn ? slice_from_cstr(kn) : SLICE_NULL; 475 out->sym = KIT_OBJ_SYMBOL_NONE; 476 out->sym_name = pool_slice(it->file->compiler.global, dr->sym_name); 477 return KIT_ITER_ITEM; 478 } 479 480 r = obj_reloc_at(it->file->ob, it->idx++); 481 out->section = 482 r->section_id ? (KitObjSection)(r->section_id - 1) : KIT_SECTION_NONE; 483 out->offset = r->offset; 484 out->addend = r->addend; 485 out->kind.arch = it->file->target.arch; 486 out->kind.obj_fmt = it->file->fmt; 487 out->kind.code = (uint32_t)r->kind; 488 { 489 /* Prefer the format-specific canonical spelling (e.g. "R_X86_64_PLT32"); 490 * fall back to the arch-neutral diagnostic spelling ("RV_CALL"). */ 491 const char* kn = 492 kit_obj_reloc_kind_name(it->file->target.arch, it->file->fmt, r->kind); 493 if (!kn) kn = reloc_kind_name(r->kind); 494 out->kind_name = kn ? slice_from_cstr(kn) : SLICE_NULL; 495 } 496 497 if (r->sym == OBJ_SYM_NONE) { 498 out->sym = KIT_OBJ_SYMBOL_NONE; 499 out->sym_name = SLICE_LIT(""); 500 } else { 501 out->sym = (KitObjSymbol)r->sym; 502 sym = obj_symbol_get(it->file->ob, r->sym); 503 out->sym_name = (sym && sym->name) 504 ? pool_slice(it->file->compiler.global, sym->name) 505 : SLICE_LIT(""); 506 } 507 return KIT_ITER_ITEM; 508 } 509 510 void kit_obj_reliter_free(KitObjRelocIter* it) { 511 Heap* h; 512 if (!it) return; 513 h = it->file->ctx->heap; 514 h->free(h, it, sizeof(*it)); 515 } 516 517 static int reloc_live_id_in_set(KitObjSymbol id, const KitObjSymbol* arr, 518 u32 n) { 519 u32 i; 520 for (i = 0; i < n; ++i) 521 if (arr[i] == id) return 1; 522 return 0; 523 } 524 525 KitStatus kit_obj_reloc_live_symbols(const KitContext* ctx, KitObjFile* f, 526 KitObjSymbol** out, uint32_t* n_out) { 527 Heap* h; 528 KitObjRelocIter* rit = NULL; 529 KitObjSymbol* arr = NULL; 530 u32 n = 0, cap = 0; 531 KitStatus st; 532 533 if (!out || !n_out) return KIT_INVALID; 534 *out = NULL; 535 *n_out = 0; 536 if (!ctx || !ctx->heap || !f) return KIT_INVALID; 537 h = ctx->heap; 538 539 st = kit_obj_reliter_new(f, &rit); 540 if (st != KIT_OK) return st; 541 for (;;) { 542 KitObjReloc r; 543 KitIterResult ir = kit_obj_reliter_next(rit, &r); 544 if (ir != KIT_ITER_ITEM) break; 545 if (r.sym == KIT_OBJ_SYMBOL_NONE) continue; 546 /* Skip relocs hosted in a debug section -- that section is being dropped, 547 * so its relocs don't actually keep their targets alive. */ 548 if (r.section != KIT_SECTION_NONE) { 549 KitObjSecInfo hi; 550 if (kit_obj_section(f, r.section, &hi) == KIT_OK && 551 hi.kind == KIT_SEC_DEBUG) 552 continue; 553 } 554 if (reloc_live_id_in_set(r.sym, arr, n)) continue; 555 if (n >= cap) { 556 u32 newcap = cap ? cap * 2u : 32u; 557 KitObjSymbol* nb = 558 (KitObjSymbol*)h->alloc(h, (size_t)newcap * sizeof(*nb), 559 _Alignof(KitObjSymbol)); 560 if (!nb) { 561 kit_obj_reliter_free(rit); 562 if (arr) h->free(h, arr, (size_t)cap * sizeof(*arr)); 563 return KIT_NOMEM; 564 } 565 if (arr) { 566 memcpy(nb, arr, (size_t)n * sizeof(*arr)); 567 h->free(h, arr, (size_t)cap * sizeof(*arr)); 568 } 569 arr = nb; 570 cap = newcap; 571 } 572 arr[n++] = r.sym; 573 } 574 kit_obj_reliter_free(rit); 575 576 /* Hand back an exactly-sized array so the caller frees with n_out, not a 577 * private capacity. */ 578 if (n == 0) { 579 if (arr) h->free(h, arr, (size_t)cap * sizeof(*arr)); 580 return KIT_OK; 581 } 582 if (n != cap) { 583 KitObjSymbol* shrunk = 584 (KitObjSymbol*)h->alloc(h, (size_t)n * sizeof(*shrunk), 585 _Alignof(KitObjSymbol)); 586 if (!shrunk) { 587 /* Keep the over-sized buffer rather than fail; but the caller frees with 588 * n, which would mismatch. Safer to report NOMEM and release. */ 589 h->free(h, arr, (size_t)cap * sizeof(*arr)); 590 return KIT_NOMEM; 591 } 592 memcpy(shrunk, arr, (size_t)n * sizeof(*shrunk)); 593 h->free(h, arr, (size_t)cap * sizeof(*arr)); 594 arr = shrunk; 595 } 596 *out = arr; 597 *n_out = n; 598 return KIT_OK; 599 } 600 601 struct KitObjGroupIter { 602 KitObjFile* file; 603 ObjGroupIter* inner; 604 /* Translation scratch for the borrowed `sections` slice handed back to 605 * the caller. Lazily grown to the largest group's nsections. */ 606 KitObjSection* secbuf; 607 u32 seccap; 608 }; 609 610 KitStatus kit_obj_groupiter_new(KitObjFile* f, KitObjGroupIter** out) { 611 Heap* h; 612 KitObjGroupIter* it; 613 if (!f || !out) return KIT_INVALID; 614 h = f->ctx->heap; 615 it = (KitObjGroupIter*)h->alloc(h, sizeof(*it), _Alignof(KitObjGroupIter)); 616 if (!it) return KIT_NOMEM; 617 memset(it, 0, sizeof(*it)); 618 it->file = f; 619 it->inner = obj_groupiter_new(f->ob); 620 if (!it->inner) { 621 h->free(h, it, sizeof(*it)); 622 return KIT_NOMEM; 623 } 624 *out = it; 625 return KIT_OK; 626 } 627 628 KitIterResult kit_obj_groupiter_next(KitObjGroupIter* it, 629 KitObjGroupInfo* out) { 630 ObjGroupEntry entry; 631 Heap* h; 632 u32 i; 633 if (!it || !out) return KIT_ITER_ERROR; 634 if (!obj_groupiter_next(it->inner, &entry)) return KIT_ITER_END; 635 h = it->file->ctx->heap; 636 if (entry.group->nsections > it->seccap) { 637 KitObjSection* nb; 638 nb = (KitObjSection*)h->alloc(h, sizeof(*nb) * entry.group->nsections, 639 _Alignof(KitObjSection)); 640 if (!nb) return KIT_ITER_ERROR; 641 if (it->secbuf) h->free(h, it->secbuf, sizeof(*it->secbuf) * it->seccap); 642 it->secbuf = nb; 643 it->seccap = entry.group->nsections; 644 } 645 for (i = 0; i < entry.group->nsections; ++i) { 646 ObjSecId sid = entry.group->sections[i]; 647 it->secbuf[i] = 648 (sid != OBJ_SEC_NONE) ? (KitObjSection)(sid - 1) : KIT_SECTION_NONE; 649 } 650 out->name = entry.group->name 651 ? pool_slice(it->file->compiler.global, entry.group->name) 652 : KIT_SLICE_NULL; 653 out->signature = (entry.group->signature != OBJ_SYM_NONE) 654 ? (KitObjSymbol)entry.group->signature 655 : KIT_OBJ_SYMBOL_NONE; 656 out->flags = entry.group->flags; 657 out->nsections = entry.group->nsections; 658 out->sections = it->secbuf; 659 return KIT_ITER_ITEM; 660 } 661 662 void kit_obj_groupiter_free(KitObjGroupIter* it) { 663 Heap* h; 664 if (!it) return; 665 h = it->file->ctx->heap; 666 if (it->secbuf) h->free(h, it->secbuf, sizeof(*it->secbuf) * it->seccap); 667 obj_groupiter_free(it->inner); 668 h->free(h, it, sizeof(*it)); 669 } 670 671 /* Accessor for disasm/jit to access the underlying ObjBuilder when both 672 * are inside libkit. Internal name kept stable for existing callers 673 * (src/link/link_jit.c, src/api/disasm.c). */ 674 ObjBuilder* kit_objfile_builder(const KitObjFile* f) { 675 return f ? f->ob : NULL; 676 } 677 678 /* Public alias of kit_objfile_builder. Promoted to the public API so the 679 * driver (and other libkit consumers) can take an opened object and feed 680 * it into kit_obj_builder_emit for a byte-equivalent roundtrip without 681 * re-implementing the read-then-replay loop. */ 682 KitObjBuilder* kit_obj_file_builder(const KitObjFile* f) { 683 return kit_objfile_builder(f); 684 } 685 686 /* Allocate an empty KitObjFile wrapping a private Compiler and a fresh 687 * ObjBuilder. Used by the JIT debug-view builder (src/link/link_jit.c) 688 * to assemble a synthetic object file from merged input debug sections. 689 * The handle is freed via kit_objfile_internal_free below — the public 690 * kit_obj_free path is keyed off obj_read_bytes, so the view path uses 691 * its own teardown that does not depend on the cached section data 692 * tables. */ 693 KitObjFile* kit_objfile_internal_new(const KitContext* ctx, 694 KitTargetSpec target, KitObjFmt fmt) { 695 Heap* h; 696 KitObjFile* f; 697 if (!ctx || !ctx->heap) return NULL; 698 h = ctx->heap; 699 f = (KitObjFile*)h->alloc(h, sizeof(*f), _Alignof(KitObjFile)); 700 if (!f) return NULL; 701 memset(f, 0, sizeof(*f)); 702 f->ctx = ctx; 703 f->fmt = fmt; 704 f->target = target; 705 { 706 KitTargetOptions topts; 707 KitStatus st; 708 memset(&topts, 0, sizeof topts); 709 topts.spec = target; 710 st = kit_target_new(ctx, &topts, &f->resolved_target); 711 if (st != KIT_OK) { 712 h->free(h, f, sizeof(*f)); 713 return NULL; 714 } 715 st = compiler_init(&f->compiler, f->resolved_target, ctx); 716 if (st != KIT_OK) { 717 kit_target_free(f->resolved_target); 718 h->free(h, f, sizeof(*f)); 719 return NULL; 720 } 721 } 722 { 723 PanicFrame panic; 724 compiler_panic_push(&f->compiler, &panic); 725 if (setjmp(panic.env)) { 726 compiler_run_cleanups(&f->compiler); 727 compiler_panic_pop(&f->compiler, &panic); 728 compiler_fini(&f->compiler); 729 kit_target_free(f->resolved_target); 730 h->free(h, f, sizeof(*f)); 731 return NULL; 732 } 733 f->ob = obj_new(&f->compiler); 734 compiler_panic_pop(&f->compiler, &panic); 735 } 736 if (!f->ob) { 737 compiler_fini(&f->compiler); 738 kit_target_free(f->resolved_target); 739 h->free(h, f, sizeof(*f)); 740 return NULL; 741 } 742 return f; 743 } 744 745 void kit_objfile_internal_free(KitObjFile* f) { 746 /* Same teardown contract as kit_obj_free: caller may have cached 747 * section data, so we route through the same path. */ 748 kit_obj_free(f); 749 } 750 751 /* ============================================================ 752 * Linked-image view 753 * ============================================================ */ 754 755 KitObjKind kit_obj_kind(const KitObjFile* f) { 756 const ObjImage* im; 757 if (!f) return KIT_OBJ_KIND_REL; 758 im = obj_image(f->ob); 759 if (!im) return KIT_OBJ_KIND_REL; 760 switch (obj_image_kind(im)) { 761 case OBJ_KIND_EXEC: 762 return KIT_OBJ_KIND_EXEC; 763 case OBJ_KIND_DYN: 764 return KIT_OBJ_KIND_DYN; 765 case OBJ_KIND_CORE: 766 return KIT_OBJ_KIND_CORE; 767 case OBJ_KIND_REL: 768 default: 769 return KIT_OBJ_KIND_REL; 770 } 771 } 772 773 KitStatus kit_obj_image_info(const KitObjFile* f, KitObjImageInfo* out) { 774 const ObjImage* im; 775 if (!f || !out) return KIT_INVALID; 776 im = obj_image(f->ob); 777 if (!im) return KIT_NOT_FOUND; 778 out->entry = obj_image_entry(im); 779 out->image_base = obj_image_base(im); 780 out->interp = pool_slice(f->compiler.global, obj_image_interp(im)); 781 out->soname = pool_slice(f->compiler.global, obj_image_soname(im)); 782 return KIT_OK; 783 } 784 785 struct KitObjSegIter { 786 KitObjFile* file; 787 u32 idx; 788 }; 789 790 KitStatus kit_obj_segiter_new(KitObjFile* f, KitObjSegIter** out) { 791 Heap* h; 792 KitObjSegIter* it; 793 if (!f || !out) return KIT_INVALID; 794 h = f->ctx->heap; 795 it = (KitObjSegIter*)h->alloc(h, sizeof(*it), _Alignof(KitObjSegIter)); 796 if (!it) return KIT_NOMEM; 797 it->file = f; 798 it->idx = 0; 799 *out = it; 800 return KIT_OK; 801 } 802 803 KitIterResult kit_obj_segiter_next(KitObjSegIter* it, KitObjSegInfo* out) { 804 const ObjImage* im; 805 const ObjSegment* s; 806 if (!it || !out) return KIT_ITER_ERROR; 807 im = obj_image(it->file->ob); 808 if (it->idx >= obj_image_nsegments(im)) return KIT_ITER_END; 809 s = obj_image_segment(im, it->idx++); 810 out->name = pool_slice(it->file->compiler.global, s->name); 811 out->vaddr = s->vaddr; 812 out->paddr = s->paddr; 813 out->vsize = s->vsize; 814 out->file_off = s->file_off; 815 out->file_size = s->file_size; 816 out->perms = s->perms; /* OBJ_SEG_* and KIT_SEG_* share bit values */ 817 out->align = s->align; 818 return KIT_ITER_ITEM; 819 } 820 821 void kit_obj_segiter_free(KitObjSegIter* it) { 822 Heap* h; 823 if (!it) return; 824 h = it->file->ctx->heap; 825 h->free(h, it, sizeof(*it)); 826 } 827 828 struct KitObjDepIter { 829 KitObjFile* file; 830 u32 idx; 831 KitSlice* import_buf; /* scratch for the current dep's import names */ 832 u32 import_cap; 833 }; 834 835 KitStatus kit_obj_depiter_new(KitObjFile* f, KitObjDepIter** out) { 836 Heap* h; 837 KitObjDepIter* it; 838 if (!f || !out) return KIT_INVALID; 839 h = f->ctx->heap; 840 it = (KitObjDepIter*)h->alloc(h, sizeof(*it), _Alignof(KitObjDepIter)); 841 if (!it) return KIT_NOMEM; 842 it->file = f; 843 it->idx = 0; 844 it->import_buf = NULL; 845 it->import_cap = 0; 846 *out = it; 847 return KIT_OK; 848 } 849 850 KitIterResult kit_obj_depiter_next(KitObjDepIter* it, KitObjDepInfo* out) { 851 const ObjImage* im; 852 const ObjImageDep* d; 853 Heap* h; 854 u32 i; 855 if (!it || !out) return KIT_ITER_ERROR; 856 im = obj_image(it->file->ob); 857 if (it->idx >= obj_image_ndeps(im)) return KIT_ITER_END; 858 d = obj_image_dep(im, it->idx++); 859 out->name = pool_slice(it->file->compiler.global, d->name); 860 out->imports = NULL; 861 out->nimports = d->nimports; 862 if (d->nimports) { 863 h = it->file->ctx->heap; 864 if (it->import_cap < d->nimports) { 865 if (VEC_GROW(h, it->import_buf, it->import_cap, d->nimports)) 866 return KIT_ITER_ERROR; 867 } 868 for (i = 0; i < d->nimports; ++i) 869 it->import_buf[i] = pool_slice(it->file->compiler.global, d->imports[i]); 870 out->imports = it->import_buf; 871 } 872 return KIT_ITER_ITEM; 873 } 874 875 void kit_obj_depiter_free(KitObjDepIter* it) { 876 Heap* h; 877 if (!it) return; 878 h = it->file->ctx->heap; 879 if (it->import_buf) 880 h->free(h, it->import_buf, sizeof(*it->import_buf) * it->import_cap); 881 h->free(h, it, sizeof(*it)); 882 } 883 884 struct KitObjRpathIter { 885 KitObjFile* file; 886 u32 idx; 887 }; 888 889 KitStatus kit_obj_rpathiter_new(KitObjFile* f, KitObjRpathIter** out) { 890 Heap* h; 891 KitObjRpathIter* it; 892 if (!f || !out) return KIT_INVALID; 893 h = f->ctx->heap; 894 it = (KitObjRpathIter*)h->alloc(h, sizeof(*it), _Alignof(KitObjRpathIter)); 895 if (!it) return KIT_NOMEM; 896 it->file = f; 897 it->idx = 0; 898 *out = it; 899 return KIT_OK; 900 } 901 902 KitIterResult kit_obj_rpathiter_next(KitObjRpathIter* it, KitSlice* out) { 903 const ObjImage* im; 904 if (!it || !out) return KIT_ITER_ERROR; 905 im = obj_image(it->file->ob); 906 if (it->idx >= obj_image_nrpaths(im)) return KIT_ITER_END; 907 *out = pool_slice(it->file->compiler.global, obj_image_rpath(im, it->idx++)); 908 return KIT_ITER_ITEM; 909 } 910 911 void kit_obj_rpathiter_free(KitObjRpathIter* it) { 912 Heap* h; 913 if (!it) return; 914 h = it->file->ctx->heap; 915 h->free(h, it, sizeof(*it)); 916 } 917 918 struct KitObjImageRawIter { 919 KitObjFile* file; 920 u32 idx; 921 }; 922 923 KitStatus kit_obj_image_rawiter_new(KitObjFile* f, KitObjImageRawIter** out) { 924 Heap* h; 925 KitObjImageRawIter* it; 926 if (!f || !out) return KIT_INVALID; 927 if (!obj_image(f->ob)) return KIT_NOT_FOUND; /* relocatable: no image */ 928 h = f->ctx->heap; 929 it = (KitObjImageRawIter*)h->alloc(h, sizeof(*it), 930 _Alignof(KitObjImageRawIter)); 931 if (!it) return KIT_NOMEM; 932 it->file = f; 933 it->idx = 0; 934 *out = it; 935 return KIT_OK; 936 } 937 938 KitIterResult kit_obj_image_rawiter_next(KitObjImageRawIter* it, 939 KitObjImageRaw* out) { 940 const ObjImage* im; 941 const ObjImageRaw* r; 942 if (!it || !out) return KIT_ITER_ERROR; 943 im = obj_image(it->file->ob); 944 if (it->idx >= obj_image_nraws(im)) return KIT_ITER_END; 945 r = obj_image_raw(im, it->idx++); 946 out->tag = r->tag; 947 out->value = r->value; 948 out->extra = r->extra; 949 return KIT_ITER_ITEM; 950 } 951 952 void kit_obj_image_rawiter_free(KitObjImageRawIter* it) { 953 Heap* h; 954 if (!it) return; 955 h = it->file->ctx->heap; 956 h->free(h, it, sizeof(*it)); 957 }