kit

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

object_file.c (25266B)


      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 static void fill_syminfo(const KitObjFile* f, ObjSymId id, const ObjSym* sym,
    237                          KitObjSymInfo* out) {
    238   out->name =
    239       sym->name ? pool_slice(f->compiler.global, sym->name) : SLICE_LIT("");
    240   out->id = (id != OBJ_SYM_NONE) ? (KitObjSymbol)id : KIT_OBJ_SYMBOL_NONE;
    241   out->bind = (KitSymBind)sym->bind;
    242   out->kind = (KitSymKind)sym->kind;
    243   out->section = sym->section_id != OBJ_SEC_NONE
    244                      ? (KitObjSection)(sym->section_id - 1)
    245                      : KIT_SECTION_NONE;
    246   out->value = sym->value;
    247   out->size = sym->size;
    248 }
    249 
    250 KitStatus kit_obj_symbol_by_name(const KitObjFile* f, KitSlice name,
    251                                  KitObjSymInfo* out) {
    252   ObjSymIter* it;
    253   ObjSymEntry e;
    254   if (!f || !out) return KIT_INVALID;
    255   it = obj_symiter_new(f->ob);
    256   if (!it) return KIT_NOMEM;
    257   while (obj_symiter_next(it, &e)) {
    258     if (!e.sym || !e.sym->name) continue;
    259     if (slice_eq(pool_slice(f->compiler.global, e.sym->name), name)) {
    260       fill_syminfo(f, e.id, e.sym, out);
    261       obj_symiter_free(it);
    262       return KIT_OK;
    263     }
    264   }
    265   obj_symiter_free(it);
    266   return KIT_NOT_FOUND;
    267 }
    268 
    269 struct KitObjSymIter {
    270   KitObjFile* file;
    271   ObjSymIter* inner; /* .symtab walk; NULL when iterating the dynamic table */
    272   u32 dyn_idx;       /* next index into obj_image dynsyms (dynamic mode) */
    273   int dynamic;
    274 };
    275 
    276 /* Shared by kit_obj_symiter_new (.symtab) and kit_obj_dynsymiter_new
    277  * (.dynsym). When dynamic, the inner ObjSymIter is unused and we walk the
    278  * image's dynamic symbol table by index. */
    279 static KitStatus symiter_make(KitObjFile* f, int dynamic, KitObjSymIter** out) {
    280   Heap* h;
    281   KitObjSymIter* it;
    282   if (!f || !out) return KIT_INVALID;
    283   h = f->ctx->heap;
    284   it = (KitObjSymIter*)h->alloc(h, sizeof(*it), _Alignof(KitObjSymIter));
    285   if (!it) return KIT_NOMEM;
    286   it->file = f;
    287   it->inner = NULL;
    288   it->dyn_idx = 0;
    289   it->dynamic = dynamic;
    290   if (!dynamic) {
    291     it->inner = obj_symiter_new(f->ob);
    292     if (!it->inner) {
    293       h->free(h, it, sizeof(*it));
    294       return KIT_NOMEM;
    295     }
    296   }
    297   *out = it;
    298   return KIT_OK;
    299 }
    300 
    301 KitStatus kit_obj_symiter_new(KitObjFile* f, KitObjSymIter** out) {
    302   return symiter_make(f, 0, out);
    303 }
    304 
    305 KitStatus kit_obj_dynsymiter_new(KitObjFile* f, KitObjSymIter** out) {
    306   return symiter_make(f, 1, out);
    307 }
    308 
    309 KitIterResult kit_obj_symiter_next(KitObjSymIter* it, KitObjSymInfo* out) {
    310   ObjSymEntry entry;
    311   if (!it || !out) return KIT_ITER_ERROR;
    312   if (it->dynamic) {
    313     const ObjImage* im = obj_image(it->file->ob);
    314     const ObjImageSym* s;
    315     if (it->dyn_idx >= obj_image_ndynsyms(im)) return KIT_ITER_END;
    316     s = obj_image_dynsym(im, it->dyn_idx++);
    317     out->name = pool_slice(it->file->compiler.global, s->name);
    318     out->id = KIT_OBJ_SYMBOL_NONE;
    319     out->bind = (KitSymBind)s->bind;
    320     out->kind = (KitSymKind)s->kind;
    321     out->section = s->section != OBJ_SEC_NONE ? (KitObjSection)(s->section - 1)
    322                                               : KIT_SECTION_NONE;
    323     out->value = s->value;
    324     out->size = s->size;
    325     return KIT_ITER_ITEM;
    326   }
    327   if (!obj_symiter_next(it->inner, &entry)) return KIT_ITER_END;
    328   fill_syminfo(it->file, entry.id, entry.sym, out);
    329   return KIT_ITER_ITEM;
    330 }
    331 
    332 void kit_obj_symiter_free(KitObjSymIter* it) {
    333   Heap* h;
    334   if (!it) return;
    335   if (it->inner) obj_symiter_free(it->inner);
    336   h = it->file->ctx->heap;
    337   h->free(h, it, sizeof(*it));
    338 }
    339 
    340 struct KitObjRelocIter {
    341   KitObjFile* file;
    342   u32 idx;
    343   u32 total;
    344   int dynamic; /* iterate obj_image dynamic relocs instead of section relocs */
    345 };
    346 
    347 static KitStatus reliter_make(KitObjFile* f, int dynamic,
    348                               KitObjRelocIter** out) {
    349   Heap* h;
    350   KitObjRelocIter* it;
    351   if (!f || !out) return KIT_INVALID;
    352   h = f->ctx->heap;
    353   it = (KitObjRelocIter*)h->alloc(h, sizeof(*it), _Alignof(KitObjRelocIter));
    354   if (!it) return KIT_NOMEM;
    355   it->file = f;
    356   it->idx = 0;
    357   it->dynamic = dynamic;
    358   it->total =
    359       dynamic ? obj_image_ndynrelocs(obj_image(f->ob)) : obj_reloc_total(f->ob);
    360   *out = it;
    361   return KIT_OK;
    362 }
    363 
    364 KitStatus kit_obj_reliter_new(KitObjFile* f, KitObjRelocIter** out) {
    365   return reliter_make(f, 0, out);
    366 }
    367 
    368 KitStatus kit_obj_dynreliter_new(KitObjFile* f, KitObjRelocIter** out) {
    369   return reliter_make(f, 1, out);
    370 }
    371 
    372 /* Format-specific canonical spelling of a reloc kind (e.g. "R_X86_64_PLT32",
    373  * "R_AARCH64_CALL26", "R_RISCV_CALL"), or NULL when the format has no per-arch
    374  * name table (callers fall back to the arch-neutral reloc_kind_name).
    375  *
    376  * Consulted for every ELF arch whose ObjElfArchOps carries a reloc_name table
    377  * (x86_64 / aarch64 / riscv): the kit-canonical RelocKind is lowered to its
    378  * ELF wire type via reloc_to, then named — matching binutils objdump's
    379  * spelling. The Mach-O / COFF formats have no reloc_name table yet and keep
    380  * the arch-neutral spelling. reloc_to maps unsupported kinds to wire type 0;
    381  * only R_NONE legitimately names that slot, so anything else falling through
    382  * to 0 is reported as "no per-arch name" (NULL) rather than the format's NONE
    383  * spelling. */
    384 static const char* kit_obj_reloc_kind_name(KitArchKind arch, KitObjFmt fmt,
    385                                            u32 kind) {
    386   const ObjFormatImpl* impl;
    387   const ObjElfArchOps* ops;
    388   u32 wire;
    389   if (fmt != KIT_OBJ_ELF) return NULL;
    390   impl = obj_format_lookup(fmt);
    391   if (!impl || !impl->elf_arch) return NULL;
    392   ops = impl->elf_arch(arch);
    393   if (!ops || !ops->reloc_to || !ops->reloc_name) return NULL;
    394   wire = ops->reloc_to(kind);
    395   if (wire == 0u && (RelocKind)kind != R_NONE) return NULL;
    396   return ops->reloc_name(wire);
    397 }
    398 
    399 KitIterResult kit_obj_reliter_next(KitObjRelocIter* it, KitObjReloc* out) {
    400   const Reloc* r;
    401   const ObjSym* sym;
    402   if (!it || !out) return KIT_ITER_ERROR;
    403   if (it->idx >= it->total) return KIT_ITER_END;
    404 
    405   if (it->dynamic) {
    406     const ObjImageReloc* dr =
    407         obj_image_dynreloc(obj_image(it->file->ob), it->idx++);
    408     const char* kn;
    409     out->section =
    410         dr->section ? (KitObjSection)(dr->section - 1) : KIT_SECTION_NONE;
    411     out->offset = dr->offset;
    412     out->addend = dr->addend;
    413     out->kind.arch = it->file->target.arch;
    414     out->kind.obj_fmt = it->file->fmt;
    415     out->kind.code = (uint32_t)dr->kind;
    416     kn =
    417         kit_obj_reloc_kind_name(it->file->target.arch, it->file->fmt, dr->kind);
    418     if (!kn) kn = reloc_kind_name(dr->kind);
    419     out->kind_name = kn ? slice_from_cstr(kn) : SLICE_NULL;
    420     out->sym = KIT_OBJ_SYMBOL_NONE;
    421     out->sym_name = pool_slice(it->file->compiler.global, dr->sym_name);
    422     return KIT_ITER_ITEM;
    423   }
    424 
    425   r = obj_reloc_at(it->file->ob, it->idx++);
    426   out->section =
    427       r->section_id ? (KitObjSection)(r->section_id - 1) : KIT_SECTION_NONE;
    428   out->offset = r->offset;
    429   out->addend = r->addend;
    430   out->kind.arch = it->file->target.arch;
    431   out->kind.obj_fmt = it->file->fmt;
    432   out->kind.code = (uint32_t)r->kind;
    433   {
    434     /* Prefer the format-specific canonical spelling (e.g. "R_X86_64_PLT32");
    435      * fall back to the arch-neutral diagnostic spelling ("RV_CALL"). */
    436     const char* kn =
    437         kit_obj_reloc_kind_name(it->file->target.arch, it->file->fmt, r->kind);
    438     if (!kn) kn = reloc_kind_name(r->kind);
    439     out->kind_name = kn ? slice_from_cstr(kn) : SLICE_NULL;
    440   }
    441 
    442   if (r->sym == OBJ_SYM_NONE) {
    443     out->sym = KIT_OBJ_SYMBOL_NONE;
    444     out->sym_name = SLICE_LIT("");
    445   } else {
    446     out->sym = (KitObjSymbol)r->sym;
    447     sym = obj_symbol_get(it->file->ob, r->sym);
    448     out->sym_name = (sym && sym->name)
    449                         ? pool_slice(it->file->compiler.global, sym->name)
    450                         : SLICE_LIT("");
    451   }
    452   return KIT_ITER_ITEM;
    453 }
    454 
    455 void kit_obj_reliter_free(KitObjRelocIter* it) {
    456   Heap* h;
    457   if (!it) return;
    458   h = it->file->ctx->heap;
    459   h->free(h, it, sizeof(*it));
    460 }
    461 
    462 struct KitObjGroupIter {
    463   KitObjFile* file;
    464   ObjGroupIter* inner;
    465   /* Translation scratch for the borrowed `sections` slice handed back to
    466    * the caller. Lazily grown to the largest group's nsections. */
    467   KitObjSection* secbuf;
    468   u32 seccap;
    469 };
    470 
    471 KitStatus kit_obj_groupiter_new(KitObjFile* f, KitObjGroupIter** out) {
    472   Heap* h;
    473   KitObjGroupIter* it;
    474   if (!f || !out) return KIT_INVALID;
    475   h = f->ctx->heap;
    476   it = (KitObjGroupIter*)h->alloc(h, sizeof(*it), _Alignof(KitObjGroupIter));
    477   if (!it) return KIT_NOMEM;
    478   memset(it, 0, sizeof(*it));
    479   it->file = f;
    480   it->inner = obj_groupiter_new(f->ob);
    481   if (!it->inner) {
    482     h->free(h, it, sizeof(*it));
    483     return KIT_NOMEM;
    484   }
    485   *out = it;
    486   return KIT_OK;
    487 }
    488 
    489 KitIterResult kit_obj_groupiter_next(KitObjGroupIter* it,
    490                                      KitObjGroupInfo* out) {
    491   ObjGroupEntry entry;
    492   Heap* h;
    493   u32 i;
    494   if (!it || !out) return KIT_ITER_ERROR;
    495   if (!obj_groupiter_next(it->inner, &entry)) return KIT_ITER_END;
    496   h = it->file->ctx->heap;
    497   if (entry.group->nsections > it->seccap) {
    498     KitObjSection* nb;
    499     nb = (KitObjSection*)h->alloc(h, sizeof(*nb) * entry.group->nsections,
    500                                   _Alignof(KitObjSection));
    501     if (!nb) return KIT_ITER_ERROR;
    502     if (it->secbuf) h->free(h, it->secbuf, sizeof(*it->secbuf) * it->seccap);
    503     it->secbuf = nb;
    504     it->seccap = entry.group->nsections;
    505   }
    506   for (i = 0; i < entry.group->nsections; ++i) {
    507     ObjSecId sid = entry.group->sections[i];
    508     it->secbuf[i] =
    509         (sid != OBJ_SEC_NONE) ? (KitObjSection)(sid - 1) : KIT_SECTION_NONE;
    510   }
    511   out->name = entry.group->name
    512                   ? pool_slice(it->file->compiler.global, entry.group->name)
    513                   : KIT_SLICE_NULL;
    514   out->signature = (entry.group->signature != OBJ_SYM_NONE)
    515                        ? (KitObjSymbol)entry.group->signature
    516                        : KIT_OBJ_SYMBOL_NONE;
    517   out->flags = entry.group->flags;
    518   out->nsections = entry.group->nsections;
    519   out->sections = it->secbuf;
    520   return KIT_ITER_ITEM;
    521 }
    522 
    523 void kit_obj_groupiter_free(KitObjGroupIter* it) {
    524   Heap* h;
    525   if (!it) return;
    526   h = it->file->ctx->heap;
    527   if (it->secbuf) h->free(h, it->secbuf, sizeof(*it->secbuf) * it->seccap);
    528   obj_groupiter_free(it->inner);
    529   h->free(h, it, sizeof(*it));
    530 }
    531 
    532 /* Accessor for disasm/jit to access the underlying ObjBuilder when both
    533  * are inside libkit. Internal name kept stable for existing callers
    534  * (src/link/link_jit.c, src/api/disasm.c). */
    535 ObjBuilder* kit_objfile_builder(const KitObjFile* f) {
    536   return f ? f->ob : NULL;
    537 }
    538 
    539 /* Public alias of kit_objfile_builder. Promoted to the public API so the
    540  * driver (and other libkit consumers) can take an opened object and feed
    541  * it into kit_obj_builder_emit for a byte-equivalent roundtrip without
    542  * re-implementing the read-then-replay loop. */
    543 KitObjBuilder* kit_obj_file_builder(const KitObjFile* f) {
    544   return kit_objfile_builder(f);
    545 }
    546 
    547 /* Allocate an empty KitObjFile wrapping a private Compiler and a fresh
    548  * ObjBuilder. Used by the JIT debug-view builder (src/link/link_jit.c)
    549  * to assemble a synthetic object file from merged input debug sections.
    550  * The handle is freed via kit_objfile_internal_free below — the public
    551  * kit_obj_free path is keyed off obj_read_bytes, so the view path uses
    552  * its own teardown that does not depend on the cached section data
    553  * tables. */
    554 KitObjFile* kit_objfile_internal_new(const KitContext* ctx,
    555                                      KitTargetSpec target, KitObjFmt fmt) {
    556   Heap* h;
    557   KitObjFile* f;
    558   if (!ctx || !ctx->heap) return NULL;
    559   h = ctx->heap;
    560   f = (KitObjFile*)h->alloc(h, sizeof(*f), _Alignof(KitObjFile));
    561   if (!f) return NULL;
    562   memset(f, 0, sizeof(*f));
    563   f->ctx = ctx;
    564   f->fmt = fmt;
    565   f->target = target;
    566   {
    567     KitTargetOptions topts;
    568     KitStatus st;
    569     memset(&topts, 0, sizeof topts);
    570     topts.spec = target;
    571     st = kit_target_new(ctx, &topts, &f->resolved_target);
    572     if (st != KIT_OK) {
    573       h->free(h, f, sizeof(*f));
    574       return NULL;
    575     }
    576     st = compiler_init(&f->compiler, f->resolved_target, ctx);
    577     if (st != KIT_OK) {
    578       kit_target_free(f->resolved_target);
    579       h->free(h, f, sizeof(*f));
    580       return NULL;
    581     }
    582   }
    583   {
    584     PanicFrame panic;
    585     compiler_panic_push(&f->compiler, &panic);
    586     if (setjmp(panic.env)) {
    587       compiler_run_cleanups(&f->compiler);
    588       compiler_panic_pop(&f->compiler, &panic);
    589       compiler_fini(&f->compiler);
    590       kit_target_free(f->resolved_target);
    591       h->free(h, f, sizeof(*f));
    592       return NULL;
    593     }
    594     f->ob = obj_new(&f->compiler);
    595     compiler_panic_pop(&f->compiler, &panic);
    596   }
    597   if (!f->ob) {
    598     compiler_fini(&f->compiler);
    599     kit_target_free(f->resolved_target);
    600     h->free(h, f, sizeof(*f));
    601     return NULL;
    602   }
    603   return f;
    604 }
    605 
    606 void kit_objfile_internal_free(KitObjFile* f) {
    607   /* Same teardown contract as kit_obj_free: caller may have cached
    608    * section data, so we route through the same path. */
    609   kit_obj_free(f);
    610 }
    611 
    612 /* ============================================================
    613  * Linked-image view
    614  * ============================================================ */
    615 
    616 KitObjKind kit_obj_kind(const KitObjFile* f) {
    617   const ObjImage* im;
    618   if (!f) return KIT_OBJ_KIND_REL;
    619   im = obj_image(f->ob);
    620   if (!im) return KIT_OBJ_KIND_REL;
    621   switch (obj_image_kind(im)) {
    622     case OBJ_KIND_EXEC:
    623       return KIT_OBJ_KIND_EXEC;
    624     case OBJ_KIND_DYN:
    625       return KIT_OBJ_KIND_DYN;
    626     case OBJ_KIND_CORE:
    627       return KIT_OBJ_KIND_CORE;
    628     case OBJ_KIND_REL:
    629     default:
    630       return KIT_OBJ_KIND_REL;
    631   }
    632 }
    633 
    634 KitStatus kit_obj_image_info(const KitObjFile* f, KitObjImageInfo* out) {
    635   const ObjImage* im;
    636   if (!f || !out) return KIT_INVALID;
    637   im = obj_image(f->ob);
    638   if (!im) return KIT_NOT_FOUND;
    639   out->entry = obj_image_entry(im);
    640   out->image_base = obj_image_base(im);
    641   out->interp = pool_slice(f->compiler.global, obj_image_interp(im));
    642   out->soname = pool_slice(f->compiler.global, obj_image_soname(im));
    643   return KIT_OK;
    644 }
    645 
    646 struct KitObjSegIter {
    647   KitObjFile* file;
    648   u32 idx;
    649 };
    650 
    651 KitStatus kit_obj_segiter_new(KitObjFile* f, KitObjSegIter** out) {
    652   Heap* h;
    653   KitObjSegIter* it;
    654   if (!f || !out) return KIT_INVALID;
    655   h = f->ctx->heap;
    656   it = (KitObjSegIter*)h->alloc(h, sizeof(*it), _Alignof(KitObjSegIter));
    657   if (!it) return KIT_NOMEM;
    658   it->file = f;
    659   it->idx = 0;
    660   *out = it;
    661   return KIT_OK;
    662 }
    663 
    664 KitIterResult kit_obj_segiter_next(KitObjSegIter* it, KitObjSegInfo* out) {
    665   const ObjImage* im;
    666   const ObjSegment* s;
    667   if (!it || !out) return KIT_ITER_ERROR;
    668   im = obj_image(it->file->ob);
    669   if (it->idx >= obj_image_nsegments(im)) return KIT_ITER_END;
    670   s = obj_image_segment(im, it->idx++);
    671   out->name = pool_slice(it->file->compiler.global, s->name);
    672   out->vaddr = s->vaddr;
    673   out->vsize = s->vsize;
    674   out->file_off = s->file_off;
    675   out->file_size = s->file_size;
    676   out->perms = s->perms; /* OBJ_SEG_* and KIT_SEG_* share bit values */
    677   out->align = s->align;
    678   return KIT_ITER_ITEM;
    679 }
    680 
    681 void kit_obj_segiter_free(KitObjSegIter* it) {
    682   Heap* h;
    683   if (!it) return;
    684   h = it->file->ctx->heap;
    685   h->free(h, it, sizeof(*it));
    686 }
    687 
    688 struct KitObjDepIter {
    689   KitObjFile* file;
    690   u32 idx;
    691   KitSlice* import_buf; /* scratch for the current dep's import names */
    692   u32 import_cap;
    693 };
    694 
    695 KitStatus kit_obj_depiter_new(KitObjFile* f, KitObjDepIter** out) {
    696   Heap* h;
    697   KitObjDepIter* it;
    698   if (!f || !out) return KIT_INVALID;
    699   h = f->ctx->heap;
    700   it = (KitObjDepIter*)h->alloc(h, sizeof(*it), _Alignof(KitObjDepIter));
    701   if (!it) return KIT_NOMEM;
    702   it->file = f;
    703   it->idx = 0;
    704   it->import_buf = NULL;
    705   it->import_cap = 0;
    706   *out = it;
    707   return KIT_OK;
    708 }
    709 
    710 KitIterResult kit_obj_depiter_next(KitObjDepIter* it, KitObjDepInfo* out) {
    711   const ObjImage* im;
    712   const ObjImageDep* d;
    713   Heap* h;
    714   u32 i;
    715   if (!it || !out) return KIT_ITER_ERROR;
    716   im = obj_image(it->file->ob);
    717   if (it->idx >= obj_image_ndeps(im)) return KIT_ITER_END;
    718   d = obj_image_dep(im, it->idx++);
    719   out->name = pool_slice(it->file->compiler.global, d->name);
    720   out->imports = NULL;
    721   out->nimports = d->nimports;
    722   if (d->nimports) {
    723     h = it->file->ctx->heap;
    724     if (it->import_cap < d->nimports) {
    725       if (VEC_GROW(h, it->import_buf, it->import_cap, d->nimports))
    726         return KIT_ITER_ERROR;
    727     }
    728     for (i = 0; i < d->nimports; ++i)
    729       it->import_buf[i] = pool_slice(it->file->compiler.global, d->imports[i]);
    730     out->imports = it->import_buf;
    731   }
    732   return KIT_ITER_ITEM;
    733 }
    734 
    735 void kit_obj_depiter_free(KitObjDepIter* it) {
    736   Heap* h;
    737   if (!it) return;
    738   h = it->file->ctx->heap;
    739   if (it->import_buf)
    740     h->free(h, it->import_buf, sizeof(*it->import_buf) * it->import_cap);
    741   h->free(h, it, sizeof(*it));
    742 }
    743 
    744 struct KitObjRpathIter {
    745   KitObjFile* file;
    746   u32 idx;
    747 };
    748 
    749 KitStatus kit_obj_rpathiter_new(KitObjFile* f, KitObjRpathIter** out) {
    750   Heap* h;
    751   KitObjRpathIter* it;
    752   if (!f || !out) return KIT_INVALID;
    753   h = f->ctx->heap;
    754   it = (KitObjRpathIter*)h->alloc(h, sizeof(*it), _Alignof(KitObjRpathIter));
    755   if (!it) return KIT_NOMEM;
    756   it->file = f;
    757   it->idx = 0;
    758   *out = it;
    759   return KIT_OK;
    760 }
    761 
    762 KitIterResult kit_obj_rpathiter_next(KitObjRpathIter* it, KitSlice* out) {
    763   const ObjImage* im;
    764   if (!it || !out) return KIT_ITER_ERROR;
    765   im = obj_image(it->file->ob);
    766   if (it->idx >= obj_image_nrpaths(im)) return KIT_ITER_END;
    767   *out = pool_slice(it->file->compiler.global, obj_image_rpath(im, it->idx++));
    768   return KIT_ITER_ITEM;
    769 }
    770 
    771 void kit_obj_rpathiter_free(KitObjRpathIter* it) {
    772   Heap* h;
    773   if (!it) return;
    774   h = it->file->ctx->heap;
    775   h->free(h, it, sizeof(*it));
    776 }
    777 
    778 struct KitObjImageRawIter {
    779   KitObjFile* file;
    780   u32 idx;
    781 };
    782 
    783 KitStatus kit_obj_image_rawiter_new(KitObjFile* f, KitObjImageRawIter** out) {
    784   Heap* h;
    785   KitObjImageRawIter* it;
    786   if (!f || !out) return KIT_INVALID;
    787   if (!obj_image(f->ob)) return KIT_NOT_FOUND; /* relocatable: no image */
    788   h = f->ctx->heap;
    789   it = (KitObjImageRawIter*)h->alloc(h, sizeof(*it),
    790                                      _Alignof(KitObjImageRawIter));
    791   if (!it) return KIT_NOMEM;
    792   it->file = f;
    793   it->idx = 0;
    794   *out = it;
    795   return KIT_OK;
    796 }
    797 
    798 KitIterResult kit_obj_image_rawiter_next(KitObjImageRawIter* it,
    799                                          KitObjImageRaw* out) {
    800   const ObjImage* im;
    801   const ObjImageRaw* r;
    802   if (!it || !out) return KIT_ITER_ERROR;
    803   im = obj_image(it->file->ob);
    804   if (it->idx >= obj_image_nraws(im)) return KIT_ITER_END;
    805   r = obj_image_raw(im, it->idx++);
    806   out->tag = r->tag;
    807   out->value = r->value;
    808   out->extra = r->extra;
    809   return KIT_ITER_ITEM;
    810 }
    811 
    812 void kit_obj_image_rawiter_free(KitObjImageRawIter* it) {
    813   Heap* h;
    814   if (!it) return;
    815   h = it->file->ctx->heap;
    816   h->free(h, it, sizeof(*it));
    817 }