kit

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

commit 13d1a28d0b81cc43eb901962ef049aa68b8b2569
parent 03096a7125d3ed99ee15e2b6b39b6198c5f4cc59
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Thu, 14 May 2026 20:27:05 -0700

Improve dbg JIT expression REPL

Diffstat:
Mdriver/dbg.c | 1639++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Mdriver/driver.h | 107++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Mdriver/env.c | 738+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Mdriver/inputs.c | 98++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Mdriver/inputs.h | 36+++++++++++++++++-------------------
Minclude/cfree.h | 593++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/api/cg.c | 2501++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Msrc/arch/aa64/emit.c | 159++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Msrc/arch/rv64/emit.c | 79+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Msrc/arch/rv64/internal.h | 97+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Msrc/arch/x64/emit.c | 256+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Msrc/arch/x64/internal.h | 131++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/debug/debug_emit.c | 578++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msrc/debug/dwarf_die.c | 314++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msrc/debug/dwarf_internal.h | 176++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/debug/dwarf_query.c | 436+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Msrc/link/link_jit.c | 854++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
17 files changed, 5245 insertions(+), 3547 deletions(-)

diff --git a/driver/dbg.c b/driver/dbg.c @@ -39,23 +39,23 @@ * ============================================================ */ typedef struct DbgOpts { - DriverEnv* env; + DriverEnv *env; size_t argv_bound; int opt_level; int debug_info; - const char* entry; + const char *entry; DriverCflags cf; DriverInputs inputs; - char** prog_argv; + char **prog_argv; uint32_t prog_argc; } DbgOpts; static void dbg_usage(void) { driver_errf(DBG_TOOL, "%s", - "usage: cfree dbg [options] input.c... [-- arg...]\n" + "usage: cfree dbg [options] input.{c,toy,s}... [-- arg...]\n" " cfree dbg --help for full option reference"); } @@ -65,7 +65,7 @@ void driver_help_dbg(void) { "cfree dbg — interactive JIT debugger\n" "\n" "USAGE\n" - " cfree dbg [options] input.c ... [-- prog-arg ...]\n" + " cfree dbg [options] input.{c,toy,s} ... [-- prog-arg ...]\n" "\n" "DESCRIPTION\n" " Mirrors `cfree run` for compile flags and argv shape, but instead\n" @@ -96,6 +96,8 @@ void driver_help_dbg(void) { " n, next step to next source line (over calls)\n" " finish run until current frame returns\n" " jit [LANG|NAME] { ... } compile and append a frontend snippet\n" + " edit [LANG|NAME] edit and append a frontend snippet\n" + " expr C_EXPR | expr { ... } compile and call a C thunk\n" " call SYMBOL [INT_OR_ADDR...] call function, returns uint64_t\n" " jump ADDR set PC to ADDR (no resume)\n" " bt, backtrace print stack trace with arguments\n" @@ -128,7 +130,7 @@ void driver_help_dbg(void) { "usage\n"); } -static int dbg_alloc_arrays(DbgOpts* o, int argc) { +static int dbg_alloc_arrays(DbgOpts *o, int argc) { size_t bound = (size_t)argc; o->argv_bound = bound; o->prog_argv = driver_alloc_zeroed(o->env, bound * sizeof(*o->prog_argv)); @@ -136,7 +138,8 @@ static int dbg_alloc_arrays(DbgOpts* o, int argc) { driver_errf(DBG_TOOL, "out of memory"); return 1; } - if (driver_inputs_init(&o->inputs, o->env, DBG_TOOL, argc) != 0) return 1; + if (driver_inputs_init(&o->inputs, o->env, DBG_TOOL, argc) != 0) + return 1; if (driver_cflags_init(&o->cf, o->env, argc) != 0) { driver_errf(DBG_TOOL, "out of memory"); return 1; @@ -144,13 +147,14 @@ static int dbg_alloc_arrays(DbgOpts* o, int argc) { return 0; } -static int dbg_parse(int argc, char** argv, DbgOpts* o) { +static int dbg_parse(int argc, char **argv, DbgOpts *o) { int i; int after_dash_dash = 0; - if (dbg_alloc_arrays(o, argc) != 0) return 1; + if (dbg_alloc_arrays(o, argc) != 0) + return 1; for (i = 1; i < argc; ++i) { - const char* a = argv[i]; + const char *a = argv[i]; if (after_dash_dash) { o->prog_argv[o->prog_argc++] = argv[i]; @@ -164,8 +168,10 @@ static int dbg_parse(int argc, char** argv, DbgOpts* o) { { int r = driver_cflags_try_consume(&o->cf, o->env, DBG_TOOL, argc, argv, &i); - if (r < 0) return 1; - if (r > 0) continue; + if (r < 0) + return 1; + if (r > 0) + continue; } if (driver_streq(a, "-g")) { @@ -201,10 +207,10 @@ static int dbg_parse(int argc, char** argv, DbgOpts* o) { { int r = driver_inputs_classify(&o->inputs, a); - if (r < 0) return 1; + if (r < 0) + return 1; if (r == 0) { - driver_errf(DBG_TOOL, "input does not have a recognized suffix: %s", - a); + driver_errf(DBG_TOOL, "input does not have a recognized suffix: %s", a); return 1; } } @@ -215,7 +221,8 @@ static int dbg_parse(int argc, char** argv, DbgOpts* o) { dbg_usage(); return 1; } - if (!o->entry) o->entry = "main"; + if (!o->entry) + o->entry = "main"; if (!o->debug_info) { /* Without -g there are no source lines or variable locations to * read at runtime; force it on so `b file:line` and `p name` @@ -226,7 +233,7 @@ static int dbg_parse(int argc, char** argv, DbgOpts* o) { return 0; } -static void dbg_options_release(DbgOpts* o) { +static void dbg_options_release(DbgOpts *o) { size_t bound = o->argv_bound; driver_inputs_release(&o->inputs); driver_cflags_fini(&o->cf, o->env); @@ -236,8 +243,8 @@ static void dbg_options_release(DbgOpts* o) { /* Compile every C source through a pipeline owned by the caller and JIT-link * the result. Pipeline ownership stays with the caller so DWARF lookups * during the REPL session can run against the live pipeline compiler. */ -static int dbg_compile_and_jit(DbgOpts* o, CfreePipeline* pipe, - CfreeJit** out_jit) { +static int dbg_compile_and_jit(DbgOpts *o, CfreePipeline *pipe, + CfreeJit **out_jit) { CfreeCompileOptions copts; { CfreeCompileOptions z = {0}; @@ -250,7 +257,7 @@ static int dbg_compile_and_jit(DbgOpts* o, CfreePipeline* pipe, driver_dlsym_resolver, NULL, out_jit); } -static void dbg_fill_compile_options(DbgOpts* o, CfreeCompileOptions* copts) { +static void dbg_fill_compile_options(DbgOpts *o, CfreeCompileOptions *copts) { { CfreeCompileOptions z = {0}; *copts = z; @@ -278,7 +285,7 @@ typedef struct Bp { int id; /* user-facing handle, 1.. */ int enabled; BpKind kind; - char* spec; /* heap-owned NUL-terminated copy */ + char *spec; /* heap-owned NUL-terminated copy */ size_t spec_size; uint64_t addr; uint64_t skip_count; /* silent skips before the first stop */ @@ -291,21 +298,24 @@ typedef struct Bp { * ============================================================ */ typedef struct DbgState { - DriverEnv* env; - CfreePipeline* pipe; + DriverEnv *env; + CfreePipeline *pipe; CfreeCompileOptions copts; - CfreeJit* jit; - CfreeJitSession* session; - const CfreeObjFile* view; - CfreeDebugInfo* dwarf; - void* entry_addr; + CfreeJit *jit; + CfreeJitSession *session; + const CfreeObjFile *view; + CfreeDebugInfo *dwarf; + void *entry_addr; + CfreeLanguage default_jit_lang; + const char *default_jit_name; int prog_argc; - char** prog_argv; + char **prog_argv; - Bp* bps; + Bp *bps; uint32_t nbps; uint32_t bps_cap; int next_bp_id; + uint64_t expr_counter; int has_stop; CfreeStopInfo last_stop; @@ -315,9 +325,10 @@ typedef struct DbgState { /* SIGINT trampoline. The handler in env.c calls our cb with this state; * we forward into the session. cfree_jit_session_interrupt is documented * async-signal-safe. */ -static void dbg_on_sigint(void* user) { - DbgState* s = (DbgState*)user; - if (s && s->session) cfree_jit_session_interrupt(s->session); +static void dbg_on_sigint(void *user) { + DbgState *s = (DbgState *)user; + if (s && s->session) + cfree_jit_session_interrupt(s->session); } /* PC-space translation between the JIT runtime address space (where @@ -328,11 +339,11 @@ static void dbg_on_sigint(void* user) { * boundary. Fallback is pass-through so out-of-image PCs (e.g. * stops inside libc on a future multi-input setup) don't return 0 * and silently degrade lookups. */ -static uint64_t dbg_pc_rt_to_img(DbgState* s, uint64_t rt) { +static uint64_t dbg_pc_rt_to_img(DbgState *s, uint64_t rt) { uint64_t v = cfree_jit_runtime_to_image(s->jit, rt); return v ? v : rt; } -static uint64_t dbg_pc_img_to_rt(DbgState* s, uint64_t img) { +static uint64_t dbg_pc_img_to_rt(DbgState *s, uint64_t img) { uint64_t v = cfree_jit_image_to_runtime(s->jit, img); return v ? v : img; } @@ -341,8 +352,8 @@ static uint64_t dbg_pc_img_to_rt(DbgState* s, uint64_t img) { * frame->pc (subprogram_at, param_iter_new, vars_at_new, unwind_step). * The register snapshot and CFA stay in their original (runtime) form * because dw_eval_expr / loc_read interpret them as live host values. */ -static CfreeUnwindFrame dbg_frame_for_dwarf(DbgState* s, - const CfreeUnwindFrame* rt) { +static CfreeUnwindFrame dbg_frame_for_dwarf(DbgState *s, + const CfreeUnwindFrame *rt) { CfreeUnwindFrame out = *rt; out.pc = dbg_pc_rt_to_img(s, rt->pc); return out; @@ -355,8 +366,9 @@ static CfreeUnwindFrame dbg_frame_for_dwarf(DbgState* s, * .debug_info; DLOC_REG / DLOC_FRAME_OFS / DLOC_EXPR derive their * effective address from live register state or are evaluated against * the frame, both of which are already in runtime space. */ -static void dbg_translate_loc(DbgState* s, CfreeDwarfVarLoc* loc) { - if (!loc) return; +static void dbg_translate_loc(DbgState *s, CfreeDwarfVarLoc *loc) { + if (!loc) + return; if (loc->kind == CFREE_DLOC_GLOBAL) loc->v.global = dbg_pc_img_to_rt(s, loc->v.global); } @@ -372,39 +384,49 @@ static int dbg_isspace(int c) { return c == ' ' || c == '\t' || c == '\r' || c == '\n'; } static int dbg_isdigit(int c) { return c >= '0' && c <= '9'; } +static int dbg_isalpha_(int c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'; +} +static int dbg_isalnum_(int c) { return dbg_isalpha_(c) || dbg_isdigit(c); } static int dbg_isxdigit(int c) { return dbg_isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); } static int dbg_xval(int c) { - if (dbg_isdigit(c)) return c - '0'; - if (c >= 'a' && c <= 'f') return c - 'a' + 10; + if (dbg_isdigit(c)) + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; return c - 'A' + 10; } -static char* dbg_dup(DriverEnv* env, const char* s, size_t n, - size_t* size_out) { - char* p = driver_alloc(env, n + 1); - if (!p) return NULL; +static char *dbg_dup(DriverEnv *env, const char *s, size_t n, + size_t *size_out) { + char *p = driver_alloc(env, n + 1); + if (!p) + return NULL; driver_memcpy(p, s, n); p[n] = '\0'; - if (size_out) *size_out = n + 1; + if (size_out) + *size_out = n + 1; return p; } /* Parse a 0x-prefixed hex literal or a decimal literal into *out. Returns * the number of characters consumed, or 0 on failure. */ -static size_t dbg_parse_uint(const char* s, uint64_t* out) { +static size_t dbg_parse_uint(const char *s, uint64_t *out) { size_t i = 0; uint64_t v = 0; if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { i = 2; - if (!dbg_isxdigit((unsigned char)s[i])) return 0; + if (!dbg_isxdigit((unsigned char)s[i])) + return 0; for (; dbg_isxdigit((unsigned char)s[i]); ++i) { v = (v << 4) | (uint64_t)dbg_xval((unsigned char)s[i]); } } else { - if (!dbg_isdigit((unsigned char)s[0])) return 0; + if (!dbg_isdigit((unsigned char)s[0])) + return 0; for (; dbg_isdigit((unsigned char)s[i]); ++i) { v = v * 10 + (uint64_t)(s[i] - '0'); } @@ -417,11 +439,12 @@ static size_t dbg_parse_uint(const char* s, uint64_t* out) { * Breakpoint table operations * ============================================================ */ -static Bp* dbg_bp_grow(DbgState* s) { +static Bp *dbg_bp_grow(DbgState *s) { uint32_t nc; size_t old_size, new_size; - Bp* nb; - if (s->nbps < s->bps_cap) return &s->bps[s->nbps]; + Bp *nb; + if (s->nbps < s->bps_cap) + return &s->bps[s->nbps]; nc = s->bps_cap ? s->bps_cap * 2 : 8; old_size = (size_t)s->bps_cap * sizeof(Bp); @@ -434,25 +457,27 @@ static Bp* dbg_bp_grow(DbgState* s) { } /* Zero the freshly grown tail so future driver_free walks it cleanly. */ { - char* z = (char*)nb + old_size; + char *z = (char *)nb + old_size; size_t n = new_size - old_size; size_t j; - for (j = 0; j < n; ++j) z[j] = 0; + for (j = 0; j < n; ++j) + z[j] = 0; } s->bps = nb; s->bps_cap = nc; return &s->bps[s->nbps]; } -static Bp* dbg_bp_find(DbgState* s, int id) { +static Bp *dbg_bp_find(DbgState *s, int id) { uint32_t i; for (i = 0; i < s->nbps; ++i) { - if (s->bps[i].id == id) return &s->bps[i]; + if (s->bps[i].id == id) + return &s->bps[i]; } return NULL; } -static void dbg_bp_release(DbgState* s, Bp* b) { +static void dbg_bp_release(DbgState *s, Bp *b) { if (b->session_id) { cfree_jit_session_breakpoint_clear(s->session, b->session_id); b->session_id = 0; @@ -464,7 +489,7 @@ static void dbg_bp_release(DbgState* s, Bp* b) { } } -static int dbg_bp_remove(DbgState* s, int id) { +static int dbg_bp_remove(DbgState *s, int id) { uint32_t i; for (i = 0; i < s->nbps; ++i) { if (s->bps[i].id == id) { @@ -472,7 +497,8 @@ static int dbg_bp_remove(DbgState* s, int id) { /* Shift tail down to keep the array dense; ids stay stable. */ { uint32_t j; - for (j = i + 1; j < s->nbps; ++j) s->bps[j - 1] = s->bps[j]; + for (j = i + 1; j < s->nbps; ++j) + s->bps[j - 1] = s->bps[j]; } s->nbps--; { @@ -485,9 +511,10 @@ static int dbg_bp_remove(DbgState* s, int id) { return 1; } -static void dbg_bps_release_all(DbgState* s) { +static void dbg_bps_release_all(DbgState *s) { uint32_t i; - for (i = 0; i < s->nbps; ++i) dbg_bp_release(s, &s->bps[i]); + for (i = 0; i < s->nbps; ++i) + dbg_bp_release(s, &s->bps[i]); if (s->bps) { driver_free(s->env, s->bps, (size_t)s->bps_cap * sizeof(Bp)); s->bps = NULL; @@ -509,16 +536,16 @@ static void dbg_bps_release_all(DbgState* s) { * Returns 0 on success, 1 on parse / resolution failure (already * reported via driver_errf). */ -static int dbg_resolve_loc(DbgState* s, const char* spec, BpKind* kind_out, - uint64_t* addr_out) { +static int dbg_resolve_loc(DbgState *s, const char *spec, BpKind *kind_out, + uint64_t *addr_out) { /* file:line — uniquely identifiable by a colon NOT preceded by + and * followed by digits. We require the suffix after ':' to be all * digits so we don't confuse, say, hypothetical `func:42` (which * isn't a thing in C). */ - const char* colon = driver_strchr(spec, ':'); + const char *colon = driver_strchr(spec, ':'); if (colon && dbg_isdigit((unsigned char)colon[1])) { size_t file_n = (size_t)(colon - spec); - char* file; + char *file; uint64_t line64; size_t used; size_t file_size; @@ -564,16 +591,16 @@ static int dbg_resolve_loc(DbgState* s, const char* spec, BpKind* kind_out, uint32_t k; cfree_dwarf_line_to_addr_all(s->dwarf, file, (uint32_t)line64, cands, 8u, &n); - driver_errf(DBG_TOOL, "ambiguous: %s:%u matches %u files", - file, (uint32_t)line64, (unsigned)n); + driver_errf(DBG_TOOL, "ambiguous: %s:%u matches %u files", file, + (uint32_t)line64, (unsigned)n); for (k = 0; k < n && k < 8u; ++k) { driver_errf(DBG_TOOL, " %s (0x%llx)", cands[k].file, (unsigned long long)cands[k].pc); } - if (n > 8u) driver_errf(DBG_TOOL, " ... and %u more", n - 8u); - driver_errf(DBG_TOOL, - "use a longer path suffix (e.g. b dir/%s:%u)", file, - (uint32_t)line64); + if (n > 8u) + driver_errf(DBG_TOOL, " ... and %u more", n - 8u); + driver_errf(DBG_TOOL, "use a longer path suffix (e.g. b dir/%s:%u)", + file, (uint32_t)line64); driver_free(s->env, file, file_size); return 1; } @@ -605,11 +632,11 @@ static int dbg_resolve_loc(DbgState* s, const char* spec, BpKind* kind_out, /* sym[+off] */ { - const char* plus = driver_strchr(spec, '+'); + const char *plus = driver_strchr(spec, '+'); size_t name_n = plus ? (size_t)(plus - spec) : driver_strlen(spec); - char* name; + char *name; size_t name_size; - void* resolved; + void *resolved; uint64_t off = 0; if (name_n == 0) { @@ -643,7 +670,7 @@ static int dbg_resolve_loc(DbgState* s, const char* spec, BpKind* kind_out, * runs. */ { union { - void* p; + void *p; uint64_t u; } cv; cv.p = resolved; @@ -657,10 +684,10 @@ static int dbg_resolve_loc(DbgState* s, const char* spec, BpKind* kind_out, * Stop rendering * ============================================================ */ -static void dbg_print_pc(DbgState* s, uint64_t pc) { - const char* sym = NULL; +static void dbg_print_pc(DbgState *s, uint64_t pc) { + const char *sym = NULL; uint64_t off = 0; - const char* file = NULL; + const char *file = NULL; uint32_t line = 0; uint32_t col = 0; @@ -676,42 +703,43 @@ static void dbg_print_pc(DbgState* s, uint64_t pc) { &col) == 0 && file) { driver_printf(" at %s:%u", file, line); - if (col) driver_printf(":%u", col); + if (col) + driver_printf(":%u", col); } } -static void dbg_render_stop(DbgState* s, const CfreeStopInfo* st) { +static void dbg_render_stop(DbgState *s, const CfreeStopInfo *st) { switch (st->kind) { - case CFREE_STOP_BREAKPOINT: { - Bp* b = NULL; - uint32_t i; - for (i = 0; i < s->nbps; ++i) { - if (s->bps[i].session_id == st->bp_id) { - b = &s->bps[i]; - break; - } + case CFREE_STOP_BREAKPOINT: { + Bp *b = NULL; + uint32_t i; + for (i = 0; i < s->nbps; ++i) { + if (s->bps[i].session_id == st->bp_id) { + b = &s->bps[i]; + break; } - if (b) - driver_printf("Breakpoint %d (%s) hit at ", b->id, b->spec); - else - driver_printf("Breakpoint hit at "); - dbg_print_pc(s, st->regs.pc); - driver_printf("\n"); - break; } - case CFREE_STOP_SIGNAL: - driver_printf("Stopped on signal %d at ", st->signal); - dbg_print_pc(s, st->regs.pc); - driver_printf("\n"); - break; - case CFREE_STOP_INTERRUPT: - driver_printf("Interrupted at "); - dbg_print_pc(s, st->regs.pc); - driver_printf("\n"); - break; - case CFREE_STOP_EXIT: - driver_printf("Program exited with code %d\n", st->exit_code); - break; + if (b) + driver_printf("Breakpoint %d (%s) hit at ", b->id, b->spec); + else + driver_printf("Breakpoint hit at "); + dbg_print_pc(s, st->regs.pc); + driver_printf("\n"); + break; + } + case CFREE_STOP_SIGNAL: + driver_printf("Stopped on signal %d at ", st->signal); + dbg_print_pc(s, st->regs.pc); + driver_printf("\n"); + break; + case CFREE_STOP_INTERRUPT: + driver_printf("Interrupted at "); + dbg_print_pc(s, st->regs.pc); + driver_printf("\n"); + break; + case CFREE_STOP_EXIT: + driver_printf("Program exited with code %d\n", st->exit_code); + break; } } @@ -732,7 +760,7 @@ typedef enum DbgRunMode { RUN_STEP_OUT, /* finish — _resume(step_out) */ } DbgRunMode; -static int dbg_drive(DbgState* s, DbgRunMode mode) { +static int dbg_drive(DbgState *s, DbgRunMode mode) { int rc; if (mode == RUN_FRESH && s->has_stop) { @@ -755,23 +783,23 @@ static int dbg_drive(DbgState* s, DbgRunMode mode) { } else { CfreeResumeMode rm = CFREE_RESUME_CONTINUE; switch (mode) { - case RUN_STEP_INSN: - rm = CFREE_RESUME_STEP_INSN; - break; - case RUN_STEP_LINE: - rm = CFREE_RESUME_STEP_LINE; - break; - case RUN_NEXT_LINE: - rm = CFREE_RESUME_NEXT_LINE; - break; - case RUN_STEP_OUT: - rm = CFREE_RESUME_STEP_OUT; - break; - case RUN_CONTINUE: - rm = CFREE_RESUME_CONTINUE; - break; - case RUN_FRESH: - break; /* unreachable */ + case RUN_STEP_INSN: + rm = CFREE_RESUME_STEP_INSN; + break; + case RUN_STEP_LINE: + rm = CFREE_RESUME_STEP_LINE; + break; + case RUN_NEXT_LINE: + rm = CFREE_RESUME_NEXT_LINE; + break; + case RUN_STEP_OUT: + rm = CFREE_RESUME_STEP_OUT; + break; + case RUN_CONTINUE: + rm = CFREE_RESUME_CONTINUE; + break; + case RUN_FRESH: + break; /* unreachable */ } rc = cfree_jit_session_resume(s->session, rm, &s->last_stop); } @@ -788,20 +816,21 @@ static int dbg_drive(DbgState* s, DbgRunMode mode) { s->has_stop = 1; dbg_render_stop(s, &s->last_stop); - if (s->last_stop.kind == CFREE_STOP_EXIT) s->has_stop = 0; + if (s->last_stop.kind == CFREE_STOP_EXIT) + s->has_stop = 0; return 0; } /* Forward declarations: backtrace renders parameter values via the * type-aware printer defined below. */ -static void dbg_print_value(DbgState*, const CfreeDwarfType*, const uint8_t*, +static void dbg_print_value(DbgState *, const CfreeDwarfType *, const uint8_t *, size_t got, int depth); -static int dbg_read_value(DbgState*, const CfreeDwarfVarLoc*, - const CfreeUnwindFrame*, uint8_t* stack_buf, - size_t stack_cap, uint8_t** buf_out, - size_t* alloc_out, size_t* got_out); -static void dbg_release_value_buf(DbgState*, uint8_t* buf, size_t alloc); -static char* dbg_take_word(char* line, char** word_out); +static int dbg_read_value(DbgState *, const CfreeDwarfVarLoc *, + const CfreeUnwindFrame *, uint8_t *stack_buf, + size_t stack_cap, uint8_t **buf_out, + size_t *alloc_out, size_t *got_out); +static void dbg_release_value_buf(DbgState *, uint8_t *buf, size_t alloc); +static char *dbg_take_word(char *line, char **word_out); /* ============================================================ * Backtrace @@ -811,7 +840,7 @@ static char* dbg_take_word(char* line, char** word_out); * Parameter rendering uses cfree_dwarf_param_iter_* against the frame's * PC and the unwound register snapshot. Inlined frames are flagged. */ -static void dbg_cmd_bt(DbgState* s) { +static void dbg_cmd_bt(DbgState *s) { CfreeUnwindFrame frame; int level = 0; @@ -835,7 +864,7 @@ static void dbg_cmd_bt(DbgState* s) { driver_printf("0x%llx", (unsigned long long)frame.pc); { - const char* sym = NULL; + const char *sym = NULL; uint64_t off = 0; if (cfree_jit_addr_to_sym(s->jit, frame.pc, &sym, &off) == 0 && sym) { if (off) @@ -848,7 +877,7 @@ static void dbg_cmd_bt(DbgState* s) { img_frame = dbg_frame_for_dwarf(s, &frame); have_sp = (cfree_dwarf_subprogram_at(s->dwarf, img_frame.pc, &sp) == 0); if (have_sp && sp.name) { - CfreeDwarfParamIter* it; + CfreeDwarfParamIter *it; CfreeDwarfVar p; int first = 1; driver_printf(" in %s%s (", sp.name, sp.inlined ? " [inlined]" : ""); @@ -856,10 +885,11 @@ static void dbg_cmd_bt(DbgState* s) { if (it) { while (cfree_dwarf_param_iter_next(it, &p)) { uint8_t stack_buf[64]; - uint8_t* buf; + uint8_t *buf; size_t alloc; size_t got; - if (!first) driver_printf(", "); + if (!first) + driver_printf(", "); driver_printf("%s=", p.name ? p.name : "?"); dbg_translate_loc(s, &p.loc); if (dbg_read_value(s, &p.loc, &frame, stack_buf, sizeof(stack_buf), @@ -877,14 +907,15 @@ static void dbg_cmd_bt(DbgState* s) { } { - const char* file = NULL; + const char *file = NULL; uint32_t line = 0; uint32_t col = 0; - int rc = cfree_dwarf_addr_to_line(s->dwarf, img_frame.pc, &file, &line, - &col); + int rc = + cfree_dwarf_addr_to_line(s->dwarf, img_frame.pc, &file, &line, &col); if (rc == 0 && file) { driver_printf(" at %s:%u", file, line); - if (col) driver_printf(":%u", col); + if (col) + driver_printf(":%u", col); } else if (rc == 2) { driver_printf(" [no debug info for this frame]"); } @@ -897,7 +928,8 @@ static void dbg_cmd_bt(DbgState* s) { * frame in, then copy back to `frame` so the next iteration's * lookups translate from the new runtime PC. */ step = cfree_dwarf_unwind_step(s->dwarf, &img_frame); - if (step == 1) break; /* bottom of stack */ + if (step == 1) + break; /* bottom of stack */ if (step != 0) { driver_errf(DBG_TOOL, "unwind step failed"); break; @@ -922,29 +954,32 @@ static void dbg_cmd_bt(DbgState* s) { * value only — callers print any leading "name = " and the trailing * newline. */ -static uint64_t dbg_load_le_u(const uint8_t* buf, size_t n) { +static uint64_t dbg_load_le_u(const uint8_t *buf, size_t n) { uint64_t v = 0; size_t i; - for (i = 0; i < n && i < 8; ++i) v |= ((uint64_t)buf[i]) << (8 * i); + for (i = 0; i < n && i < 8; ++i) + v |= ((uint64_t)buf[i]) << (8 * i); return v; } -static int64_t dbg_load_le_s(const uint8_t* buf, size_t n) { +static int64_t dbg_load_le_s(const uint8_t *buf, size_t n) { uint64_t v = dbg_load_le_u(buf, n); if (n > 0 && n < 8) { uint64_t sign = (uint64_t)1 << (8 * n - 1); - if (v & sign) v |= ~((sign << 1) - 1); + if (v & sign) + v |= ~((sign << 1) - 1); } return (int64_t)v; } static void dbg_indent(int n) { int i; - for (i = 0; i < n; ++i) driver_printf(" "); + for (i = 0; i < n; ++i) + driver_printf(" "); } -static void dbg_print_value(DbgState* s, const CfreeDwarfType* type, - const uint8_t* buf, size_t got, int depth) { +static void dbg_print_value(DbgState *s, const CfreeDwarfType *type, + const uint8_t *buf, size_t got, int depth) { CfreeDwarfTypeInfo ti; if (!type) { @@ -961,7 +996,8 @@ static void dbg_print_value(DbgState* s, const CfreeDwarfType* type, { size_t i; driver_printf("{"); - for (i = 0; i < got; ++i) driver_printf(" %02x", buf[i]); + for (i = 0; i < got; ++i) + driver_printf(" %02x", buf[i]); driver_printf(" }"); return; } @@ -969,135 +1005,137 @@ static void dbg_print_value(DbgState* s, const CfreeDwarfType* type, ti = cfree_dwarf_type_info(type); switch (ti.kind) { - case CFREE_DT_VOID: - driver_printf("void"); - return; - case CFREE_DT_SINT: - case CFREE_DT_CHAR: - driver_printf("%lld", (long long)dbg_load_le_s(buf, got)); - return; - case CFREE_DT_UINT: - case CFREE_DT_BOOL: - driver_printf("%llu", (unsigned long long)dbg_load_le_u(buf, got)); - return; - case CFREE_DT_PTR: - driver_printf("0x%llx", (unsigned long long)dbg_load_le_u(buf, got)); - return; - case CFREE_DT_FLOAT: - if (got == 4) { - union { - uint32_t u; - float f; - } cv; - cv.u = (uint32_t)dbg_load_le_u(buf, 4); - driver_printf("%g", (double)cv.f); - } else if (got == 8) { - union { - uint64_t u; - double d; - } cv; - cv.u = dbg_load_le_u(buf, 8); - driver_printf("%g", cv.d); - } else { - size_t i; - driver_printf("<float-%zu", got); - for (i = 0; i < got; ++i) driver_printf(" %02x", buf[i]); - driver_printf(">"); - } - return; - case CFREE_DT_ENUM: { - int64_t v = dbg_load_le_s(buf, got); - CfreeDwarfEnumIter* it = cfree_dwarf_enum_iter_new(s->dwarf, type); - CfreeDwarfEnumVal ev; - const char* match = NULL; - if (it) { - while (cfree_dwarf_enum_iter_next(it, &ev)) { - if (ev.value == v) { - match = ev.name; - break; - } + case CFREE_DT_VOID: + driver_printf("void"); + return; + case CFREE_DT_SINT: + case CFREE_DT_CHAR: + driver_printf("%lld", (long long)dbg_load_le_s(buf, got)); + return; + case CFREE_DT_UINT: + case CFREE_DT_BOOL: + driver_printf("%llu", (unsigned long long)dbg_load_le_u(buf, got)); + return; + case CFREE_DT_PTR: + driver_printf("0x%llx", (unsigned long long)dbg_load_le_u(buf, got)); + return; + case CFREE_DT_FLOAT: + if (got == 4) { + union { + uint32_t u; + float f; + } cv; + cv.u = (uint32_t)dbg_load_le_u(buf, 4); + driver_printf("%g", (double)cv.f); + } else if (got == 8) { + union { + uint64_t u; + double d; + } cv; + cv.u = dbg_load_le_u(buf, 8); + driver_printf("%g", cv.d); + } else { + size_t i; + driver_printf("<float-%zu", got); + for (i = 0; i < got; ++i) + driver_printf(" %02x", buf[i]); + driver_printf(">"); + } + return; + case CFREE_DT_ENUM: { + int64_t v = dbg_load_le_s(buf, got); + CfreeDwarfEnumIter *it = cfree_dwarf_enum_iter_new(s->dwarf, type); + CfreeDwarfEnumVal ev; + const char *match = NULL; + if (it) { + while (cfree_dwarf_enum_iter_next(it, &ev)) { + if (ev.value == v) { + match = ev.name; + break; } - cfree_dwarf_enum_iter_free(it); } - if (match) - driver_printf("%s (%lld)", match, (long long)v); - else - driver_printf("%lld", (long long)v); - return; + cfree_dwarf_enum_iter_free(it); } - case CFREE_DT_TYPEDEF: - dbg_print_value(s, ti.inner, buf, got, depth); - return; - case CFREE_DT_ARRAY: { - uint32_t n = ti.element_count; - size_t esz = 0; - uint32_t i; - if (ti.inner) { - CfreeDwarfTypeInfo ein = cfree_dwarf_type_info(ti.inner); - esz = ein.byte_size; - } - if (esz == 0 || n == 0 || (size_t)n * esz > got) { - size_t k; - driver_printf("{"); - for (k = 0; k < got; ++k) driver_printf(" %02x", buf[k]); - driver_printf(" }"); - return; - } - driver_printf("{\n"); - for (i = 0; i < n; ++i) { - dbg_indent(depth + 1); - driver_printf("[%u] = ", i); - dbg_print_value(s, ti.inner, buf + (size_t)i * esz, esz, depth + 1); - driver_printf(",\n"); - } - dbg_indent(depth); - driver_printf("}"); + if (match) + driver_printf("%s (%lld)", match, (long long)v); + else + driver_printf("%lld", (long long)v); + return; + } + case CFREE_DT_TYPEDEF: + dbg_print_value(s, ti.inner, buf, got, depth); + return; + case CFREE_DT_ARRAY: { + uint32_t n = ti.element_count; + size_t esz = 0; + uint32_t i; + if (ti.inner) { + CfreeDwarfTypeInfo ein = cfree_dwarf_type_info(ti.inner); + esz = ein.byte_size; + } + if (esz == 0 || n == 0 || (size_t)n * esz > got) { + size_t k; + driver_printf("{"); + for (k = 0; k < got; ++k) + driver_printf(" %02x", buf[k]); + driver_printf(" }"); return; } - case CFREE_DT_STRUCT: - case CFREE_DT_UNION: { - CfreeDwarfFieldIter* it = cfree_dwarf_field_iter_new(s->dwarf, type); - CfreeDwarfField f; - driver_printf("{\n"); - if (it) { - while (cfree_dwarf_field_iter_next(it, &f)) { - size_t fsz = 0; - dbg_indent(depth + 1); - driver_printf(".%s = ", (f.name && *f.name) ? f.name : "<anon>"); - if (f.bit_size) { - /* Bitfield: read up to 8 bytes spanning the storage - * unit at byte_offset, shift, mask. */ - size_t off = f.byte_offset; - size_t take = (off + 8 <= got) ? 8 : (off < got ? got - off : 0); - uint64_t raw = take ? dbg_load_le_u(buf + off, take) : 0; - uint64_t mask = (f.bit_size >= 64) - ? (uint64_t)-1 - : (((uint64_t)1 << f.bit_size) - 1); - uint64_t v = (raw >> f.bit_offset) & mask; - driver_printf("%llu", (unsigned long long)v); + driver_printf("{\n"); + for (i = 0; i < n; ++i) { + dbg_indent(depth + 1); + driver_printf("[%u] = ", i); + dbg_print_value(s, ti.inner, buf + (size_t)i * esz, esz, depth + 1); + driver_printf(",\n"); + } + dbg_indent(depth); + driver_printf("}"); + return; + } + case CFREE_DT_STRUCT: + case CFREE_DT_UNION: { + CfreeDwarfFieldIter *it = cfree_dwarf_field_iter_new(s->dwarf, type); + CfreeDwarfField f; + driver_printf("{\n"); + if (it) { + while (cfree_dwarf_field_iter_next(it, &f)) { + size_t fsz = 0; + dbg_indent(depth + 1); + driver_printf(".%s = ", (f.name && *f.name) ? f.name : "<anon>"); + if (f.bit_size) { + /* Bitfield: read up to 8 bytes spanning the storage + * unit at byte_offset, shift, mask. */ + size_t off = f.byte_offset; + size_t take = (off + 8 <= got) ? 8 : (off < got ? got - off : 0); + uint64_t raw = take ? dbg_load_le_u(buf + off, take) : 0; + uint64_t mask = (f.bit_size >= 64) + ? (uint64_t)-1 + : (((uint64_t)1 << f.bit_size) - 1); + uint64_t v = (raw >> f.bit_offset) & mask; + driver_printf("%llu", (unsigned long long)v); + } else { + if (f.type) { + CfreeDwarfTypeInfo fti = cfree_dwarf_type_info(f.type); + fsz = fti.byte_size; + } + if (f.type && fsz > 0 && (size_t)f.byte_offset + fsz <= got) { + dbg_print_value(s, f.type, buf + f.byte_offset, fsz, depth + 1); } else { - if (f.type) { - CfreeDwarfTypeInfo fti = cfree_dwarf_type_info(f.type); - fsz = fti.byte_size; - } - if (f.type && fsz > 0 && (size_t)f.byte_offset + fsz <= got) { - dbg_print_value(s, f.type, buf + f.byte_offset, fsz, depth + 1); - } else { - driver_printf("<truncated>"); - } + driver_printf("<truncated>"); } - driver_printf(",\n"); } - cfree_dwarf_field_iter_free(it); + driver_printf(",\n"); } - dbg_indent(depth); - driver_printf("}"); - return; + cfree_dwarf_field_iter_free(it); } - case CFREE_DT_FUNC: - driver_printf("<function@0x%llx>", - (unsigned long long)dbg_load_le_u(buf, got)); - return; + dbg_indent(depth); + driver_printf("}"); + return; + } + case CFREE_DT_FUNC: + driver_printf("<function@0x%llx>", + (unsigned long long)dbg_load_le_u(buf, got)); + return; } driver_printf("<?>"); } @@ -1106,11 +1144,11 @@ static void dbg_print_value(DbgState* s, const CfreeDwarfType* type, * type. On success returns 0 and sets *buf_out (which may point at * stack_buf or at a heap allocation) plus *got_out. The caller frees * *buf_out via dbg_release_value_buf when done. */ -static int dbg_read_value(DbgState* s, const CfreeDwarfVarLoc* loc, - const CfreeUnwindFrame* frame, uint8_t* stack_buf, - size_t stack_cap, uint8_t** buf_out, - size_t* alloc_out, size_t* got_out) { - uint8_t* buf = stack_buf; +static int dbg_read_value(DbgState *s, const CfreeDwarfVarLoc *loc, + const CfreeUnwindFrame *frame, uint8_t *stack_buf, + size_t stack_cap, uint8_t **buf_out, + size_t *alloc_out, size_t *got_out) { + uint8_t *buf = stack_buf; size_t alloc = 0; size_t cap = stack_cap; size_t got = 0; @@ -1118,12 +1156,14 @@ static int dbg_read_value(DbgState* s, const CfreeDwarfVarLoc* loc, if (loc->byte_size > cap) { alloc = loc->byte_size; buf = driver_alloc(s->env, alloc); - if (!buf) return 1; + if (!buf) + return 1; cap = alloc; } if (cfree_dwarf_loc_read(s->dwarf, loc, frame, s->session, buf, cap, &got) != 0) { - if (alloc) driver_free(s->env, buf, alloc); + if (alloc) + driver_free(s->env, buf, alloc); return 1; } *buf_out = buf; @@ -1132,18 +1172,19 @@ static int dbg_read_value(DbgState* s, const CfreeDwarfVarLoc* loc, return 0; } -static void dbg_release_value_buf(DbgState* s, uint8_t* buf, size_t alloc) { - if (alloc) driver_free(s->env, buf, alloc); +static void dbg_release_value_buf(DbgState *s, uint8_t *buf, size_t alloc) { + if (alloc) + driver_free(s->env, buf, alloc); } /* ============================================================ * `p name` * ============================================================ */ -static void dbg_cmd_print(DbgState* s, const char* name) { +static void dbg_cmd_print(DbgState *s, const char *name) { CfreeDwarfVarLoc loc; uint8_t stack_buf[64]; - uint8_t* buf; + uint8_t *buf; size_t alloc; size_t got; @@ -1154,9 +1195,9 @@ static void dbg_cmd_print(DbgState* s, const char* name) { { int rc = s->dwarf - ? cfree_dwarf_var_at( - s->dwarf, dbg_pc_rt_to_img(s, s->last_stop.regs.pc), - name, &loc) + ? cfree_dwarf_var_at(s->dwarf, + dbg_pc_rt_to_img(s, s->last_stop.regs.pc), + name, &loc) : 1; if (rc == 0) { dbg_translate_loc(s, &loc); @@ -1174,10 +1215,10 @@ static void dbg_cmd_print(DbgState* s, const char* name) { /* DWARF didn't know about it — try a global symbol. */ { - void* p = cfree_jit_lookup(s->jit, name); + void *p = cfree_jit_lookup(s->jit, name); if (p) { union { - void* p; + void *p; uint64_t u; } cv; cv.p = p; @@ -1203,7 +1244,7 @@ static void dbg_cmd_print(DbgState* s, const char* name) { * variables. v1 supports integer/pointer scalars only — float and * aggregate writes are out of scope. */ -static void dbg_cmd_set(DbgState* s, const char* name, uint64_t value) { +static void dbg_cmd_set(DbgState *s, const char *name, uint64_t value) { CfreeDwarfVarLoc loc; uint8_t buf[8]; size_t sz; @@ -1215,9 +1256,9 @@ static void dbg_cmd_set(DbgState* s, const char* name, uint64_t value) { } { int rc = s->dwarf - ? cfree_dwarf_var_at( - s->dwarf, dbg_pc_rt_to_img(s, s->last_stop.regs.pc), - name, &loc) + ? cfree_dwarf_var_at(s->dwarf, + dbg_pc_rt_to_img(s, s->last_stop.regs.pc), + name, &loc) : 1; if (rc != 0) { if (rc == 2) @@ -1231,41 +1272,41 @@ static void dbg_cmd_set(DbgState* s, const char* name, uint64_t value) { dbg_translate_loc(s, &loc); sz = (loc.byte_size == 0 || loc.byte_size > 8) ? 8 : loc.byte_size; - for (i = 0; i < sz; ++i) buf[i] = (uint8_t)(value >> (8 * i)); + for (i = 0; i < sz; ++i) + buf[i] = (uint8_t)(value >> (8 * i)); switch (loc.kind) { - case CFREE_DLOC_FRAME_OFS: { - uint64_t addr = - s->last_stop.regs.cfa + (uint64_t)(int64_t)loc.v.frame_ofs; - if (cfree_jit_session_write_mem(s->session, addr, buf, sz) != 0) { - driver_errf(DBG_TOOL, "memory write failed"); - } - return; + case CFREE_DLOC_FRAME_OFS: { + uint64_t addr = s->last_stop.regs.cfa + (uint64_t)(int64_t)loc.v.frame_ofs; + if (cfree_jit_session_write_mem(s->session, addr, buf, sz) != 0) { + driver_errf(DBG_TOOL, "memory write failed"); } - case CFREE_DLOC_GLOBAL: - if (cfree_jit_session_write_mem(s->session, loc.v.global, buf, sz) != 0) { - driver_errf(DBG_TOOL, "memory write failed"); - } - return; - case CFREE_DLOC_REG: { - CfreeUnwindFrame fr = s->last_stop.regs; - if (loc.v.reg >= 32) { - driver_errf(DBG_TOOL, "register %u outside the snapshot range", - loc.v.reg); - return; - } - fr.regs[loc.v.reg] = value; - if (cfree_jit_session_set_regs(s->session, &fr) != 0) { - driver_errf(DBG_TOOL, "register write failed"); - return; - } - s->last_stop.regs = fr; + return; + } + case CFREE_DLOC_GLOBAL: + if (cfree_jit_session_write_mem(s->session, loc.v.global, buf, sz) != 0) { + driver_errf(DBG_TOOL, "memory write failed"); + } + return; + case CFREE_DLOC_REG: { + CfreeUnwindFrame fr = s->last_stop.regs; + if (loc.v.reg >= 32) { + driver_errf(DBG_TOOL, "register %u outside the snapshot range", + loc.v.reg); return; } - case CFREE_DLOC_EXPR: - driver_errf(DBG_TOOL, "cannot set '%s': location is a DWARF expression", - name); + fr.regs[loc.v.reg] = value; + if (cfree_jit_session_set_regs(s->session, &fr) != 0) { + driver_errf(DBG_TOOL, "register write failed"); return; + } + s->last_stop.regs = fr; + return; + } + case CFREE_DLOC_EXPR: + driver_errf(DBG_TOOL, "cannot set '%s': location is a DWARF expression", + name); + return; } } @@ -1275,7 +1316,7 @@ static void dbg_cmd_set(DbgState* s, const char* name, uint64_t value) { * Move PC without resuming. The session validates that the new PC lies * within the JIT image. */ -static void dbg_cmd_jump(DbgState* s, uint64_t pc) { +static void dbg_cmd_jump(DbgState *s, uint64_t pc) { CfreeUnwindFrame fr; if (!s->has_stop) { driver_errf(DBG_TOOL, "no program is stopped"); @@ -1296,8 +1337,8 @@ static void dbg_cmd_jump(DbgState* s, uint64_t pc) { * `info locals` / `info args` / `info reg` * ============================================================ */ -static void dbg_cmd_info_vars(DbgState* s, uint32_t mask, const char* label) { - CfreeDwarfVarIter* it; +static void dbg_cmd_info_vars(DbgState *s, uint32_t mask, const char *label) { + CfreeDwarfVarIter *it; CfreeDwarfVar v; int printed = 0; @@ -1318,7 +1359,7 @@ static void dbg_cmd_info_vars(DbgState* s, uint32_t mask, const char* label) { } while (cfree_dwarf_vars_at_next(it, &v)) { uint8_t stack_buf[64]; - uint8_t* buf; + uint8_t *buf; size_t alloc; size_t got; printed = 1; @@ -1334,10 +1375,11 @@ static void dbg_cmd_info_vars(DbgState* s, uint32_t mask, const char* label) { dbg_release_value_buf(s, buf, alloc); } cfree_dwarf_vars_at_free(it); - if (!printed) driver_printf("No %s.\n", label); + if (!printed) + driver_printf("No %s.\n", label); } -static void dbg_cmd_info_reg(DbgState* s) { +static void dbg_cmd_info_reg(DbgState *s) { CfreeArchKind arch = driver_host_target().arch; uint32_t n = cfree_arch_register_count(arch); uint32_t i; @@ -1355,8 +1397,10 @@ static void dbg_cmd_info_reg(DbgState* s) { (unsigned long long)s->last_stop.regs.cfa); for (i = 0; i < n; ++i) { CfreeArchReg r; - if (cfree_arch_register_at(arch, i, &r) != 0) continue; - if (r.dwarf_idx >= 32) continue; /* outside CfreeUnwindFrame.regs */ + if (cfree_arch_register_at(arch, i, &r) != 0) + continue; + if (r.dwarf_idx >= 32) + continue; /* outside CfreeUnwindFrame.regs */ driver_printf("%-6s 0x%016llx\n", r.name, (unsigned long long)s->last_stop.regs.regs[r.dwarf_idx]); } @@ -1368,28 +1412,33 @@ static void dbg_cmd_info_reg(DbgState* s) { /* Tiny glob matcher: '*' matches any run, '?' matches any single byte. * NULL pattern matches every name. */ -static int dbg_glob(const char* pat, const char* s) { - if (!pat) return 1; +static int dbg_glob(const char *pat, const char *s) { + if (!pat) + return 1; while (*pat && *s) { if (*pat == '*') { - if (pat[1] == '\0') return 1; + if (pat[1] == '\0') + return 1; while (*s) { - if (dbg_glob(pat + 1, s)) return 1; + if (dbg_glob(pat + 1, s)) + return 1; ++s; } return dbg_glob(pat + 1, s); } - if (*pat != '?' && *pat != *s) return 0; + if (*pat != '?' && *pat != *s) + return 0; ++pat; ++s; } - while (*pat == '*') ++pat; + while (*pat == '*') + ++pat; return *pat == '\0' && *s == '\0'; } -static void dbg_cmd_info_syms(DbgState* s, CfreeSymKind want, - const char* pattern) { - CfreeJitSymIter* it = cfree_jit_sym_iter_new(s->jit); +static void dbg_cmd_info_syms(DbgState *s, CfreeSymKind want, + const char *pattern) { + CfreeJitSymIter *it = cfree_jit_sym_iter_new(s->jit); CfreeJitSym sym; int printed = 0; @@ -1398,16 +1447,19 @@ static void dbg_cmd_info_syms(DbgState* s, CfreeSymKind want, return; } while (cfree_jit_sym_iter_next(it, &sym)) { - if (sym.kind != want) continue; - if (pattern && !dbg_glob(pattern, sym.name)) continue; + if (sym.kind != want) + continue; + if (pattern && !dbg_glob(pattern, sym.name)) + continue; driver_printf("0x%016llx %s\n", (unsigned long long)sym.addr, sym.name); printed = 1; } cfree_jit_sym_iter_free(it); - if (!printed) driver_printf("(none)\n"); + if (!printed) + driver_printf("(none)\n"); } -static int dbg_refresh_dwarf(DbgState* s) { +static int dbg_refresh_dwarf(DbgState *s) { if (s->dwarf) { cfree_dwarf_close(s->dwarf); s->dwarf = NULL; @@ -1424,15 +1476,17 @@ static int dbg_refresh_dwarf(DbgState* s) { return 0; } -static int dbg_buf_append(DbgState* s, char** buf, size_t* len, size_t* cap, - const char* src, size_t n) { +static int dbg_buf_append(DbgState *s, char **buf, size_t *len, size_t *cap, + const char *src, size_t n) { if (*len + n + 1u > *cap) { size_t nc = *cap ? *cap * 2u : 1024u; - char* nb; - while (nc < *len + n + 1u) nc *= 2u; - nb = (char*)s->env->heap->realloc(s->env->heap, *buf, *cap, nc, - _Alignof(char)); - if (!nb) return 1; + char *nb; + while (nc < *len + n + 1u) + nc *= 2u; + nb = (char *)s->env->heap->realloc(s->env->heap, *buf, *cap, nc, + _Alignof(char)); + if (!nb) + return 1; *buf = nb; *cap = nc; } @@ -1442,60 +1496,156 @@ static int dbg_buf_append(DbgState* s, char** buf, size_t* len, size_t* cap, return 0; } -static int dbg_brace_delta(const char* p) { +static int dbg_brace_delta(const char *p) { int d = 0; while (*p) { - if (*p == '{') ++d; - else if (*p == '}') --d; + if (*p == '{') + ++d; + else if (*p == '}') + --d; ++p; } return d; } -static CfreeLanguage dbg_jit_language_for_tag(const char* tag, - const char** name_out) { - if (!tag || !*tag || driver_streq(tag, "c")) { - if (name_out) *name_out = "<dbg-jit.c>"; +static const char *dbg_jit_language_name(CfreeLanguage lang) { + switch (lang) { + case CFREE_LANG_ASM: + return "asm"; + case CFREE_LANG_TOY: + return "toy"; + case CFREE_LANG_C: + case CFREE_LANG_COUNT: + break; + } + return "c"; +} + +static const char *dbg_jit_language_suffix(CfreeLanguage lang) { + switch (lang) { + case CFREE_LANG_ASM: + return ".s"; + case CFREE_LANG_TOY: + return ".toy"; + case CFREE_LANG_C: + case CFREE_LANG_COUNT: + break; + } + return ".c"; +} + +static const char *dbg_jit_default_name(CfreeLanguage lang) { + switch (lang) { + case CFREE_LANG_ASM: + return "<dbg-jit.s>"; + case CFREE_LANG_TOY: + return "<dbg-jit.toy>"; + case CFREE_LANG_C: + case CFREE_LANG_COUNT: + break; + } + return "<dbg-jit.c>"; +} + +static CfreeLanguage dbg_jit_language_for_tag(DbgState *s, const char *tag, + const char **name_out) { + if (!tag || !*tag) { + if (name_out) + *name_out = s->default_jit_name; + return s->default_jit_lang; + } + if (driver_streq(tag, "c")) { + if (name_out) + *name_out = "<dbg-jit.c>"; return CFREE_LANG_C; } if (driver_streq(tag, "toy")) { - if (name_out) *name_out = "<dbg-jit.toy>"; + if (name_out) + *name_out = "<dbg-jit.toy>"; return CFREE_LANG_TOY; } if (driver_streq(tag, "asm") || driver_streq(tag, "s")) { - if (name_out) *name_out = "<dbg-jit.s>"; + if (name_out) + *name_out = "<dbg-jit.s>"; return CFREE_LANG_ASM; } - if (name_out) *name_out = tag; + if (name_out) + *name_out = tag; return cfree_language_for_path(tag); } -static void dbg_cmd_jit(DbgState* s, const char* rest) { - char* src = NULL; - size_t len = 0, cap = 0; +static int dbg_jit_compile_append(DbgState *s, CfreeLanguage lang, + const char *input_name, const char *src, + size_t len) { CfreeBytesInput in; - CfreeObjBuilder* ob = NULL; - const char* p = rest; - const char* input_name = "<dbg-jit.c>"; - CfreeLanguage lang = CFREE_LANG_C; - int depth; + CfreeObjBuilder *ob = NULL; - while (*p && dbg_isspace((unsigned char)*p)) ++p; - if (*p != '{') { - const char* tag = p; + s->jit_counter++; + in.name = input_name ? input_name : dbg_jit_default_name(lang); + in.data = (const uint8_t *)src; + in.len = len; + in.lang = lang; + if (cfree_pipeline_compile_obj(s->pipe, &s->copts, &in, &ob) != 0 || !ob) { + driver_errf(DBG_TOOL, "jit compile failed"); + return 1; + } + if (cfree_jit_append_obj(s->jit, ob) != 0) { + driver_errf(DBG_TOOL, "jit append failed"); + return 1; + } + dbg_refresh_dwarf(s); + driver_printf("JIT generation %llu (%s)\n", + (unsigned long long)cfree_jit_generation(s->jit), + dbg_jit_language_name(lang)); + return 0; +} + +static int dbg_parse_jit_lang_arg(DbgState *s, const char *rest, + CfreeLanguage *lang_out, + const char **input_name_out, + const char **after_out) { + const char *p = rest; + const char *input_name = NULL; + CfreeLanguage lang; + + while (*p && dbg_isspace((unsigned char)*p)) + ++p; + if (*p && *p != '{') { + const char *tag = p; size_t tag_n; char tag_buf[64]; - while (*p && !dbg_isspace((unsigned char)*p) && *p != '{') ++p; + while (*p && !dbg_isspace((unsigned char)*p) && *p != '{') + ++p; tag_n = (size_t)(p - tag); if (tag_n == 0 || tag_n >= sizeof(tag_buf)) { - driver_errf(DBG_TOOL, "usage: jit [c|toy|asm|name.ext] { ... }"); - return; + driver_errf(DBG_TOOL, "language/name is too long"); + return 1; } driver_memcpy(tag_buf, tag, tag_n); tag_buf[tag_n] = '\0'; - lang = dbg_jit_language_for_tag(tag_buf, &input_name); - while (*p && dbg_isspace((unsigned char)*p)) ++p; + lang = dbg_jit_language_for_tag(s, tag_buf, &input_name); + while (*p && dbg_isspace((unsigned char)*p)) + ++p; + } else { + lang = dbg_jit_language_for_tag(s, NULL, &input_name); } + + *lang_out = lang; + *input_name_out = input_name; + *after_out = p; + return 0; +} + +static void dbg_cmd_jit(DbgState *s, const char *rest) { + char *src = NULL; + size_t len = 0, cap = 0; + const char *p; + const char *input_name; + CfreeLanguage lang; + int depth; + + if (dbg_parse_jit_lang_arg(s, rest, &lang, &input_name, &p) != 0) + return; if (*p != '{') { driver_errf(DBG_TOOL, "usage: jit [c|toy|asm|name.ext] { ... }"); return; @@ -1503,14 +1653,17 @@ static void dbg_cmd_jit(DbgState* s, const char* rest) { ++p; depth = 1 + dbg_brace_delta(p); { - const char* end = p + driver_strlen(p); + const char *end = p + driver_strlen(p); if (depth <= 0) { - while (end > p && end[-1] != '}') --end; - if (end > p) --end; + while (end > p && end[-1] != '}') + --end; + if (end > p) + --end; } if (dbg_buf_append(s, &src, &len, &cap, p, (size_t)(end - p)) != 0) goto oom; - if (dbg_buf_append(s, &src, &len, &cap, "\n", 1) != 0) goto oom; + if (dbg_buf_append(s, &src, &len, &cap, "\n", 1) != 0) + goto oom; } while (depth > 0) { char line[LINE_CAP]; @@ -1524,53 +1677,553 @@ static void dbg_cmd_jit(DbgState* s, const char* rest) { } depth += dbg_brace_delta(line); if (depth <= 0) { - char* close = line; - while (*close && *close != '}') ++close; - if (dbg_buf_append(s, &src, &len, &cap, line, - (size_t)(close - line)) != 0) + char *close = line; + while (*close && *close != '}') + ++close; + if (dbg_buf_append(s, &src, &len, &cap, line, (size_t)(close - line)) != + 0) + goto oom; + if (dbg_buf_append(s, &src, &len, &cap, "\n", 1) != 0) goto oom; - if (dbg_buf_append(s, &src, &len, &cap, "\n", 1) != 0) goto oom; break; } if (dbg_buf_append(s, &src, &len, &cap, line, driver_strlen(line)) != 0) goto oom; - if (dbg_buf_append(s, &src, &len, &cap, "\n", 1) != 0) goto oom; + if (dbg_buf_append(s, &src, &len, &cap, "\n", 1) != 0) + goto oom; } - s->jit_counter++; - in.name = input_name; - in.data = (const uint8_t*)src; - in.len = len; - in.lang = lang; - if (cfree_pipeline_compile_obj(s->pipe, &s->copts, &in, &ob) != 0 || !ob) { - driver_errf(DBG_TOOL, "jit compile failed"); + (void)dbg_jit_compile_append(s, lang, input_name, src, len); + goto out; + +oom: + driver_errf(DBG_TOOL, "out of memory"); +out: + if (src) + driver_free(s->env, src, cap); +} + +static void dbg_cmd_edit(DbgState *s, const char *rest) { + CfreeLanguage lang; + const char *input_name; + const char *p; + uint8_t *src = NULL; + size_t len = 0; + + if (dbg_parse_jit_lang_arg(s, rest, &lang, &input_name, &p) != 0) + return; + if (*p) { + driver_errf(DBG_TOOL, "usage: edit [c|toy|asm|name.ext]"); + return; + } + if (!driver_edit_temp(s->env, dbg_jit_language_suffix(lang), NULL, 0, &src, + &len)) { + driver_errf(DBG_TOOL, "editor failed"); + return; + } + if (len == 0) { + driver_errf(DBG_TOOL, "empty editor buffer; nothing appended"); goto out; } - if (cfree_jit_append_obj(s->jit, ob) != 0) { - driver_errf(DBG_TOOL, "jit append failed"); + (void)dbg_jit_compile_append(s, lang, input_name, (const char *)src, len); + +out: + driver_free(s->env, src, len); +} + +static size_t dbg_u64_dec(char *dst, size_t cap, uint64_t v) { + char tmp[32]; + size_t n = 0; + size_t i; + if (!dst || cap == 0) + return 0; + if (v == 0) { + if (cap < 2u) + return 0; + dst[0] = '0'; + dst[1] = '\0'; + return 1; + } + while (v && n < sizeof(tmp)) { + tmp[n++] = (char)('0' + (v % 10u)); + v /= 10u; + } + if (n + 1u > cap) + return 0; + for (i = 0; i < n; ++i) + dst[i] = tmp[n - 1u - i]; + dst[n] = '\0'; + return n; +} + +static int dbg_call_u64_entry(DbgState *s, void *entry, const uint64_t *args, + uint32_t nargs, uint64_t *ret_out) { + uint64_t ret = 0; + CfreeStopInfo stop; + + if (driver_install_sigint(dbg_on_sigint, s) != 0) { + driver_errf(DBG_TOOL, "failed to install SIGINT handler"); + return 1; + } + if (cfree_jit_session_call_u64(s->session, entry, args, nargs, &ret, &stop) != + 0) { + driver_restore_sigint(); + driver_errf(DBG_TOOL, "call failed (debuggee must be idle or exited)"); + return 1; + } + driver_restore_sigint(); + s->last_stop = stop; + s->has_stop = (stop.kind != CFREE_STOP_EXIT); + if (ret_out) + *ret_out = ret; + if (stop.kind != CFREE_STOP_EXIT) { + s->has_stop = 1; + dbg_render_stop(s, &stop); + return 2; + } + return 0; +} + +static int dbg_c_ident_ok(const char *name) { + if (!name || !dbg_isalpha_((unsigned char)name[0])) + return 0; + while (*++name) { + if (!dbg_isalnum_((unsigned char)*name)) + return 0; + } + return 1; +} + +static int dbg_type_base_to_c(DbgState *s, char **buf, size_t *len, size_t *cap, + const CfreeDwarfTypeInfo *ti) { + const char *spelling = NULL; + switch (ti->kind) { + case CFREE_DT_VOID: + spelling = "void"; + break; + case CFREE_DT_BOOL: + spelling = "_Bool"; + break; + case CFREE_DT_CHAR: + spelling = "char"; + break; + case CFREE_DT_SINT: + switch (ti->byte_size) { + case 1: + spelling = "signed char"; + break; + case 2: + spelling = "short"; + break; + case 4: + spelling = "int"; + break; + case 8: + spelling = "long long"; + break; + } + break; + case CFREE_DT_UINT: + switch (ti->byte_size) { + case 1: + spelling = "unsigned char"; + break; + case 2: + spelling = "unsigned short"; + break; + case 4: + spelling = "unsigned int"; + break; + case 8: + spelling = "unsigned long long"; + break; + } + break; + case CFREE_DT_FLOAT: + if (ti->byte_size == 4) + spelling = "float"; + else if (ti->byte_size == 8) + spelling = "double"; + break; + case CFREE_DT_ENUM: + spelling = "int"; + break; + default: + break; + } + if (!spelling) + return 1; + return dbg_buf_append(s, buf, len, cap, spelling, driver_strlen(spelling)); +} + +static int dbg_type_render_c(DbgState *s, const CfreeDwarfType *type, + char **buf, size_t *len, size_t *cap, + uint32_t ptr_depth) { + CfreeDwarfTypeInfo ti; + if (!type) + return 1; + ti = cfree_dwarf_type_info(type); + while (ti.kind == CFREE_DT_TYPEDEF) { + if (!ti.inner) + return 1; + ti = cfree_dwarf_type_info(ti.inner); + } + if (ti.kind == CFREE_DT_PTR) { + if (!ti.inner) + return 1; + return dbg_type_render_c(s, ti.inner, buf, len, cap, ptr_depth + 1u); + } + if (ti.kind == CFREE_DT_STRUCT || ti.kind == CFREE_DT_UNION) { + const char *tag = ti.kind == CFREE_DT_STRUCT ? "struct " : "union "; + if (ptr_depth == 0 || !ti.name || !dbg_c_ident_ok(ti.name)) + return 1; + if (dbg_buf_append(s, buf, len, cap, tag, driver_strlen(tag)) != 0) + return 1; + if (dbg_buf_append(s, buf, len, cap, ti.name, driver_strlen(ti.name)) != 0) + return 1; + } else if (ti.kind == CFREE_DT_ARRAY || ti.kind == CFREE_DT_FUNC) { + return 1; + } else if (dbg_type_base_to_c(s, buf, len, cap, &ti) != 0) { + return 1; + } + while (ptr_depth--) { + if (dbg_buf_append(s, buf, len, cap, " *", 2) != 0) + return 1; + } + return 0; +} + +static int dbg_append_typed_func_proto(DbgState *s, char **src, size_t *len, + size_t *cap, const CfreeJitSym *sym) { + char *tmp = NULL; + size_t tmp_len = 0, tmp_cap = 0; + uint64_t img_pc; + CfreeDwarfSubprogram sp; + CfreeDwarfParamIter *pit; + CfreeDwarfVar param; + int any_param = 0; + int use_named = 0; + int rc = 1; + + if (!s->dwarf) goto out; + img_pc = dbg_pc_rt_to_img(s, sym->addr); + if (!img_pc || cfree_dwarf_subprogram_at(s->dwarf, img_pc, &sp) != 0) { + if (cfree_dwarf_subprogram_named(s->dwarf, sym->name, &sp) != 0) + goto out; + use_named = 1; + } + if (sp.inlined) + goto out; + if (dbg_buf_append(s, &tmp, &tmp_len, &tmp_cap, "extern ", 7) != 0) + goto out; + if (dbg_type_render_c(s, sp.return_type, &tmp, &tmp_len, &tmp_cap, 0) != 0) + goto out; + if (dbg_buf_append(s, &tmp, &tmp_len, &tmp_cap, " ", 1) != 0) + goto out; + if (dbg_buf_append(s, &tmp, &tmp_len, &tmp_cap, sym->name, + driver_strlen(sym->name)) != 0) + goto out; + if (dbg_buf_append(s, &tmp, &tmp_len, &tmp_cap, "(", 1) != 0) + goto out; + pit = use_named ? cfree_dwarf_param_iter_new_named(s->dwarf, sym->name) + : cfree_dwarf_param_iter_new(s->dwarf, img_pc); + if (!pit) { + if (dbg_buf_append(s, &tmp, &tmp_len, &tmp_cap, "void", 4) != 0) + goto out; + } else { + while (cfree_dwarf_param_iter_next(pit, &param)) { + if (any_param && + dbg_buf_append(s, &tmp, &tmp_len, &tmp_cap, ", ", 2) != 0) { + cfree_dwarf_param_iter_free(pit); + goto out; + } + if (dbg_type_render_c(s, param.loc.type, &tmp, &tmp_len, &tmp_cap, 0) != + 0) { + cfree_dwarf_param_iter_free(pit); + goto out; + } + any_param = 1; + } + cfree_dwarf_param_iter_free(pit); + if (!any_param && + dbg_buf_append(s, &tmp, &tmp_len, &tmp_cap, "void", 4) != 0) + goto out; + } + if (dbg_buf_append(s, &tmp, &tmp_len, &tmp_cap, ");\n", 3) != 0) + goto out; + if (dbg_buf_append(s, src, len, cap, tmp, tmp_len) != 0) + goto out; + rc = 0; + +out: + if (tmp) + driver_free(s->env, tmp, tmp_cap); + return rc; +} + +static int dbg_expr_call_arg_count_one(const char *p, const char *end) { + int depth = 1; + int saw_arg = 0; + int nargs = 0; + while (p < end && *p) { + if (*p == '"' || *p == '\'') { + int quote = (unsigned char)*p++; + while (p < end && *p) { + if (*p == '\\' && p + 1 < end) { + p += 2; + continue; + } + if ((unsigned char)*p++ == quote) + break; + } + continue; + } + if (*p == '(') { + saw_arg = 1; + depth++; + } else if (*p == ')') { + depth--; + if (depth == 0) + return saw_arg ? nargs + 1 : 0; + } else if (*p == ',' && depth == 1) { + nargs++; + saw_arg = 0; + } else if (!dbg_isspace((unsigned char)*p)) { + saw_arg = 1; + } + p++; + } + return -1; +} + +static int dbg_expr_call_arg_count(const char *text, const char *name) { + size_t name_len = driver_strlen(name); + int best = -1; + const char *p = text; + if (!text || !name || !name_len) + return -1; + while (*p) { + if (*p == '"' || *p == '\'') { + int quote = (unsigned char)*p++; + while (*p) { + if (*p == '\\' && p[1]) { + p += 2; + continue; + } + if ((unsigned char)*p++ == quote) + break; + } + continue; + } + if ((p == text || !dbg_isalnum_((unsigned char)p[-1])) && + driver_strneq(p, name, name_len) && + !dbg_isalnum_((unsigned char)p[name_len])) { + const char *q = p + name_len; + while (*q && dbg_isspace((unsigned char)*q)) + q++; + if (*q == '(') { + int n = dbg_expr_call_arg_count_one(q + 1, q + driver_strlen(q)); + if (n > best) + best = n; + } + p = q; + continue; + } + p++; + } + return best; +} + +static int dbg_append_fallback_func_proto(DbgState *s, char **src, size_t *len, + size_t *cap, const char *name, + int nargs) { + int i; + if (dbg_buf_append(s, src, len, cap, "extern unsigned long long ", 26) != 0) + return 1; + if (dbg_buf_append(s, src, len, cap, name, driver_strlen(name)) != 0) + return 1; + if (dbg_buf_append(s, src, len, cap, "(", 1) != 0) + return 1; + if (nargs <= 0) { + if (dbg_buf_append(s, src, len, cap, "void", 4) != 0) + return 1; + } else { + for (i = 0; i < nargs; ++i) { + if (i && dbg_buf_append(s, src, len, cap, ", ", 2) != 0) + return 1; + if (dbg_buf_append(s, src, len, cap, "unsigned long long", 18) != 0) + return 1; + } + } + return dbg_buf_append(s, src, len, cap, ");\n", 3); +} + +static int dbg_append_expr_prelude(DbgState *s, char **src, size_t *len, + size_t *cap, const char *call_scan_text) { + CfreeJitSymIter *it = cfree_jit_sym_iter_new(s->jit); + CfreeJitSym sym; + if (!it) + return 0; + while (cfree_jit_sym_iter_next(it, &sym)) { + if (sym.kind != CFREE_SK_FUNC) + continue; + if (!dbg_c_ident_ok(sym.name)) + continue; + if (dbg_append_typed_func_proto(s, src, len, cap, &sym) == 0) + continue; + if (dbg_append_fallback_func_proto( + s, src, len, cap, sym.name, + dbg_expr_call_arg_count(call_scan_text, sym.name)) != 0) + goto oom; + } + cfree_jit_sym_iter_free(it); + return 0; + +oom: + cfree_jit_sym_iter_free(it); + return 1; +} + +static void dbg_cmd_expr(DbgState *s, const char *expr) { + char *src = NULL; + char *body = NULL; + size_t len = 0, cap = 0; + size_t body_len = 0, body_cap = 0; + char num[32]; + char name[64]; + size_t num_len; + size_t prefix_len; + void *entry; + uint64_t ret = 0; + uint64_t id; + int is_block = 0; + + while (*expr && dbg_isspace((unsigned char)*expr)) + ++expr; + if (!*expr) { + driver_errf(DBG_TOOL, "usage: expr C_EXPR | expr { C_STATEMENTS }"); + return; + } + + if (*expr == '{') { + const char *p = expr + 1; + int depth = 1 + dbg_brace_delta(p); + const char *end = p + driver_strlen(p); + is_block = 1; + if (depth <= 0) { + while (end > p && end[-1] != '}') + --end; + if (end > p) + --end; + } + if (dbg_buf_append(s, &body, &body_len, &body_cap, p, (size_t)(end - p)) != + 0) + goto oom; + if (dbg_buf_append(s, &body, &body_len, &body_cap, "\n", 1) != 0) + goto oom; + while (depth > 0) { + char line[LINE_CAP]; + int n; + driver_printf("expr > "); + driver_flush_stdout(); + n = driver_read_line(line, sizeof(line)); + if (n <= 0) { + driver_errf(DBG_TOOL, "unterminated expr block"); + goto out; + } + depth += dbg_brace_delta(line); + if (depth <= 0) { + char *close = line; + while (*close && *close != '}') + ++close; + if (dbg_buf_append(s, &body, &body_len, &body_cap, line, + (size_t)(close - line)) != 0) + goto oom; + if (dbg_buf_append(s, &body, &body_len, &body_cap, "\n", 1) != 0) + goto oom; + break; + } + if (dbg_buf_append(s, &body, &body_len, &body_cap, line, + driver_strlen(line)) != 0) + goto oom; + if (dbg_buf_append(s, &body, &body_len, &body_cap, "\n", 1) != 0) + goto oom; + } + } + + id = ++s->expr_counter; + num_len = dbg_u64_dec(num, sizeof(num), id); + if (!num_len) { + driver_errf(DBG_TOOL, "expression counter overflow"); + return; + } + prefix_len = driver_strlen("__cfree_dbg_expr_"); + if (prefix_len + num_len + 1u > sizeof(name)) { + driver_errf(DBG_TOOL, "expression symbol too long"); + return; + } + driver_memcpy(name, "__cfree_dbg_expr_", prefix_len); + driver_memcpy(name + prefix_len, num, num_len + 1u); + + if (dbg_append_expr_prelude(s, &src, &len, &cap, is_block ? body : expr) != 0) + goto oom; + { + const char *ret_type = "unsigned long long "; + if (dbg_buf_append(s, &src, &len, &cap, ret_type, + driver_strlen(ret_type)) != 0) + goto oom; + if (dbg_buf_append(s, &src, &len, &cap, name, driver_strlen(name)) != 0) + goto oom; + } + if (is_block) { + if (dbg_buf_append(s, &src, &len, &cap, "(void) {\n", 9) != 0) + goto oom; + if (dbg_buf_append(s, &src, &len, &cap, body, body_len) != 0) + goto oom; + if (dbg_buf_append(s, &src, &len, &cap, "}\n", 2) != 0) + goto oom; + } else { + const char *open = "(void) { return (unsigned long long)("; + if (dbg_buf_append(s, &src, &len, &cap, open, driver_strlen(open)) != 0) + goto oom; + if (dbg_buf_append(s, &src, &len, &cap, expr, driver_strlen(expr)) != 0) + goto oom; + if (dbg_buf_append(s, &src, &len, &cap, "); }\n", 5) != 0) + goto oom; + } + + if (dbg_jit_compile_append(s, CFREE_LANG_C, "<dbg-expr.c>", src, len) != 0) + goto out; + entry = cfree_jit_lookup(s->jit, name); + if (!entry) { + driver_errf(DBG_TOOL, "expression thunk not found: %s", name); + goto out; + } + if (dbg_call_u64_entry(s, entry, NULL, 0, &ret) == 0) { + driver_printf("$%llu = %llu (0x%llx)\n", (unsigned long long)id, + (unsigned long long)ret, (unsigned long long)ret); } - dbg_refresh_dwarf(s); - driver_printf("JIT generation %llu\n", - (unsigned long long)cfree_jit_generation(s->jit)); goto out; oom: driver_errf(DBG_TOOL, "out of memory"); out: - if (src) driver_free(s->env, src, cap); + if (src) + driver_free(s->env, src, cap); + if (body) + driver_free(s->env, body, body_cap); } -static void dbg_cmd_call(DbgState* s, const char* rest) { - char* tmp; +static void dbg_cmd_call(DbgState *s, const char *rest) { + char *tmp; size_t tmp_size; - char* sym; - char* p; + char *sym; + char *p; uint64_t args[8]; uint32_t nargs = 0; - void* entry; + void *entry; uint64_t ret = 0; - CfreeStopInfo stop; tmp = dbg_dup(s->env, rest, driver_strlen(rest), &tmp_size); if (!tmp) { @@ -1588,11 +2241,12 @@ static void dbg_cmd_call(DbgState* s, const char* rest) { goto out; } while (*p) { - char* a; + char *a; uint64_t v; size_t used; p = dbg_take_word(p, &a); - if (!*a) break; + if (!*a) + break; if (nargs == 8u) { driver_errf(DBG_TOOL, "call supports at most 8 arguments"); goto out; @@ -1604,25 +2258,9 @@ static void dbg_cmd_call(DbgState* s, const char* rest) { } args[nargs++] = v; } - if (driver_install_sigint(dbg_on_sigint, s) != 0) { - driver_errf(DBG_TOOL, "failed to install SIGINT handler"); - goto out; - } - if (cfree_jit_session_call_u64(s->session, entry, args, nargs, &ret, &stop) != - 0) { - driver_restore_sigint(); - driver_errf(DBG_TOOL, "call failed (debuggee must be idle or exited)"); - goto out; - } - driver_restore_sigint(); - s->last_stop = stop; - s->has_stop = (stop.kind != CFREE_STOP_EXIT); - if (stop.kind == CFREE_STOP_EXIT) { + if (dbg_call_u64_entry(s, entry, args, nargs, &ret) == 0) { driver_printf("= %llu (0x%llx)\n", (unsigned long long)ret, (unsigned long long)ret); - } else { - s->has_stop = 1; - dbg_render_stop(s, &stop); } out: @@ -1635,7 +2273,7 @@ out: * Examine memory: reads `count` bytes (default 16) at `addr` from the * worker's address space and prints them as 16-byte rows. */ -static void dbg_cmd_examine(DbgState* s, uint64_t addr, size_t count) { +static void dbg_cmd_examine(DbgState *s, uint64_t addr, size_t count) { uint8_t buf[256]; size_t remaining = count; @@ -1655,7 +2293,8 @@ static void dbg_cmd_examine(DbgState* s, uint64_t addr, size_t count) { size_t j; size_t row = chunk - i < 16 ? chunk - i : 16; driver_printf("0x%llx:", (unsigned long long)(addr + i)); - for (j = 0; j < row; ++j) driver_printf(" %02x", buf[i + j]); + for (j = 0; j < row; ++j) + driver_printf(" %02x", buf[i + j]); driver_printf("\n"); } addr += chunk; @@ -1672,10 +2311,10 @@ static void dbg_cmd_examine(DbgState* s, uint64_t addr, size_t count) { * (e.g. the DWARF came from a `.o` / `.a` whose source isn't available * here), report the DWARF line number alone and omit the snippet. */ -#define DBG_LIST_CTX 5 /* lines printed before/after the target */ +#define DBG_LIST_CTX 5 /* lines printed before/after the target */ -static void dbg_cmd_list(DbgState* s, const char* spec) { - const char* colon; +static void dbg_cmd_list(DbgState *s, const char *spec) { + const char *colon; size_t flen; char path[1024]; uint64_t line_u; @@ -1683,7 +2322,7 @@ static void dbg_cmd_list(DbgState* s, const char* spec) { uint64_t pc; int rc; CfreeFileData fd; - const CfreeFileIO* io; + const CfreeFileIO *io; if (!s->dwarf) { driver_errf(DBG_TOOL, "no DWARF: cannot resolve %s", spec); @@ -1720,8 +2359,9 @@ static void dbg_cmd_list(DbgState* s, const char* spec) { return; } if (rc == 3) { - driver_errf(DBG_TOOL, "ambiguous: %s:%u matches multiple files; " - "use a longer path suffix", + driver_errf(DBG_TOOL, + "ambiguous: %s:%u matches multiple files; " + "use a longer path suffix", path, (uint32_t)line_u); return; } @@ -1746,30 +2386,32 @@ static void dbg_cmd_list(DbgState* s, const char* spec) { uint32_t lo = target > DBG_LIST_CTX ? target - DBG_LIST_CTX : 1; uint32_t hi = target + DBG_LIST_CTX; uint32_t cur = 1; - const uint8_t* p = fd.data; - const uint8_t* end = fd.data + fd.size; - const uint8_t* line_start = p; + const uint8_t *p = fd.data; + const uint8_t *end = fd.data + fd.size; + const uint8_t *line_start = p; while (p <= end) { int eol = (p == end) || (*p == '\n'); if (eol) { if (cur >= lo && cur <= hi) { size_t len = (size_t)(p - line_start); driver_printf("%6u%s %.*s\n", cur, cur == target ? " >" : " ", - (int)len, (const char*)line_start); + (int)len, (const char *)line_start); } ++cur; - if (p == end) break; + if (p == end) + break; line_start = p + 1; } ++p; } if (cur <= target) { - driver_errf(DBG_TOOL, "file has only %u lines; %u requested", - cur - 1u, target); + driver_errf(DBG_TOOL, "file has only %u lines; %u requested", cur - 1u, + target); } } - if (io->release) io->release(io->user, &fd); + if (io->release) + io->release(io->user, &fd); } /* ============================================================ @@ -1780,7 +2422,7 @@ static void dbg_cmd_list(DbgState* s, const char* spec) { * is used when no skip/cap is in effect; otherwise the spec form. The * driver does not yet wire conditions, but the spec callback slot is left * NULL so this remains forward-compatible. */ -static int dbg_bp_arm(DbgState* s, Bp* b) { +static int dbg_bp_arm(DbgState *s, Bp *b) { if (b->skip_count == 0 && b->max_hits == 0) { return cfree_jit_session_breakpoint_set(s->session, b->addr, &b->session_id); @@ -1797,19 +2439,21 @@ static int dbg_bp_arm(DbgState* s, Bp* b) { } } -static void dbg_cmd_break(DbgState* s, const char* spec) { +static void dbg_cmd_break(DbgState *s, const char *spec) { BpKind kind; uint64_t addr; - Bp* b; + Bp *b; if (!*spec) { driver_errf(DBG_TOOL, "usage: b <0xADDR | sym[+off] | file.c:line>"); return; } - if (dbg_resolve_loc(s, spec, &kind, &addr) != 0) return; + if (dbg_resolve_loc(s, spec, &kind, &addr) != 0) + return; b = dbg_bp_grow(s); - if (!b) return; + if (!b) + return; { Bp z = {0}; @@ -1838,7 +2482,7 @@ static void dbg_cmd_break(DbgState* s, const char* spec) { b->session_id ? "" : " [disarmed]"); } -static void dbg_cmd_info_b(DbgState* s) { +static void dbg_cmd_info_b(DbgState *s) { uint32_t i; if (s->nbps == 0) { driver_printf("No breakpoints.\n"); @@ -1846,7 +2490,7 @@ static void dbg_cmd_info_b(DbgState* s) { } driver_printf("Num Enb Address Skip Max Spec\n"); for (i = 0; i < s->nbps; ++i) { - Bp* b = &s->bps[i]; + Bp *b = &s->bps[i]; driver_printf("%-4d %-4s 0x%-18llx %-6llu %-6llu %s%s\n", b->id, b->enabled ? "y" : "n", (unsigned long long)b->addr, (unsigned long long)b->skip_count, @@ -1855,8 +2499,8 @@ static void dbg_cmd_info_b(DbgState* s) { } } -static void dbg_cmd_ignore(DbgState* s, int id, uint64_t count) { - Bp* b = dbg_bp_find(s, id); +static void dbg_cmd_ignore(DbgState *s, int id, uint64_t count) { + Bp *b = dbg_bp_find(s, id); if (!b) { driver_errf(DBG_TOOL, "no breakpoint %d", id); return; @@ -1876,14 +2520,14 @@ static void dbg_cmd_ignore(DbgState* s, int id, uint64_t count) { (unsigned long long)count); } -static void dbg_cmd_delete(DbgState* s, int id) { +static void dbg_cmd_delete(DbgState *s, int id) { if (dbg_bp_remove(s, id) != 0) { driver_errf(DBG_TOOL, "no breakpoint %d", id); } } -static void dbg_cmd_set_enabled(DbgState* s, int id, int enable) { - Bp* b = dbg_bp_find(s, id); +static void dbg_cmd_set_enabled(DbgState *s, int id, int enable) { + Bp *b = dbg_bp_find(s, id); if (!b) { driver_errf(DBG_TOOL, "no breakpoint %d", id); return; @@ -1920,6 +2564,8 @@ static void dbg_cmd_help(void) { " n, next step to next source line (over calls)\n" " finish run until current frame returns\n" " jit [LANG|NAME] { ... } compile and append a frontend snippet\n" + " edit [LANG|NAME], e [...] edit and append a frontend snippet\n" + " expr C_EXPR | expr { ... } compile and call a C thunk\n" " call SYMBOL [INT_OR_ADDR...] call function, returns uint64_t\n" " jump ADDR set PC to ADDR (no resume)\n" " bt, backtrace print stack trace with arguments\n" @@ -1940,6 +2586,14 @@ static void dbg_cmd_help(void) { " info variables [PATTERN] list JIT globals matching PATTERN\n"); } +static CfreeLanguage dbg_default_language_from_inputs(const DbgOpts *o) { + if (o->inputs.nsources) + return cfree_language_for_path(o->inputs.sources[0]); + if (o->inputs.nsource_memory) + return o->inputs.source_memory[0].lang; + return CFREE_LANG_C; +} + /* ============================================================ * Tokenizer / dispatch * ============================================================ */ @@ -1948,30 +2602,34 @@ static void dbg_cmd_help(void) { * Returns the start of the next region (i.e. the rest of the line, with * its own leading whitespace skipped). The input buffer is mutated: * the byte after the first word is replaced with a NUL. */ -static char* dbg_take_word(char* line, char** word_out) { - char* p = line; - char* w; - while (*p && dbg_isspace((unsigned char)*p)) ++p; +static char *dbg_take_word(char *line, char **word_out) { + char *p = line; + char *w; + while (*p && dbg_isspace((unsigned char)*p)) + ++p; if (!*p) { *word_out = p; return p; } w = p; - while (*p && !dbg_isspace((unsigned char)*p)) ++p; + while (*p && !dbg_isspace((unsigned char)*p)) + ++p; if (*p) { *p = '\0'; ++p; } - while (*p && dbg_isspace((unsigned char)*p)) ++p; + while (*p && dbg_isspace((unsigned char)*p)) + ++p; *word_out = w; return p; } -static int dbg_dispatch(DbgState* s, char* line) { - char* cmd; - char* rest = dbg_take_word(line, &cmd); +static int dbg_dispatch(DbgState *s, char *line) { + char *cmd; + char *rest = dbg_take_word(line, &cmd); - if (!*cmd) return 0; /* blank line */ + if (!*cmd) + return 0; /* blank line */ if (driver_streq(cmd, "h") || driver_streq(cmd, "help")) { dbg_cmd_help(); @@ -2013,6 +2671,18 @@ static int dbg_dispatch(DbgState* s, char* line) { dbg_cmd_jit(s, rest); return 0; } + if (driver_streq(cmd, "edit") || driver_streq(cmd, "e")) { + dbg_cmd_edit(s, rest); + return 0; + } + if (driver_streq(cmd, "expr")) { + if (!s->session) { + driver_errf(DBG_TOOL, "no JIT session"); + return 0; + } + dbg_cmd_expr(s, rest); + return 0; + } if (driver_streq(cmd, "call")) { if (!s->session) { driver_errf(DBG_TOOL, "no JIT session"); @@ -2027,13 +2697,13 @@ static int dbg_dispatch(DbgState* s, char* line) { return 0; } if (driver_streq(cmd, "b") || driver_streq(cmd, "break")) { - char* loc; + char *loc; dbg_take_word(rest, &loc); dbg_cmd_break(s, loc); return 0; } if (driver_streq(cmd, "info")) { - char* what; + char *what; rest = dbg_take_word(rest, &what); if (driver_streq(what, "b") || driver_streq(what, "break") || driver_streq(what, "breakpoints")) { @@ -2045,11 +2715,11 @@ static int dbg_dispatch(DbgState* s, char* line) { } else if (driver_streq(what, "args")) { dbg_cmd_info_vars(s, 1u << CFREE_DVR_ARG, "args"); } else if (driver_streq(what, "functions") || driver_streq(what, "func")) { - char* pat; + char *pat; dbg_take_word(rest, &pat); dbg_cmd_info_syms(s, CFREE_SK_FUNC, *pat ? pat : NULL); } else if (driver_streq(what, "variables") || driver_streq(what, "var")) { - char* pat; + char *pat; dbg_take_word(rest, &pat); dbg_cmd_info_syms(s, CFREE_SK_OBJ, *pat ? pat : NULL); } else { @@ -2058,8 +2728,8 @@ static int dbg_dispatch(DbgState* s, char* line) { return 0; } if (driver_streq(cmd, "set")) { - char* name; - char* val_s; + char *name; + char *val_s; uint64_t v; size_t used; rest = dbg_take_word(rest, &name); @@ -2089,7 +2759,7 @@ static int dbg_dispatch(DbgState* s, char* line) { return 0; } if (driver_streq(cmd, "jump") || driver_streq(cmd, "j")) { - char* addr_s; + char *addr_s; uint64_t addr; size_t used; dbg_take_word(rest, &addr_s); @@ -2106,8 +2776,8 @@ static int dbg_dispatch(DbgState* s, char* line) { return 0; } if (driver_streq(cmd, "ignore")) { - char* id_s; - char* cnt_s; + char *id_s; + char *cnt_s; uint64_t id; uint64_t cnt; size_t used; @@ -2131,7 +2801,7 @@ static int dbg_dispatch(DbgState* s, char* line) { return 0; } if (driver_streq(cmd, "d") || driver_streq(cmd, "delete")) { - char* arg; + char *arg; uint64_t id; size_t used; dbg_take_word(rest, &arg); @@ -2148,7 +2818,7 @@ static int dbg_dispatch(DbgState* s, char* line) { return 0; } if (driver_streq(cmd, "enable") || driver_streq(cmd, "disable")) { - char* arg; + char *arg; uint64_t id; size_t used; dbg_take_word(rest, &arg); @@ -2161,7 +2831,7 @@ static int dbg_dispatch(DbgState* s, char* line) { return 0; } if (driver_streq(cmd, "p") || driver_streq(cmd, "print")) { - char* name; + char *name; dbg_take_word(rest, &name); if (!*name) { driver_errf(DBG_TOOL, "usage: p <name>"); @@ -2171,7 +2841,7 @@ static int dbg_dispatch(DbgState* s, char* line) { return 0; } if (driver_streq(cmd, "list") || driver_streq(cmd, "l")) { - char* loc; + char *loc; dbg_take_word(rest, &loc); if (!*loc) { driver_errf(DBG_TOOL, "usage: list file:line"); @@ -2181,8 +2851,8 @@ static int dbg_dispatch(DbgState* s, char* line) { return 0; } if (driver_streq(cmd, "x") || driver_streq(cmd, "examine")) { - char* addr_s; - char* count_s; + char *addr_s; + char *count_s; uint64_t addr; uint64_t count = 16; size_t used; @@ -2216,7 +2886,7 @@ static int dbg_dispatch(DbgState* s, char* line) { * REPL * ============================================================ */ -static void dbg_repl(DbgState* s) { +static void dbg_repl(DbgState *s) { char line[LINE_CAP]; driver_printf("cfree dbg — 'h' for help, 'q' to quit\n"); for (;;) { @@ -2236,7 +2906,8 @@ static void dbg_repl(DbgState* s) { driver_printf("\n"); continue; } - if (dbg_dispatch(s, line)) return; + if (dbg_dispatch(s, line)) + return; } } @@ -2244,11 +2915,11 @@ static void dbg_repl(DbgState* s) { * Top-level entry * ============================================================ */ -int driver_dbg(int argc, char** argv) { +int driver_dbg(int argc, char **argv) { DriverEnv env; DbgOpts o = {0}; - CfreePipeline* pipe = NULL; - CfreeJit* jit = NULL; + CfreePipeline *pipe = NULL; + CfreeJit *jit = NULL; DbgState st = {0}; CfreeEnv cenv; CfreeTarget target; @@ -2290,6 +2961,8 @@ int driver_dbg(int argc, char** argv) { st.pipe = pipe; dbg_fill_compile_options(&o, &st.copts); st.jit = jit; + st.default_jit_lang = dbg_default_language_from_inputs(&o); + st.default_jit_name = dbg_jit_default_name(st.default_jit_lang); st.prog_argc = (int)o.prog_argc; st.prog_argv = o.prog_argv; @@ -2323,8 +2996,10 @@ int driver_dbg(int argc, char** argv) { dbg_repl(&st); dbg_bps_release_all(&st); - if (st.dwarf) cfree_dwarf_close(st.dwarf); - if (st.session) cfree_jit_session_free(st.session); + if (st.dwarf) + cfree_dwarf_close(st.dwarf); + if (st.session) + cfree_jit_session_free(st.session); cfree_jit_free(jit); driver_pipeline_free(pipe); dbg_options_release(&o); diff --git a/driver/driver.h b/driver/driver.h @@ -22,17 +22,17 @@ typedef enum DriverTool { } DriverTool; /* Multi-call entry: dispatches by argv[0] basename (or argv[1] fallback). */ -int driver_main(int argc, char** argv); +int driver_main(int argc, char **argv); /* Direct entry per tool. Each lives in driver/<tool>.c. */ -int driver_cc(int argc, char** argv); -int driver_as(int argc, char** argv); -int driver_ld(int argc, char** argv); -int driver_ar(int argc, char** argv); -int driver_objdump(int argc, char** argv); -int driver_dbg(int argc, char** argv); -int driver_run(int argc, char** argv); -int driver_emu(int argc, char** argv); +int driver_cc(int argc, char **argv); +int driver_as(int argc, char **argv); +int driver_ld(int argc, char **argv); +int driver_ar(int argc, char **argv); +int driver_objdump(int argc, char **argv); +int driver_dbg(int argc, char **argv); +int driver_run(int argc, char **argv); +int driver_emu(int argc, char **argv); /* Per-tool help printers. Write a multi-section help text to stdout and * return. The tool entry-points call these when invoked with no args, -h, @@ -56,48 +56,48 @@ void driver_help_top(void); * as a help request by every tool except objdump (where it means * "section headers"); callers that want to honour it should test it * explicitly via driver_argv_wants_help(..., 1). */ -int driver_is_help_flag(const char* arg); +int driver_is_help_flag(const char *arg); /* Scan argv[1..argc-1] for a help request, returning 1 on a hit. Triggers * on "--help" / "-help" always, and on "-h" when accept_short_h is set. * Tool entries also treat argc < 2 (no positional or option args) as a * help request — the convention is "no args means show help". */ -int driver_argv_wants_help(int argc, char** argv, int accept_short_h); +int driver_argv_wants_help(int argc, char **argv, int accept_short_h); /* Shared host environment used by every tool that calls into libcfree. * driver_env_init wires up the libc-backed heap, the stderr diag sink, and * a POSIX file_io implementation (open/read/write on real paths). It is * the single piece of glue that turns "the host" into a CfreeEnv. */ typedef struct DriverEnv { - CfreeHeap* heap; - CfreeDiagSink* diag; + CfreeHeap *heap; + CfreeDiagSink *diag; CfreeFileIO file_io; - const CfreeExecMem* execmem; - const CfreeDbgOs* dbg_os; /* NULL unless `cfree dbg` paths run */ - const CfreeJitTls* jit_tls; /* NULL unless `cfree run` w/ TLV paths run */ - const CfreeMetrics* metrics; /* optional scoped metrics sink */ - int64_t now; /* unix seconds; -1 = unknown */ + const CfreeExecMem *execmem; + const CfreeDbgOs *dbg_os; /* NULL unless `cfree dbg` paths run */ + const CfreeJitTls *jit_tls; /* NULL unless `cfree run` w/ TLV paths run */ + const CfreeMetrics *metrics; /* optional scoped metrics sink */ + int64_t now; /* unix seconds; -1 = unknown */ } DriverEnv; -void driver_env_init(DriverEnv*); -void driver_env_fini(DriverEnv*); -CfreeEnv driver_env_to_cfree(const DriverEnv*); +void driver_env_init(DriverEnv *); +void driver_env_fini(DriverEnv *); +CfreeEnv driver_env_to_cfree(const DriverEnv *); /* Tells the stderr diag sink which compiler to use when resolving * SrcLoc.file_id to a path. The driver_{compiler,pipeline}_{new,free} * helpers below already manage this; call this directly only when you * hand a CfreeCompiler from outside those helpers (none today). */ -void driver_diag_set_compiler(CfreeCompiler*); +void driver_diag_set_compiler(CfreeCompiler *); /* Lifecycle helpers around cfree_{compiler,pipeline}_{new,free}. * Identical to the raw entries except they register/clear the active * compiler with the stderr diag sink, so diagnostics can resolve * loc.file_id to its registered path. Tools should always go through * these inside the driver. */ -CfreeCompiler* driver_compiler_new(CfreeTarget, const CfreeEnv*); -void driver_compiler_free(CfreeCompiler*); -CfreePipeline* driver_pipeline_new(CfreeTarget, const CfreeEnv*); -void driver_pipeline_free(CfreePipeline*); +CfreeCompiler *driver_compiler_new(CfreeTarget, const CfreeEnv *); +void driver_compiler_free(CfreeCompiler *); +CfreePipeline *driver_pipeline_new(CfreeTarget, const CfreeEnv *); +void driver_pipeline_free(CfreePipeline *); /* Default target used by tools that don't expose a target-selection flag * yet. v1: native-looking host target (chosen at compile time). */ @@ -111,7 +111,7 @@ CfreeTarget driver_host_target(void); * freestanding. Sets arch/os/obj/ptr_size/ptr_align/big_endian; pic and * code_model are left at their defaults. Returns 0 on success, nonzero on * unrecognized arch or NULL inputs. */ -int driver_target_from_triple(const char* triple, CfreeTarget* out); +int driver_target_from_triple(const char *triple, CfreeTarget *out); /* ---------------------------------------------------------------------- * Host-shim helpers @@ -127,39 +127,39 @@ int driver_target_from_triple(const char* triple, CfreeTarget* out); /* String predicates and lookups. driver_streq / driver_strneq return * non-zero when the strings (or first n bytes) match — sense-flipped * from libc's strcmp so call sites read naturally. */ -int driver_streq(const char* a, const char* b); -int driver_strneq(const char* a, const char* b, size_t n); -size_t driver_strlen(const char* s); -const char* driver_strchr(const char* s, int c); -const char* driver_basename(const char* path); -int driver_has_suffix(const char* s, const char* suffix); +int driver_streq(const char *a, const char *b); +int driver_strneq(const char *a, const char *b, size_t n); +size_t driver_strlen(const char *s); +const char *driver_strchr(const char *s, int c); +const char *driver_basename(const char *path); +int driver_has_suffix(const char *s, const char *suffix); /* Memory. Allocations route through DriverEnv.heap; release returns the * size used at allocation (so the heap implementation can track usage). */ -void* driver_alloc(DriverEnv*, size_t); -void* driver_alloc_zeroed(DriverEnv*, size_t); -void driver_free(DriverEnv*, void* p, size_t); -void driver_memcpy(void* dst, const void* src, size_t n); +void *driver_alloc(DriverEnv *, size_t); +void *driver_alloc_zeroed(DriverEnv *, size_t); +void driver_free(DriverEnv *, void *p, size_t); +void driver_memcpy(void *dst, const void *src, size_t n); /* Opens a Writer that writes to stdout (fd 1). close frees the struct but * does not close the fd. */ -CfreeWriter* driver_stdout_writer(DriverEnv*); +CfreeWriter *driver_stdout_writer(DriverEnv *); /* Test whether `path` names an existing filesystem entry (any type). * Returns nonzero on existence, zero otherwise. Used by library-path * resolution; intentionally distinct from read_all so candidate-search * loops don't slurp file contents on a hit. */ -int driver_path_exists(const char* path); +int driver_path_exists(const char *path); /* Diagnostic printing to host stderr. Format is `"<tool>: <fmt>\n"`. */ -void driver_errf(const char* tool, const char* fmt, ...); +void driver_errf(const char *tool, const char *fmt, ...); /* Raw hosted stderr log. Used by optional metrics so libcfree stays callback- * only and freestanding. */ -void driver_logf(const char* fmt, ...); +void driver_logf(const char *fmt, ...); /* Formatted output to stdout. */ -void driver_printf(const char* fmt, ...); +void driver_printf(const char *fmt, ...); /* Monotonic host time in nanoseconds, or 0 if unavailable. */ uint64_t driver_now_ns(void); @@ -167,13 +167,20 @@ uint64_t driver_now_ns(void); /* Lookup a process environment variable; returns NULL if unset. The returned * pointer aliases libc-owned storage and is valid until the next setenv/ * putenv from any caller. */ -const char* driver_getenv(const char* name); +const char *driver_getenv(const char *name); /* Read all of stdin into a freshly-allocated buffer. On success returns 1 * and stores the buffer/size in out_data/out_size; the caller frees via * driver_free(env, *out_data, *out_size). Returns 0 on read failure or * allocation failure. */ -int driver_read_stdin(DriverEnv*, uint8_t** out_data, size_t* out_size); +int driver_read_stdin(DriverEnv *, uint8_t **out_data, size_t *out_size); + +/* Open a temporary file in $VISUAL, then $EDITOR, then vi. `suffix` should + * include the leading dot when a language-specific extension is useful. + * On success, returns the edited bytes in a freshly allocated buffer that the + * caller frees with driver_free(env, *out_data, *out_size). */ +int driver_edit_temp(DriverEnv *, const char *suffix, const uint8_t *initial, + size_t initial_size, uint8_t **out_data, size_t *out_size); /* Path-shaped input loader. Wraps env.file_io.read_all so each tool can * convert a list of paths to a list of CfreeBytesInput without re-implementing @@ -187,9 +194,9 @@ typedef struct DriverLoad { int loaded; } DriverLoad; -int driver_load_bytes(const CfreeFileIO*, const char* tool, const char* path, - DriverLoad* out, CfreeBytesInput* in); -void driver_release_bytes(const CfreeFileIO*, DriverLoad*); +int driver_load_bytes(const CfreeFileIO *, const char *tool, const char *path, + DriverLoad *out, CfreeBytesInput *in); +void driver_release_bytes(const CfreeFileIO *, DriverLoad *); /* Read one line from stdin into `buf` (cap >= 2). Strips the trailing * newline and NUL-terminates. Returns the line length on success, 0 at @@ -197,7 +204,7 @@ void driver_release_bytes(const CfreeFileIO*, DriverLoad*); * interrupted by a signal (caller should print a fresh prompt and * retry). Over-long lines are truncated to cap-1 bytes; the remainder * up to the next newline is consumed silently. */ -int driver_read_line(char* buf, size_t cap); +int driver_read_line(char *buf, size_t cap); /* Flush the host stdout. The dbg REPL prompt has no trailing newline, so * without an explicit flush the prompt stays buffered until the next @@ -209,7 +216,7 @@ void driver_flush_stdout(void); * forward Ctrl-C into cfree_jit_session_interrupt while the worker is * running, and to restore SIG_DFL while sitting at the REPL prompt so * Ctrl-C terminates the program normally. Returns 0 on success. */ -int driver_install_sigint(void (*cb)(void*), void* user); +int driver_install_sigint(void (*cb)(void *), void *user); void driver_restore_sigint(void); /* Host-symbol resolver for JIT extern_resolver. Looks up `name` via @@ -217,6 +224,6 @@ void driver_restore_sigint(void); * `user` is ignored and may be NULL. Wired into `cfree run` so JITed code * can call libc symbols (printf, malloc, ...) without an explicit linker * step. */ -void* driver_dlsym_resolver(void* user, const char* name); +void *driver_dlsym_resolver(void *user, const char *name); #endif diff --git a/driver/env.c b/driver/env.c @@ -27,6 +27,7 @@ #include <string.h> #include <sys/mman.h> #include <sys/stat.h> +#include <sys/wait.h> #include <time.h> #include <ucontext.h> #include <unistd.h> @@ -83,13 +84,13 @@ /* ---------------- heap (libc-backed) ---------------- */ -static void* heap_libc_alloc(CfreeHeap* h, size_t size, size_t align) { +static void *heap_libc_alloc(CfreeHeap *h, size_t size, size_t align) { (void)h; (void)align; /* malloc satisfies all max_align_t alignments */ return size ? malloc(size) : NULL; } -static void* heap_libc_realloc(CfreeHeap* h, void* p, size_t old_size, +static void *heap_libc_realloc(CfreeHeap *h, void *p, size_t old_size, size_t new_size, size_t align) { (void)h; (void)old_size; @@ -97,7 +98,7 @@ static void* heap_libc_realloc(CfreeHeap* h, void* p, size_t old_size, return realloc(p, new_size); } -static void heap_libc_free(CfreeHeap* h, void* p, size_t size) { +static void heap_libc_free(CfreeHeap *h, void *p, size_t size) { (void)h; (void)size; free(p); @@ -112,16 +113,16 @@ static CfreeHeap g_heap_libc = { /* ---------------- diag sink (stderr) ---------------- */ -static const char* diag_label(CfreeDiagKind k) { +static const char *diag_label(CfreeDiagKind k) { switch (k) { - case CFREE_DIAG_NOTE: - return "note"; - case CFREE_DIAG_WARN: - return "warning"; - case CFREE_DIAG_ERROR: - return "error"; - case CFREE_DIAG_FATAL: - return "fatal"; + case CFREE_DIAG_NOTE: + return "note"; + case CFREE_DIAG_WARN: + return "warning"; + case CFREE_DIAG_ERROR: + return "error"; + case CFREE_DIAG_FATAL: + return "fatal"; } return "diag"; } @@ -130,17 +131,17 @@ static const char* diag_label(CfreeDiagKind k) { * diag sink can resolve loc.file_id to the source's spelling (path or * memory-input label). NULL falls back to the numeric `<file:%u>` form, * which is what callers see before they've registered a compiler. */ -static CfreeCompiler* g_diag_active_compiler; +static CfreeCompiler *g_diag_active_compiler; -void driver_diag_set_compiler(CfreeCompiler* c) { g_diag_active_compiler = c; } +void driver_diag_set_compiler(CfreeCompiler *c) { g_diag_active_compiler = c; } /* driver_{compiler,pipeline}_{new,free}: thin wrappers around the libcfree * lifecycle entries that register the active compiler with the diag sink * and clear it on free. Driver tools call these instead of the raw * cfree_* calls so a fatal diagnostic from libcfree prints the source * file name rather than a bare numeric file_id. */ -CfreeCompiler* driver_compiler_new(CfreeTarget t, const CfreeEnv* env) { - CfreeCompiler* c = cfree_compiler_new(t, env); +CfreeCompiler *driver_compiler_new(CfreeTarget t, const CfreeEnv *env) { + CfreeCompiler *c = cfree_compiler_new(t, env); if (c) { cfree_c_register(c); (void)cfree_register_frontend(c, CFREE_LANG_TOY, cfree_toy_compile); @@ -149,16 +150,18 @@ CfreeCompiler* driver_compiler_new(CfreeTarget t, const CfreeEnv* env) { return c; } -void driver_compiler_free(CfreeCompiler* c) { - if (!c) return; - if (g_diag_active_compiler == c) driver_diag_set_compiler(NULL); +void driver_compiler_free(CfreeCompiler *c) { + if (!c) + return; + if (g_diag_active_compiler == c) + driver_diag_set_compiler(NULL); cfree_compiler_free(c); } -CfreePipeline* driver_pipeline_new(CfreeTarget t, const CfreeEnv* env) { - CfreePipeline* p = cfree_pipeline_new(t, env); +CfreePipeline *driver_pipeline_new(CfreeTarget t, const CfreeEnv *env) { + CfreePipeline *p = cfree_pipeline_new(t, env); if (p) { - CfreeCompiler* c = cfree_pipeline_compiler(p); + CfreeCompiler *c = cfree_pipeline_compiler(p); cfree_c_register(c); (void)cfree_register_frontend(c, CFREE_LANG_TOY, cfree_toy_compile); driver_diag_set_compiler(c); @@ -166,22 +169,22 @@ CfreePipeline* driver_pipeline_new(CfreeTarget t, const CfreeEnv* env) { return p; } -void driver_pipeline_free(CfreePipeline* p) { - if (!p) return; +void driver_pipeline_free(CfreePipeline *p) { + if (!p) + return; if (g_diag_active_compiler == cfree_pipeline_compiler(p)) driver_diag_set_compiler(NULL); cfree_pipeline_free(p); } -static void diag_stderr_emit(CfreeDiagSink* s, CfreeDiagKind k, CfreeSrcLoc loc, - const char* fmt, va_list ap) { +static void diag_stderr_emit(CfreeDiagSink *s, CfreeDiagKind k, CfreeSrcLoc loc, + const char *fmt, va_list ap) { (void)s; if (loc.file_id || loc.line) { - const char* name = cfree_compiler_file_name(g_diag_active_compiler, - loc.file_id); + const char *name = + cfree_compiler_file_name(g_diag_active_compiler, loc.file_id); if (name && *name) { - fprintf(stderr, "%s:%u:%u: %s: ", name, loc.line, loc.col, - diag_label(k)); + fprintf(stderr, "%s:%u:%u: %s: ", name, loc.line, loc.col, diag_label(k)); } else { fprintf(stderr, "<file:%u>:%u:%u: %s: ", loc.file_id, loc.line, loc.col, diag_label(k)); @@ -204,9 +207,12 @@ static CfreeDiagSink g_diag_stderr = { static int cfree_to_posix_prot(int prot) { int p = 0; - if (prot & CFREE_PROT_READ) p |= PROT_READ; - if (prot & CFREE_PROT_WRITE) p |= PROT_WRITE; - if (prot & CFREE_PROT_EXEC) p |= PROT_EXEC; + if (prot & CFREE_PROT_READ) + p |= PROT_READ; + if (prot & CFREE_PROT_WRITE) + p |= PROT_WRITE; + if (prot & CFREE_PROT_EXEC) + p |= PROT_EXEC; return p; } @@ -215,8 +221,8 @@ static int cfree_to_posix_prot(int prot) { * Apple stores nothing extra; Linux stores the memfd-backed write alias * size so munmap can release the runtime alias separately. */ typedef struct ExecMemToken { - void* write_addr; - void* runtime_addr; + void *write_addr; + void *runtime_addr; size_t size; } ExecMemToken; @@ -226,21 +232,23 @@ typedef struct ExecMemToken { * reservations (write == runtime) are not registered. JITs typically hold * 1-2 reservations live so a linked list keeps the lookup trivial. */ typedef struct ExecDualNode { - void* write_base; - void* runtime_base; + void *write_base; + void *runtime_base; size_t size; - struct ExecDualNode* next; + struct ExecDualNode *next; } ExecDualNode; -static ExecDualNode* g_jit_dual_map; +static ExecDualNode *g_jit_dual_map; static pthread_mutex_t g_jit_dual_map_mu = PTHREAD_MUTEX_INITIALIZER; -static void exec_dual_register(void* write_base, void* runtime_base, +static void exec_dual_register(void *write_base, void *runtime_base, size_t size) { - ExecDualNode* n; - if (write_base == runtime_base) return; - n = (ExecDualNode*)malloc(sizeof(*n)); - if (!n) return; /* registry is best-effort; lookup will fail open */ + ExecDualNode *n; + if (write_base == runtime_base) + return; + n = (ExecDualNode *)malloc(sizeof(*n)); + if (!n) + return; /* registry is best-effort; lookup will fail open */ n->write_base = write_base; n->runtime_base = runtime_base; n->size = size; @@ -250,12 +258,12 @@ static void exec_dual_register(void* write_base, void* runtime_base, pthread_mutex_unlock(&g_jit_dual_map_mu); } -static void exec_dual_unregister(void* runtime_base) { - ExecDualNode** pp; +static void exec_dual_unregister(void *runtime_base) { + ExecDualNode **pp; pthread_mutex_lock(&g_jit_dual_map_mu); for (pp = &g_jit_dual_map; *pp; pp = &(*pp)->next) { if ((*pp)->runtime_base == runtime_base) { - ExecDualNode* dead = *pp; + ExecDualNode *dead = *pp; *pp = dead->next; free(dead); break; @@ -264,14 +272,14 @@ static void exec_dual_unregister(void* runtime_base) { pthread_mutex_unlock(&g_jit_dual_map_mu); } -static int exec_dual_lookup(void* runtime_addr, size_t n, void** write_out) { - ExecDualNode* cur; +static int exec_dual_lookup(void *runtime_addr, size_t n, void **write_out) { + ExecDualNode *cur; uintptr_t a = (uintptr_t)runtime_addr; pthread_mutex_lock(&g_jit_dual_map_mu); for (cur = g_jit_dual_map; cur; cur = cur->next) { uintptr_t base = (uintptr_t)cur->runtime_base; if (a >= base && a + n <= base + cur->size) { - *write_out = (void*)((uintptr_t)cur->write_base + (a - base)); + *write_out = (void *)((uintptr_t)cur->write_base + (a - base)); pthread_mutex_unlock(&g_jit_dual_map_mu); return 0; } @@ -280,10 +288,11 @@ static int exec_dual_lookup(void* runtime_addr, size_t n, void** write_out) { return 1; } -static int execmem_reserve_single(size_t size, CfreeExecMemRegion* out) { - void* p = +static int execmem_reserve_single(size_t size, CfreeExecMemRegion *out) { + void *p = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); - if (p == MAP_FAILED) return 1; + if (p == MAP_FAILED) + return 1; out->write = p; out->runtime = p; out->size = size; @@ -292,15 +301,16 @@ static int execmem_reserve_single(size_t size, CfreeExecMemRegion* out) { } #if DRIVER_DUAL_APPLE -static int execmem_reserve_dual_apple(size_t size, CfreeExecMemRegion* out) { +static int execmem_reserve_dual_apple(size_t size, CfreeExecMemRegion *out) { /* 1) Allocate the writable backing via mmap. */ - void* w = + void *w = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); mach_vm_address_t r_addr = 0; vm_prot_t cur = 0, max = 0; kern_return_t kr; - ExecMemToken* tok; - if (w == MAP_FAILED) return 1; + ExecMemToken *tok; + if (w == MAP_FAILED) + return 1; /* 2) Create an alias mapping. copy=FALSE makes the new VA share the * same physical pages. We request VM_INHERIT_NONE so child @@ -317,26 +327,26 @@ static int execmem_reserve_dual_apple(size_t size, CfreeExecMemRegion* out) { /* 3) Drop the runtime alias to PROT_READ until protect() flips it. * No window of writable+executable: the write alias has W (no X), * the runtime alias has R only (no W, no X yet). */ - if (mprotect((void*)(uintptr_t)r_addr, size, PROT_READ) != 0) { - munmap((void*)(uintptr_t)r_addr, size); + if (mprotect((void *)(uintptr_t)r_addr, size, PROT_READ) != 0) { + munmap((void *)(uintptr_t)r_addr, size); munmap(w, size); return 1; } - tok = (ExecMemToken*)malloc(sizeof(*tok)); + tok = (ExecMemToken *)malloc(sizeof(*tok)); if (!tok) { - munmap((void*)(uintptr_t)r_addr, size); + munmap((void *)(uintptr_t)r_addr, size); munmap(w, size); return 1; } tok->write_addr = w; - tok->runtime_addr = (void*)(uintptr_t)r_addr; + tok->runtime_addr = (void *)(uintptr_t)r_addr; tok->size = size; - exec_dual_register(w, (void*)(uintptr_t)r_addr, size); + exec_dual_register(w, (void *)(uintptr_t)r_addr, size); out->write = w; - out->runtime = (void*)(uintptr_t)r_addr; + out->runtime = (void *)(uintptr_t)r_addr; out->size = size; out->token = tok; return 0; @@ -344,14 +354,15 @@ static int execmem_reserve_dual_apple(size_t size, CfreeExecMemRegion* out) { #endif #if DRIVER_DUAL_LINUX -static int execmem_reserve_dual_linux(size_t size, CfreeExecMemRegion* out) { +static int execmem_reserve_dual_linux(size_t size, CfreeExecMemRegion *out) { /* memfd_create gives us an anonymous fd; two mmaps of that fd alias * the same physical pages at distinct VAs. */ int fd = (int)syscall(SYS_memfd_create, "cfree-jit", 0u); - void* w; - void* r; - ExecMemToken* tok; - if (fd < 0) return 1; + void *w; + void *r; + ExecMemToken *tok; + if (fd < 0) + return 1; if (ftruncate(fd, (off_t)size) != 0) { close(fd); return 1; @@ -371,7 +382,7 @@ static int execmem_reserve_dual_linux(size_t size, CfreeExecMemRegion* out) { /* The fd is no longer needed once both aliases are mapped. */ close(fd); - tok = (ExecMemToken*)malloc(sizeof(*tok)); + tok = (ExecMemToken *)malloc(sizeof(*tok)); if (!tok) { munmap(r, size); munmap(w, size); @@ -391,10 +402,11 @@ static int execmem_reserve_dual_linux(size_t size, CfreeExecMemRegion* out) { } #endif -static int execmem_reserve(void* user, size_t size, int prot, - CfreeExecMemRegion* out) { +static int execmem_reserve(void *user, size_t size, int prot, + CfreeExecMemRegion *out) { (void)user; - if (!out || !size) return 1; + if (!out || !size) + return 1; if (prot & CFREE_PROT_EXEC) { #if DRIVER_DUAL_APPLE return execmem_reserve_dual_apple(size, out); @@ -409,21 +421,23 @@ static int execmem_reserve(void* user, size_t size, int prot, return execmem_reserve_single(size, out); } -static int execmem_protect(void* user, void* addr, size_t size, int prot) { +static int execmem_protect(void *user, void *addr, size_t size, int prot) { (void)user; return mprotect(addr, size, cfree_to_posix_prot(prot)); } -static void execmem_release(void* user, CfreeExecMemRegion* region) { +static void execmem_release(void *user, CfreeExecMemRegion *region) { (void)user; - if (!region || !region->size) return; + if (!region || !region->size) + return; if (region->token) { - ExecMemToken* tok = (ExecMemToken*)region->token; + ExecMemToken *tok = (ExecMemToken *)region->token; if (tok->runtime_addr && tok->runtime_addr != tok->write_addr) { exec_dual_unregister(tok->runtime_addr); munmap(tok->runtime_addr, tok->size); } - if (tok->write_addr) munmap(tok->write_addr, tok->size); + if (tok->write_addr) + munmap(tok->write_addr, tok->size); free(tok); } else if (region->write) { munmap(region->write, region->size); @@ -434,10 +448,10 @@ static void execmem_release(void* user, CfreeExecMemRegion* region) { region->token = NULL; } -static void execmem_flush_icache(void* user, void* addr, size_t size) { +static void execmem_flush_icache(void *user, void *addr, size_t size) { (void)user; #if defined(__aarch64__) || defined(__arm__) - __builtin___clear_cache((char*)addr, (char*)addr + size); + __builtin___clear_cache((char *)addr, (char *)addr + size); #else (void)addr; (void)size; @@ -465,7 +479,7 @@ static CfreeExecMem g_execmem_posix; /* page_size set in driver_env_init */ * signals_uninstall after restoring SIG_DFL. */ static CfreeDbgSignalOps g_dbg_ops; static int g_dbg_ops_set; -static void* g_dbg_session; +static void *g_dbg_session; static pthread_t g_dbg_worker_tid; static int g_dbg_worker_tid_valid; @@ -486,22 +500,23 @@ static __thread int g_guard_armed; typedef struct DbgThread { pthread_t tid; - void (*fn)(void*); - void* arg; + void (*fn)(void *); + void *arg; } DbgThread; -static void* dbg_thread_trampoline(void* p) { - DbgThread* t = (DbgThread*)p; +static void *dbg_thread_trampoline(void *p) { + DbgThread *t = (DbgThread *)p; t->fn(t->arg); return NULL; } -static int dbg_thread_start(void* user, void (*fn)(void*), void* arg, - void** thread_out) { - DbgThread* t; +static int dbg_thread_start(void *user, void (*fn)(void *), void *arg, + void **thread_out) { + DbgThread *t; (void)user; - t = (DbgThread*)malloc(sizeof(*t)); - if (!t) return 1; + t = (DbgThread *)malloc(sizeof(*t)); + if (!t) + return 1; t->fn = fn; t->arg = arg; if (pthread_create(&t->tid, NULL, dbg_thread_trampoline, t) != 0) { @@ -514,19 +529,21 @@ static int dbg_thread_start(void* user, void (*fn)(void*), void* arg, return 0; } -static void dbg_thread_join(void* user, void* thread) { - DbgThread* t = (DbgThread*)thread; +static void dbg_thread_join(void *user, void *thread) { + DbgThread *t = (DbgThread *)thread; (void)user; - if (!t) return; + if (!t) + return; pthread_join(t->tid, NULL); g_dbg_worker_tid_valid = 0; free(t); } -static int dbg_thread_interrupt(void* user, void* thread) { - DbgThread* t = (DbgThread*)thread; +static int dbg_thread_interrupt(void *user, void *thread) { + DbgThread *t = (DbgThread *)thread; (void)user; - if (!t) return 1; + if (!t) + return 1; return pthread_kill(t->tid, DBG_INTERRUPT_SIGNO) == 0 ? 0 : 1; } @@ -538,11 +555,12 @@ typedef struct DbgEvent { int signaled; } DbgEvent; -static void* dbg_event_new(void* user) { - DbgEvent* e; +static void *dbg_event_new(void *user) { + DbgEvent *e; (void)user; - e = (DbgEvent*)malloc(sizeof(*e)); - if (!e) return NULL; + e = (DbgEvent *)malloc(sizeof(*e)); + if (!e) + return NULL; if (pthread_mutex_init(&e->mu, NULL) != 0) { free(e); return NULL; @@ -556,20 +574,22 @@ static void* dbg_event_new(void* user) { return e; } -static void dbg_event_free(void* user, void* ev) { - DbgEvent* e = (DbgEvent*)ev; +static void dbg_event_free(void *user, void *ev) { + DbgEvent *e = (DbgEvent *)ev; (void)user; - if (!e) return; + if (!e) + return; pthread_cond_destroy(&e->cv); pthread_mutex_destroy(&e->mu); free(e); } -static void dbg_event_wait(void* user, void* ev) { - DbgEvent* e = (DbgEvent*)ev; +static void dbg_event_wait(void *user, void *ev) { + DbgEvent *e = (DbgEvent *)ev; (void)user; pthread_mutex_lock(&e->mu); - while (!e->signaled) pthread_cond_wait(&e->cv, &e->mu); + while (!e->signaled) + pthread_cond_wait(&e->cv, &e->mu); e->signaled = 0; pthread_mutex_unlock(&e->mu); } @@ -577,8 +597,8 @@ static void dbg_event_wait(void* user, void* ev) { /* pthread_cond_signal is not formally async-signal-safe per POSIX, but * it is in practice on glibc and Apple libc when callers manage the * signal mask carefully. LLDB and rr rely on the same pattern. */ -static void dbg_event_signal(void* user, void* ev) { - DbgEvent* e = (DbgEvent*)ev; +static void dbg_event_signal(void *user, void *ev) { + DbgEvent *e = (DbgEvent *)ev; (void)user; pthread_mutex_lock(&e->mu); e->signaled = 1; @@ -586,8 +606,8 @@ static void dbg_event_signal(void* user, void* ev) { pthread_mutex_unlock(&e->mu); } -static void dbg_event_reset(void* user, void* ev) { - DbgEvent* e = (DbgEvent*)ev; +static void dbg_event_reset(void *user, void *ev) { + DbgEvent *e = (DbgEvent *)ev; (void)user; pthread_mutex_lock(&e->mu); e->signaled = 0; @@ -600,38 +620,42 @@ static void dbg_event_reset(void* user, void* ev) { * in regs[31] of CfreeUnwindFrame.pc and sp lives in regs[31]. The DWARF * register numbering on aarch64 puts x0..x30 at 0..30, sp at 31. */ #if defined(__aarch64__) && defined(__APPLE__) -static void dbg_ucontext_to_frame(const ucontext_t* uc, CfreeUnwindFrame* f) { - const struct __darwin_arm_thread_state64* ss = &uc->uc_mcontext->__ss; +static void dbg_ucontext_to_frame(const ucontext_t *uc, CfreeUnwindFrame *f) { + const struct __darwin_arm_thread_state64 *ss = &uc->uc_mcontext->__ss; int i; - for (i = 0; i < 29; ++i) f->regs[i] = ss->__x[i]; + for (i = 0; i < 29; ++i) + f->regs[i] = ss->__x[i]; f->regs[29] = (uint64_t)ss->__fp; f->regs[30] = (uint64_t)ss->__lr; f->regs[31] = (uint64_t)ss->__sp; f->pc = (uint64_t)ss->__pc; f->cfa = (uint64_t)ss->__fp; /* DWARF CFI refines this in the session */ } -static void dbg_frame_to_ucontext(const CfreeUnwindFrame* f, ucontext_t* uc) { - struct __darwin_arm_thread_state64* ss = &uc->uc_mcontext->__ss; +static void dbg_frame_to_ucontext(const CfreeUnwindFrame *f, ucontext_t *uc) { + struct __darwin_arm_thread_state64 *ss = &uc->uc_mcontext->__ss; int i; - for (i = 0; i < 29; ++i) ss->__x[i] = f->regs[i]; + for (i = 0; i < 29; ++i) + ss->__x[i] = f->regs[i]; ss->__fp = f->regs[29]; ss->__lr = f->regs[30]; ss->__sp = f->regs[31]; ss->__pc = f->pc; } #elif defined(__aarch64__) && defined(__linux__) -static void dbg_ucontext_to_frame(const ucontext_t* uc, CfreeUnwindFrame* f) { - const mcontext_t* mc = &uc->uc_mcontext; +static void dbg_ucontext_to_frame(const ucontext_t *uc, CfreeUnwindFrame *f) { + const mcontext_t *mc = &uc->uc_mcontext; int i; - for (i = 0; i < 31; ++i) f->regs[i] = mc->regs[i]; + for (i = 0; i < 31; ++i) + f->regs[i] = mc->regs[i]; f->regs[31] = mc->sp; f->pc = mc->pc; f->cfa = mc->regs[29]; /* fp; CFI refines */ } -static void dbg_frame_to_ucontext(const CfreeUnwindFrame* f, ucontext_t* uc) { - mcontext_t* mc = &uc->uc_mcontext; +static void dbg_frame_to_ucontext(const CfreeUnwindFrame *f, ucontext_t *uc) { + mcontext_t *mc = &uc->uc_mcontext; int i; - for (i = 0; i < 31; ++i) mc->regs[i] = f->regs[i]; + for (i = 0; i < 31; ++i) + mc->regs[i] = f->regs[i]; mc->sp = f->regs[31]; mc->pc = f->pc; } @@ -639,8 +663,8 @@ static void dbg_frame_to_ucontext(const CfreeUnwindFrame* f, ucontext_t* uc) { #error "cfree dbg v1 supports only aarch64 on macOS or Linux" #endif -static void dbg_signal_handler(int signo, siginfo_t* si, void* ucv) { - ucontext_t* uc = (ucontext_t*)ucv; +static void dbg_signal_handler(int signo, siginfo_t *si, void *ucv) { + ucontext_t *uc = (ucontext_t *)ucv; CfreeUnwindFrame frame; int rc; (void)si; @@ -686,12 +710,13 @@ static void dbg_signal_handler(int signo, siginfo_t* si, void* ucv) { dbg_frame_to_ucontext(&frame, uc); } -static int dbg_signals_install(void* user, const CfreeDbgSignalOps* ops, - void* session) { +static int dbg_signals_install(void *user, const CfreeDbgSignalOps *ops, + void *session) { struct sigaction sa; int i; (void)user; - if (g_dbg_installed) return 1; + if (g_dbg_installed) + return 1; g_dbg_ops = *ops; g_dbg_ops_set = 1; g_dbg_session = session; @@ -702,13 +727,15 @@ static int dbg_signals_install(void* user, const CfreeDbgSignalOps* ops, sigemptyset(&sa.sa_mask); /* Block our signal cohort during the handler so nested faults from * the cond-wait critical region don't recurse. */ - for (i = 0; i < DBG_NSIGS; ++i) sigaddset(&sa.sa_mask, g_dbg_signos[i]); + for (i = 0; i < DBG_NSIGS; ++i) + sigaddset(&sa.sa_mask, g_dbg_signos[i]); for (i = 0; i < DBG_NSIGS; ++i) { if (sigaction(g_dbg_signos[i], &sa, &g_dbg_prev_sa[i]) != 0) { /* Roll back what we installed. */ int j; - for (j = 0; j < i; ++j) sigaction(g_dbg_signos[j], &g_dbg_prev_sa[j], NULL); + for (j = 0; j < i; ++j) + sigaction(g_dbg_signos[j], &g_dbg_prev_sa[j], NULL); memset(&g_dbg_ops, 0, sizeof(g_dbg_ops)); g_dbg_ops_set = 0; g_dbg_session = NULL; @@ -719,10 +746,11 @@ static int dbg_signals_install(void* user, const CfreeDbgSignalOps* ops, return 0; } -static void dbg_signals_uninstall(void* user) { +static void dbg_signals_uninstall(void *user) { int i; (void)user; - if (!g_dbg_installed) return; + if (!g_dbg_installed) + return; for (i = 0; i < DBG_NSIGS; ++i) sigaction(g_dbg_signos[i], &g_dbg_prev_sa[i], NULL); g_dbg_installed = 0; @@ -740,10 +768,11 @@ static size_t dbg_page_ceil(size_t v, size_t pg) { } #endif -static int dbg_code_write_begin(void* user, void* runtime_addr, size_t n, - void** write_out) { +static int dbg_code_write_begin(void *user, void *runtime_addr, size_t n, + void **write_out) { (void)user; - if (!runtime_addr || !n || !write_out) return 1; + if (!runtime_addr || !n || !write_out) + return 1; #if defined(__APPLE__) /* Dual-mapped reservation (mach_vm_remap): the write alias is a * separate VA already RW. Translate via the registry; no protect flip @@ -758,8 +787,9 @@ static int dbg_code_write_begin(void* user, void* runtime_addr, size_t n, /* Linux dual-mapping uses memfd: write alias and runtime alias have * distinct VAs. Prefer the alias lookup; fall back to a transient * mprotect of the runtime alias for single-mapping reservations. */ - if (exec_dual_lookup(runtime_addr, n, write_out) == 0) return 0; - if (mprotect((void*)base, span, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) + if (exec_dual_lookup(runtime_addr, n, write_out) == 0) + return 0; + if (mprotect((void *)base, span, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) return 1; *write_out = runtime_addr; return 0; @@ -769,36 +799,37 @@ static int dbg_code_write_begin(void* user, void* runtime_addr, size_t n, #endif } -static void dbg_code_write_end(void* user, void* runtime_addr, size_t n) { +static void dbg_code_write_end(void *user, void *runtime_addr, size_t n) { (void)user; #if defined(__APPLE__) (void)runtime_addr; (void)n; #elif defined(__linux__) { - void* w; + void *w; size_t pg = driver_host_page_size(); uintptr_t a = (uintptr_t)runtime_addr; uintptr_t base = dbg_page_floor(a, pg); size_t span = dbg_page_ceil((a - base) + n, pg); - if (exec_dual_lookup(runtime_addr, n, &w) == 0) return; /* dual: nothing to flip back */ - mprotect((void*)base, span, PROT_READ | PROT_EXEC); + if (exec_dual_lookup(runtime_addr, n, &w) == 0) + return; /* dual: nothing to flip back */ + mprotect((void *)base, span, PROT_READ | PROT_EXEC); } #endif } -static void dbg_flush_icache(void* user, void* runtime_addr, size_t n) { +static void dbg_flush_icache(void *user, void *runtime_addr, size_t n) { (void)user; #if defined(__APPLE__) && defined(__aarch64__) sys_icache_invalidate(runtime_addr, n); #else - __builtin___clear_cache((char*)runtime_addr, (char*)runtime_addr + n); + __builtin___clear_cache((char *)runtime_addr, (char *)runtime_addr + n); #endif } /* --- guarded copy --- */ -static int dbg_guarded_copy(void* user, void* dst, const void* src, size_t n) { +static int dbg_guarded_copy(void *user, void *dst, const void *src, size_t n) { (void)user; if (sigsetjmp(g_guard_buf, 1) != 0) { g_guard_armed = 0; @@ -823,45 +854,49 @@ static CfreeDbgOs g_dbg_os_posix; * x0 = ctx and expects back an x0 = TLS block. We satisfy this by * making `get_block` the first field. */ typedef struct JitTlsCtx { - void* (*get_block)(void* ctx); /* first; matches tlv_thunk's expectation */ + void *(*get_block)(void *ctx); /* first; matches tlv_thunk's expectation */ pthread_key_t key; size_t image_size; size_t image_filesz; size_t align; - void* init_bytes; /* heap-owned copy of init bytes, or NULL if all BSS */ + void *init_bytes; /* heap-owned copy of init bytes, or NULL if all BSS */ } JitTlsCtx; -static void jit_tls_thread_dtor(void* block) { +static void jit_tls_thread_dtor(void *block) { /* POSIX pthread_key destructor: called when a thread that touched the * TLV exits. `block` is the void* set by pthread_setspecific, never * NULL (POSIX skips the destructor if it was NULL). */ free(block); } -static void* jit_tls_alloc_block(JitTlsCtx* ctx) { +static void *jit_tls_alloc_block(JitTlsCtx *ctx) { /* macOS aligned_alloc requires alignment >= sizeof(void*); bump * smaller request alignments up. Size must be a multiple of * alignment too. */ - size_t a = ctx->align ? ctx->align : sizeof(void*); - if (a < sizeof(void*)) a = sizeof(void*); + size_t a = ctx->align ? ctx->align : sizeof(void *); + if (a < sizeof(void *)) + a = sizeof(void *); size_t sz = (ctx->image_size + a - 1u) & ~(a - 1u); - if (sz == 0) sz = a; /* zero-size TLS image still needs a non-NULL block */ - void* block = aligned_alloc(a, sz); - if (!block) return NULL; + if (sz == 0) + sz = a; /* zero-size TLS image still needs a non-NULL block */ + void *block = aligned_alloc(a, sz); + if (!block) + return NULL; if (ctx->image_filesz && ctx->init_bytes) memcpy(block, ctx->init_bytes, ctx->image_filesz); if (ctx->image_size > ctx->image_filesz) - memset((char*)block + ctx->image_filesz, 0, + memset((char *)block + ctx->image_filesz, 0, ctx->image_size - ctx->image_filesz); return block; } /* The thunk-callable entry; the asm trampoline calls this with x0=ctx * and expects x0 back = TLS block base. */ -static void* jit_tls_get_block(void* ctx_v) { - JitTlsCtx* ctx = (JitTlsCtx*)ctx_v; - void* block = pthread_getspecific(ctx->key); - if (block) return block; +static void *jit_tls_get_block(void *ctx_v) { + JitTlsCtx *ctx = (JitTlsCtx *)ctx_v; + void *block = pthread_getspecific(ctx->key); + if (block) + return block; block = jit_tls_alloc_block(ctx); if (!block) { /* OOM inside a TLV access has no clean recovery: the thunk's caller @@ -878,16 +913,17 @@ static void* jit_tls_get_block(void* ctx_v) { return block; } -static void* jit_tls_ctx_new(void* user, const void* init_bytes, +static void *jit_tls_ctx_new(void *user, const void *init_bytes, size_t image_filesz, size_t image_size, size_t align) { (void)user; - JitTlsCtx* ctx = (JitTlsCtx*)malloc(sizeof(*ctx)); - if (!ctx) return NULL; + JitTlsCtx *ctx = (JitTlsCtx *)malloc(sizeof(*ctx)); + if (!ctx) + return NULL; ctx->get_block = jit_tls_get_block; ctx->image_size = image_size; ctx->image_filesz = image_filesz; - ctx->align = align ? align : sizeof(void*); + ctx->align = align ? align : sizeof(void *); ctx->init_bytes = NULL; if (image_filesz && init_bytes) { ctx->init_bytes = malloc(image_filesz); @@ -905,16 +941,17 @@ static void* jit_tls_ctx_new(void* user, const void* init_bytes, return ctx; } -static void jit_tls_ctx_destroy(void* user, void* ctx_v) { - JitTlsCtx* ctx = (JitTlsCtx*)ctx_v; +static void jit_tls_ctx_destroy(void *user, void *ctx_v) { + JitTlsCtx *ctx = (JitTlsCtx *)ctx_v; (void)user; - if (!ctx) return; + if (!ctx) + return; /* Free the calling thread's block (POSIX won't run our destructor for * it; pthread_key_delete also doesn't fire destructors for live * threads). Other threads' blocks are reaped when those threads * exit, since their stored pointers remain reachable via the key * value already snapshotted into TSD before delete. */ - void* my_block = pthread_getspecific(ctx->key); + void *my_block = pthread_getspecific(ctx->key); if (my_block) { pthread_setspecific(ctx->key, NULL); free(my_block); @@ -930,16 +967,17 @@ static CfreeJitTls g_jit_tls_posix; typedef struct DriverFdWriter { CfreeWriter base; /* must be first; libcfree reads via this */ - CfreeHeap* heap; + CfreeHeap *heap; int fd; int err; uint64_t pos; } DriverFdWriter; -static void fdw_write(CfreeWriter* w, const void* data, size_t n) { - DriverFdWriter* fw = (DriverFdWriter*)w; - const unsigned char* p = (const unsigned char*)data; - if (fw->err) return; +static void fdw_write(CfreeWriter *w, const void *data, size_t n) { + DriverFdWriter *fw = (DriverFdWriter *)w; + const unsigned char *p = (const unsigned char *)data; + if (fw->err) + return; while (n > 0) { ssize_t k = write(fw->fd, p, n); if (k < 0) { @@ -952,9 +990,10 @@ static void fdw_write(CfreeWriter* w, const void* data, size_t n) { } } -static void fdw_seek(CfreeWriter* w, uint64_t off) { - DriverFdWriter* fw = (DriverFdWriter*)w; - if (fw->err) return; +static void fdw_seek(CfreeWriter *w, uint64_t off) { + DriverFdWriter *fw = (DriverFdWriter *)w; + if (fw->err) + return; if (lseek(fw->fd, (off_t)off, SEEK_SET) < 0) { fw->err = 1; return; @@ -962,19 +1001,21 @@ static void fdw_seek(CfreeWriter* w, uint64_t off) { fw->pos = off; } -static uint64_t fdw_tell(CfreeWriter* w) { return ((DriverFdWriter*)w)->pos; } -static int fdw_error(CfreeWriter* w) { return ((DriverFdWriter*)w)->err; } +static uint64_t fdw_tell(CfreeWriter *w) { return ((DriverFdWriter *)w)->pos; } +static int fdw_error(CfreeWriter *w) { return ((DriverFdWriter *)w)->err; } -static void fdw_close(CfreeWriter* w) { - DriverFdWriter* fw = (DriverFdWriter*)w; - if (fw->fd >= 0) close(fw->fd); +static void fdw_close(CfreeWriter *w) { + DriverFdWriter *fw = (DriverFdWriter *)w; + if (fw->fd >= 0) + close(fw->fd); fw->heap->free(fw->heap, fw, sizeof(*fw)); } -static CfreeWriter* driver_writer_fd(CfreeHeap* h, int fd) { - DriverFdWriter* fw = - (DriverFdWriter*)h->alloc(h, sizeof(*fw), _Alignof(DriverFdWriter)); - if (!fw) return NULL; +static CfreeWriter *driver_writer_fd(CfreeHeap *h, int fd) { + DriverFdWriter *fw = + (DriverFdWriter *)h->alloc(h, sizeof(*fw), _Alignof(DriverFdWriter)); + if (!fw) + return NULL; fw->base.write = fdw_write; fw->base.seek = fdw_seek; fw->base.tell = fdw_tell; @@ -993,35 +1034,37 @@ static CfreeWriter* driver_writer_fd(CfreeHeap* h, int fd) { * to fd 1 bypasses that buffer entirely). */ typedef struct DriverStdioWriter { CfreeWriter base; - CfreeHeap* heap; - FILE* fp; + CfreeHeap *heap; + FILE *fp; } DriverStdioWriter; -static void stdio_w_write(CfreeWriter* w, const void* data, size_t n) { - DriverStdioWriter* sw = (DriverStdioWriter*)w; - if (n) fwrite(data, 1, n, sw->fp); +static void stdio_w_write(CfreeWriter *w, const void *data, size_t n) { + DriverStdioWriter *sw = (DriverStdioWriter *)w; + if (n) + fwrite(data, 1, n, sw->fp); } -static void stdio_w_seek(CfreeWriter* w, uint64_t off) { - DriverStdioWriter* sw = (DriverStdioWriter*)w; +static void stdio_w_seek(CfreeWriter *w, uint64_t off) { + DriverStdioWriter *sw = (DriverStdioWriter *)w; fseek(sw->fp, (long)off, SEEK_SET); } -static uint64_t stdio_w_tell(CfreeWriter* w) { - long t = ftell(((DriverStdioWriter*)w)->fp); +static uint64_t stdio_w_tell(CfreeWriter *w) { + long t = ftell(((DriverStdioWriter *)w)->fp); return t < 0 ? 0u : (uint64_t)t; } -static int stdio_w_error(CfreeWriter* w) { - return ferror(((DriverStdioWriter*)w)->fp) ? 1 : 0; +static int stdio_w_error(CfreeWriter *w) { + return ferror(((DriverStdioWriter *)w)->fp) ? 1 : 0; } -static void stdio_w_close(CfreeWriter* w) { - DriverStdioWriter* sw = (DriverStdioWriter*)w; +static void stdio_w_close(CfreeWriter *w) { + DriverStdioWriter *sw = (DriverStdioWriter *)w; fflush(sw->fp); /* flush but do not close stdout */ sw->heap->free(sw->heap, sw, sizeof(*sw)); } -CfreeWriter* driver_stdout_writer(DriverEnv* e) { - DriverStdioWriter* sw = (DriverStdioWriter*)e->heap->alloc( +CfreeWriter *driver_stdout_writer(DriverEnv *e) { + DriverStdioWriter *sw = (DriverStdioWriter *)e->heap->alloc( e->heap, sizeof(*sw), _Alignof(DriverStdioWriter)); - if (!sw) return NULL; + if (!sw) + return NULL; sw->base.write = stdio_w_write; sw->base.seek = stdio_w_seek; sw->base.tell = stdio_w_tell; @@ -1034,16 +1077,17 @@ CfreeWriter* driver_stdout_writer(DriverEnv* e) { /* ---------------- file_io (POSIX) ---------------- */ -static int posix_read_all(void* user, const char* path, CfreeFileData* out) { - DriverEnv* env = (DriverEnv*)user; +static int posix_read_all(void *user, const char *path, CfreeFileData *out) { + DriverEnv *env = (DriverEnv *)user; int fd; struct stat sb; size_t size; size_t got; - void* buf; + void *buf; fd = open(path, O_RDONLY); - if (fd < 0) return 0; + if (fd < 0) + return 0; if (fstat(fd, &sb) < 0) { close(fd); return 0; @@ -1057,7 +1101,7 @@ static int posix_read_all(void* user, const char* path, CfreeFileData* out) { got = 0; while (got < size) { - ssize_t n = read(fd, (unsigned char*)buf + got, size - got); + ssize_t n = read(fd, (unsigned char *)buf + got, size - got); if (n <= 0) { env->heap->free(env->heap, buf, size); close(fd); @@ -1067,30 +1111,32 @@ static int posix_read_all(void* user, const char* path, CfreeFileData* out) { } close(fd); - out->data = (const uint8_t*)buf; + out->data = (const uint8_t *)buf; out->size = size; out->token = buf; return 1; } -static void posix_release(void* user, CfreeFileData* d) { - DriverEnv* env = (DriverEnv*)user; - if (d->token) env->heap->free(env->heap, d->token, d->size); +static void posix_release(void *user, CfreeFileData *d) { + DriverEnv *env = (DriverEnv *)user; + if (d->token) + env->heap->free(env->heap, d->token, d->size); d->data = NULL; d->size = 0; d->token = NULL; } -static CfreeWriter* posix_open_writer(void* user, const char* path) { - DriverEnv* env = (DriverEnv*)user; +static CfreeWriter *posix_open_writer(void *user, const char *path) { + DriverEnv *env = (DriverEnv *)user; int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (fd < 0) return NULL; + if (fd < 0) + return NULL; return driver_writer_fd(env->heap, fd); } /* ---------------- env wiring ---------------- */ -void driver_env_init(DriverEnv* e) { +void driver_env_init(DriverEnv *e) { e->heap = &g_heap_libc; e->diag = &g_diag_stderr; e->file_io.read_all = posix_read_all; @@ -1135,9 +1181,9 @@ void driver_env_init(DriverEnv* e) { * If neither is set or the env value doesn't parse, advertise -1 ("no * clock") and pp falls back to C11 placeholders. */ { - const char* sde = getenv("SOURCE_DATE_EPOCH"); + const char *sde = getenv("SOURCE_DATE_EPOCH"); if (sde && *sde) { - char* endp = NULL; + char *endp = NULL; long long v = strtoll(sde, &endp, 10); e->now = (endp != sde && v >= 0) ? (int64_t)v : (int64_t)-1; } else { @@ -1147,12 +1193,12 @@ void driver_env_init(DriverEnv* e) { } } -void driver_env_fini(DriverEnv* e) { +void driver_env_fini(DriverEnv *e) { /* Singletons; nothing to release. */ (void)e; } -CfreeEnv driver_env_to_cfree(const DriverEnv* e) { +CfreeEnv driver_env_to_cfree(const DriverEnv *e) { CfreeEnv ce; ce.heap = e->heap; ce.file_io = &e->file_io; @@ -1167,52 +1213,55 @@ CfreeEnv driver_env_to_cfree(const DriverEnv* e) { /* ---------------- host-shim helpers ---------------- */ -int driver_streq(const char* a, const char* b) { return strcmp(a, b) == 0; } +int driver_streq(const char *a, const char *b) { return strcmp(a, b) == 0; } -int driver_strneq(const char* a, const char* b, size_t n) { +int driver_strneq(const char *a, const char *b, size_t n) { return strncmp(a, b, n) == 0; } -size_t driver_strlen(const char* s) { return strlen(s); } +size_t driver_strlen(const char *s) { return strlen(s); } -const char* driver_strchr(const char* s, int c) { return strchr(s, c); } +const char *driver_strchr(const char *s, int c) { return strchr(s, c); } -const char* driver_basename(const char* path) { - const char* slash = strrchr(path, '/'); +const char *driver_basename(const char *path) { + const char *slash = strrchr(path, '/'); return slash ? slash + 1 : path; } -int driver_has_suffix(const char* s, const char* suffix) { +int driver_has_suffix(const char *s, const char *suffix) { size_t ls = strlen(s); size_t lf = strlen(suffix); return ls >= lf && strcmp(s + ls - lf, suffix) == 0; } -int driver_path_exists(const char* path) { +int driver_path_exists(const char *path) { struct stat sb; - if (!path) return 0; + if (!path) + return 0; return stat(path, &sb) == 0; } -void* driver_alloc(DriverEnv* e, size_t n) { +void *driver_alloc(DriverEnv *e, size_t n) { return e->heap->alloc(e->heap, n, _Alignof(max_align_t)); } -void* driver_alloc_zeroed(DriverEnv* e, size_t n) { - void* p = driver_alloc(e, n); - if (p) memset(p, 0, n); +void *driver_alloc_zeroed(DriverEnv *e, size_t n) { + void *p = driver_alloc(e, n); + if (p) + memset(p, 0, n); return p; } -void driver_free(DriverEnv* e, void* p, size_t n) { - if (p) e->heap->free(e->heap, p, n); +void driver_free(DriverEnv *e, void *p, size_t n) { + if (p) + e->heap->free(e->heap, p, n); } -void driver_memcpy(void* dst, const void* src, size_t n) { +void driver_memcpy(void *dst, const void *src, size_t n) { memcpy(dst, src, n); } -void driver_errf(const char* tool, const char* fmt, ...) { +void driver_errf(const char *tool, const char *fmt, ...) { va_list ap; fprintf(stderr, "%s: ", tool); va_start(ap, fmt); @@ -1221,7 +1270,7 @@ void driver_errf(const char* tool, const char* fmt, ...) { fputc('\n', stderr); } -void driver_logf(const char* fmt, ...) { +void driver_logf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); @@ -1229,7 +1278,7 @@ void driver_logf(const char* fmt, ...) { fputc('\n', stderr); } -void driver_printf(const char* fmt, ...) { +void driver_printf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vprintf(fmt, ap); @@ -1245,10 +1294,10 @@ uint64_t driver_now_ns(void) { return 0; } -const char* driver_getenv(const char* name) { return getenv(name); } +const char *driver_getenv(const char *name) { return getenv(name); } -int driver_load_bytes(const CfreeFileIO* io, const char* tool, const char* path, - DriverLoad* out, CfreeBytesInput* in) { +int driver_load_bytes(const CfreeFileIO *io, const char *tool, const char *path, + DriverLoad *out, CfreeBytesInput *in) { out->loaded = 0; out->fd.data = NULL; out->fd.size = 0; @@ -1269,25 +1318,28 @@ int driver_load_bytes(const CfreeFileIO* io, const char* tool, const char* path, return 0; } -void driver_release_bytes(const CfreeFileIO* io, DriverLoad* lf) { - if (!lf || !lf->loaded) return; - if (io && io->release) io->release(io->user, &lf->fd); +void driver_release_bytes(const CfreeFileIO *io, DriverLoad *lf) { + if (!lf || !lf->loaded) + return; + if (io && io->release) + io->release(io->user, &lf->fd); lf->loaded = 0; } -int driver_read_stdin(DriverEnv* e, uint8_t** out_data, size_t* out_size) { +int driver_read_stdin(DriverEnv *e, uint8_t **out_data, size_t *out_size) { /* stdin is unseekable in the general case (pipes, ttys), so grow a buffer * geometrically as we read, then shrink to the exact byte count so * out_size is a valid argument to driver_free. */ size_t cap = 4096; size_t len = 0; - uint8_t* buf = e->heap->alloc(e->heap, cap, 1); - if (!buf) return 0; + uint8_t *buf = e->heap->alloc(e->heap, cap, 1); + if (!buf) + return 0; for (;;) { ssize_t n; if (len == cap) { size_t newcap = cap * 2; - uint8_t* nb = e->heap->realloc(e->heap, buf, cap, newcap, 1); + uint8_t *nb = e->heap->realloc(e->heap, buf, cap, newcap, 1); if (!nb) { e->heap->free(e->heap, buf, cap); return 0; @@ -1296,7 +1348,8 @@ int driver_read_stdin(DriverEnv* e, uint8_t** out_data, size_t* out_size) { cap = newcap; } n = read(STDIN_FILENO, buf + len, cap - len); - if (n == 0) break; + if (n == 0) + break; if (n < 0) { e->heap->free(e->heap, buf, cap); return 0; @@ -1304,7 +1357,7 @@ int driver_read_stdin(DriverEnv* e, uint8_t** out_data, size_t* out_size) { len += (size_t)n; } if (len < cap) { - uint8_t* shrunk = len ? e->heap->realloc(e->heap, buf, cap, len, 1) : NULL; + uint8_t *shrunk = len ? e->heap->realloc(e->heap, buf, cap, len, 1) : NULL; if (len && !shrunk) { /* Shrink failed: keep the larger buffer. The release size below * tracks `cap`, so this remains free-correct. */ @@ -1324,20 +1377,178 @@ int driver_read_stdin(DriverEnv* e, uint8_t** out_data, size_t* out_size) { return 1; } -void* driver_dlsym_resolver(void* user, const char* name) { - void* p; +static int driver_write_fd_all(int fd, const uint8_t *data, size_t n) { + size_t off = 0; + while (off < n) { + ssize_t wr = write(fd, data + off, n - off); + if (wr < 0) { + if (errno == EINTR) + continue; + return 0; + } + if (wr == 0) + return 0; + off += (size_t)wr; + } + return 1; +} + +static char *driver_shell_quote_path(DriverEnv *e, const char *path, + size_t path_len, size_t *quoted_len_out) { + size_t i; + size_t quoted_len = 2u; + char *out; + char *q; + for (i = 0; i < path_len; ++i) + quoted_len += path[i] == '\'' ? 4u : 1u; + out = e->heap->alloc(e->heap, quoted_len + 1u, 1); + if (!out) + return NULL; + q = out; + *q++ = '\''; + for (i = 0; i < path_len; ++i) { + if (path[i] == '\'') { + *q++ = '\''; + *q++ = '\\'; + *q++ = '\''; + *q++ = '\''; + } else { + *q++ = path[i]; + } + } + *q++ = '\''; + *q = '\0'; + if (quoted_len_out) + *quoted_len_out = quoted_len; + return out; +} + +int driver_edit_temp(DriverEnv *e, const char *suffix, const uint8_t *initial, + size_t initial_size, uint8_t **out_data, + size_t *out_size) { + const char *editor; + const char *tmpdir; + const char *base = "/cfree-dbg-XXXXXX"; + size_t tmpdir_len; + size_t base_len; + size_t suffix_len; + size_t path_len; + char *path; + int fd = -1; + int ok = 0; + CfreeFileData fd_data; + + if (!out_data || !out_size) + return 0; + *out_data = NULL; + *out_size = 0; + suffix_len = suffix ? strlen(suffix) : 0u; + tmpdir = getenv("TMPDIR"); + if (!tmpdir || !*tmpdir) + tmpdir = "/tmp"; + tmpdir_len = strlen(tmpdir); + base_len = strlen(base); + path_len = tmpdir_len + base_len + suffix_len; + path = e->heap->alloc(e->heap, path_len + 1u, 1); + if (!path) + return 0; + memcpy(path, tmpdir, tmpdir_len); + memcpy(path + tmpdir_len, base, base_len); + if (suffix_len) + memcpy(path + tmpdir_len + base_len, suffix, suffix_len); + path[path_len] = '\0'; + + fd = mkstemps(path, (int)suffix_len); + if (fd < 0) + goto out; + if (initial_size && + !driver_write_fd_all(fd, initial ? initial : (const uint8_t *)"", + initial_size)) + goto out; + if (close(fd) != 0) { + fd = -1; + goto out; + } + fd = -1; + + editor = getenv("VISUAL"); + if (!editor || !*editor) + editor = getenv("EDITOR"); + if (!editor || !*editor) + editor = "vi"; + { + size_t editor_len = strlen(editor); + size_t quoted_len = 0; + char *quoted = driver_shell_quote_path(e, path, path_len, &quoted_len); + char *cmd; + int status; + pid_t pid; + if (!quoted) + goto out; + cmd = e->heap->alloc(e->heap, editor_len + 1u + quoted_len + 1u, 1); + if (!cmd) { + e->heap->free(e->heap, quoted, quoted_len + 1u); + goto out; + } + memcpy(cmd, editor, editor_len); + cmd[editor_len] = ' '; + memcpy(cmd + editor_len + 1u, quoted, quoted_len + 1u); + e->heap->free(e->heap, quoted, quoted_len + 1u); + pid = fork(); + if (pid == 0) { + execl("/bin/sh", "sh", "-c", cmd, (char *)NULL); + _exit(127); + } + e->heap->free(e->heap, cmd, editor_len + 1u + quoted_len + 1u); + if (pid < 0) + goto out; + do { + if (waitpid(pid, &status, 0) < 0) { + if (errno == EINTR) + continue; + goto out; + } + break; + } while (1); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + goto out; + } + + fd_data.data = NULL; + fd_data.size = 0; + fd_data.token = NULL; + if (!posix_read_all(e, path, &fd_data)) + goto out; + *out_data = (uint8_t *)fd_data.data; + *out_size = fd_data.size; + ok = 1; + +out: + if (fd >= 0) + close(fd); + if (path) { + unlink(path); + e->heap->free(e->heap, path, path_len + 1u); + } + return ok; +} + +void *driver_dlsym_resolver(void *user, const char *name) { + void *p; (void)user; - if (!name) return NULL; + if (!name) + return NULL; p = dlsym(RTLD_DEFAULT, name); /* On Mach-O hosts the linker hands us C names with a leading underscore * (obj_format_c_mangle), but dlsym(RTLD_DEFAULT) expects the * source-level name. Retry with the prefix stripped so JITed code can * resolve libc symbols by their C name. */ - if (!p && name[0] == '_' && name[1] != '\0') p = dlsym(RTLD_DEFAULT, name + 1); + if (!p && name[0] == '_' && name[1] != '\0') + p = dlsym(RTLD_DEFAULT, name + 1); return p; } -int driver_read_line(char* buf, size_t cap) { +int driver_read_line(char *buf, size_t cap) { /* Reads one line from stdin into `buf` (cap >= 2 required). The trailing * newline is stripped; the result is NUL-terminated. Returns the number * of characters in the line on success, 0 at EOF (with buf[0]='\0'), @@ -1345,7 +1556,8 @@ int driver_read_line(char* buf, size_t cap) { * (errno == EINTR). Lines longer than cap-1 bytes are truncated to * cap-1 and the remainder up to the next newline is consumed. */ size_t len = 0; - if (!buf || cap < 2) return -1; + if (!buf || cap < 2) + return -1; for (;;) { int c; errno = 0; @@ -1356,15 +1568,18 @@ int driver_read_line(char* buf, size_t cap) { clearerr(stdin); return -2; } - if (ferror(stdin)) return -1; - if (len == 0) return 0; + if (ferror(stdin)) + return -1; + if (len == 0) + return 0; return (int)len; } if (c == '\n') { buf[len] = '\0'; return (int)len; } - if (len + 1 < cap) buf[len++] = (char)c; + if (len + 1 < cap) + buf[len++] = (char)c; /* else: drop overflow; keep consuming until the newline. */ } } @@ -1376,15 +1591,16 @@ void driver_flush_stdout(void) { fflush(stdout); } * call cfree_jit_session_interrupt). The handler is short and async-signal * safe by construction; the cb is the caller's responsibility. */ -static void (*s_sigint_cb)(void*); -static void* s_sigint_cb_user; +static void (*s_sigint_cb)(void *); +static void *s_sigint_cb_user; static void sigint_trampoline(int sig) { (void)sig; - if (s_sigint_cb) s_sigint_cb(s_sigint_cb_user); + if (s_sigint_cb) + s_sigint_cb(s_sigint_cb_user); } -int driver_install_sigint(void (*cb)(void*), void* user) { +int driver_install_sigint(void (*cb)(void *), void *user) { struct sigaction sa; s_sigint_cb = cb; s_sigint_cb_user = user; @@ -1441,8 +1657,8 @@ CfreeTarget driver_host_target(void) { t.obj = CFREE_OBJ_ELF; #endif - t.ptr_size = (uint8_t)sizeof(void*); - t.ptr_align = (uint8_t)sizeof(void*); + t.ptr_size = (uint8_t)sizeof(void *); + t.ptr_align = (uint8_t)sizeof(void *); t.big_endian = 0; t.pic = CFREE_PIC_NONE; t.code_model = CFREE_CM_DEFAULT; diff --git a/driver/inputs.c b/driver/inputs.c @@ -3,7 +3,7 @@ #include <stddef.h> #include <stdint.h> -int driver_inputs_init(DriverInputs* in, DriverEnv* env, const char* tool, +int driver_inputs_init(DriverInputs *in, DriverEnv *env, const char *tool, int argc) { size_t bound = (size_t)argc; in->env = env; @@ -23,10 +23,12 @@ int driver_inputs_init(DriverInputs* in, DriverEnv* env, const char* tool, return 0; } -void driver_inputs_release(DriverInputs* in) { +void driver_inputs_release(DriverInputs *in) { size_t bound = in->bound; - if (in->stdin_buf) driver_free(in->env, in->stdin_buf, in->stdin_size); - if (in->sources) driver_free(in->env, in->sources, bound * sizeof(*in->sources)); + if (in->stdin_buf) + driver_free(in->env, in->stdin_buf, in->stdin_size); + if (in->sources) + driver_free(in->env, in->sources, bound * sizeof(*in->sources)); if (in->source_memory) driver_free(in->env, in->source_memory, bound * sizeof(*in->source_memory)); if (in->object_files) @@ -38,8 +40,8 @@ void driver_inputs_release(DriverInputs* in) { /* Slurp stdin into the single source_memory entry. Guarded against * duplicates so a user typo (`cfree run - -`) is surfaced rather than * silently leaking the first slurp. */ -static int inputs_record_stdin(DriverInputs* in) { - CfreeBytesInput* slot; +static int inputs_record_stdin(DriverInputs *in) { + CfreeBytesInput *slot; if (in->stdin_buf) { driver_errf(in->tool, "'-' (stdin) may appear at most once"); return -1; @@ -52,12 +54,15 @@ static int inputs_record_stdin(DriverInputs* in) { slot->name = "<stdin>"; slot->data = in->stdin_buf; slot->len = in->stdin_size; + slot->lang = CFREE_LANG_C; return 1; } -int driver_inputs_classify(DriverInputs* in, const char* arg) { - if (driver_streq(arg, "-")) return inputs_record_stdin(in); - if (driver_has_suffix(arg, ".c") || driver_has_suffix(arg, ".toy")) { +int driver_inputs_classify(DriverInputs *in, const char *arg) { + if (driver_streq(arg, "-")) + return inputs_record_stdin(in); + if (driver_has_suffix(arg, ".c") || driver_has_suffix(arg, ".toy") || + driver_has_suffix(arg, ".s")) { in->sources[in->nsources++] = arg; return 1; } @@ -72,38 +77,40 @@ int driver_inputs_classify(DriverInputs* in, const char* arg) { return 0; } -uint32_t driver_inputs_count(const DriverInputs* in) { +uint32_t driver_inputs_count(const DriverInputs *in) { return in->nsources + in->nsource_memory + in->nobject_files + in->narchives; } -const char* driver_inputs_first_name(const DriverInputs* in) { - if (in->nsources) return in->sources[0]; - if (in->nsource_memory) return in->source_memory[0].name; - if (in->nobject_files) return in->object_files[0]; - if (in->narchives) return in->archives[0]; +const char *driver_inputs_first_name(const DriverInputs *in) { + if (in->nsources) + return in->sources[0]; + if (in->nsource_memory) + return in->source_memory[0].name; + if (in->nobject_files) + return in->object_files[0]; + if (in->narchives) + return in->archives[0]; return NULL; } /* Load every input through env.file_io, compile sources via `pipe` with * `copts`, and JIT-link. The pipeline must outlive the JIT — its * Compiler backs jit->c, which cfree_jit_lookup dereferences. */ -int driver_inputs_compile_and_jit(DriverInputs* in, CfreePipeline* pipe, - const CfreeCompileOptions* copts, - const char* entry, - void* (*extern_resolver)(void*, const char*), - void* extern_resolver_user, - CfreeJit** out_jit) { - DriverEnv* env = in->env; - const char* tool = in->tool; +int driver_inputs_compile_and_jit( + DriverInputs *in, CfreePipeline *pipe, const CfreeCompileOptions *copts, + const char *entry, void *(*extern_resolver)(void *, const char *), + void *extern_resolver_user, CfreeJit **out_jit) { + DriverEnv *env = in->env; + const char *tool = in->tool; CfreeEnv cenv = driver_env_to_cfree(env); - const CfreeFileIO* io = cenv.file_io; - DriverLoad* src_lf = NULL; - DriverLoad* obj_lf = NULL; - DriverLoad* arch_lf = NULL; - CfreeBytesInput* src_in = NULL; - CfreeBytesInput* obj_in = NULL; - CfreeBytesInputArchive* arch_in = NULL; - CfreeObjBuilder** objs = NULL; + const CfreeFileIO *io = cenv.file_io; + DriverLoad *src_lf = NULL; + DriverLoad *obj_lf = NULL; + DriverLoad *arch_lf = NULL; + CfreeBytesInput *src_in = NULL; + CfreeBytesInput *obj_in = NULL; + CfreeBytesInputArchive *arch_in = NULL; + CfreeObjBuilder **objs = NULL; CfreeLinkOptions link_opts; uint32_t nsrc = in->nsources + in->nsource_memory; uint32_t i; @@ -192,21 +199,30 @@ int driver_inputs_compile_and_jit(DriverInputs* in, CfreePipeline* pipe, out: if (arch_lf) { - for (i = 0; i < in->narchives; ++i) driver_release_bytes(io, &arch_lf[i]); + for (i = 0; i < in->narchives; ++i) + driver_release_bytes(io, &arch_lf[i]); } if (obj_lf) { for (i = 0; i < in->nobject_files; ++i) driver_release_bytes(io, &obj_lf[i]); } if (src_lf) { - for (i = 0; i < in->nsources; ++i) driver_release_bytes(io, &src_lf[i]); - } - if (arch_in) driver_free(env, arch_in, in->narchives * sizeof(*arch_in)); - if (arch_lf) driver_free(env, arch_lf, in->narchives * sizeof(*arch_lf)); - if (obj_in) driver_free(env, obj_in, in->nobject_files * sizeof(*obj_in)); - if (obj_lf) driver_free(env, obj_lf, in->nobject_files * sizeof(*obj_lf)); - if (src_lf) driver_free(env, src_lf, in->nsources * sizeof(*src_lf)); - if (objs) driver_free(env, objs, nsrc * sizeof(*objs)); - if (src_in) driver_free(env, src_in, nsrc * sizeof(*src_in)); + for (i = 0; i < in->nsources; ++i) + driver_release_bytes(io, &src_lf[i]); + } + if (arch_in) + driver_free(env, arch_in, in->narchives * sizeof(*arch_in)); + if (arch_lf) + driver_free(env, arch_lf, in->narchives * sizeof(*arch_lf)); + if (obj_in) + driver_free(env, obj_in, in->nobject_files * sizeof(*obj_in)); + if (obj_lf) + driver_free(env, obj_lf, in->nobject_files * sizeof(*obj_lf)); + if (src_lf) + driver_free(env, src_lf, in->nsources * sizeof(*src_lf)); + if (objs) + driver_free(env, objs, nsrc * sizeof(*objs)); + if (src_in) + driver_free(env, src_in, nsrc * sizeof(*src_in)); return rc; } diff --git a/driver/inputs.h b/driver/inputs.h @@ -25,19 +25,19 @@ * Path strings (`.c`, `.o`, `.a`) are borrowed from argv. The stdin * buffer is heap-owned and freed by driver_inputs_release. */ typedef struct DriverInputs { - DriverEnv* env; - const char* tool; + DriverEnv *env; + const char *tool; size_t bound; - const char** sources; /* .c .cc .cpp paths (borrowed) */ + const char **sources; /* .c .cc .cpp paths (borrowed) */ uint32_t nsources; - CfreeBytesInput* source_memory; /* "-" stdin slurp; at most one entry */ + CfreeBytesInput *source_memory; /* "-" stdin slurp; at most one entry */ uint32_t nsource_memory; - uint8_t* stdin_buf; /* owning storage for the one stdin slurp */ + uint8_t *stdin_buf; /* owning storage for the one stdin slurp */ size_t stdin_size; - const char** object_files; /* .o .obj paths (borrowed) */ + const char **object_files; /* .o .obj paths (borrowed) */ uint32_t nobject_files; - const char** archives; /* .a paths (borrowed) */ + const char **archives; /* .a paths (borrowed) */ uint32_t narchives; } DriverInputs; @@ -45,15 +45,15 @@ typedef struct DriverInputs { * (typically the program's argc). `tool` is the short name used in * driver_errf messages. Returns 0 on success, 1 on allocation failure * (already reported). */ -int driver_inputs_init(DriverInputs*, DriverEnv*, const char* tool, int argc); +int driver_inputs_init(DriverInputs *, DriverEnv *, const char *tool, int argc); /* Release every allocation held by *in, including the stdin buffer. * Safe to call even after a failed init. */ -void driver_inputs_release(DriverInputs*); +void driver_inputs_release(DriverInputs *); /* Try to consume one positional input at `arg`. Recognized: * "-" read C source from stdin (at most once) - * *.c *.cc *.cpp C source path + * *.c *.toy *.s source path * *.o *.obj object-file path * *.a static-archive path * @@ -64,27 +64,25 @@ void driver_inputs_release(DriverInputs*); * -1 arg matched a recognized shape but recording failed (duplicate * stdin, stdin read failure, allocation failure); the error has * already been reported via driver_errf. */ -int driver_inputs_classify(DriverInputs*, const char* arg); +int driver_inputs_classify(DriverInputs *, const char *arg); /* Total recorded inputs across every kind. */ -uint32_t driver_inputs_count(const DriverInputs*); +uint32_t driver_inputs_count(const DriverInputs *); /* Display name of the first recorded input (sources, then source_memory, * then object_files, then archives — matches the order used by the * link/compile loop). Used by callers to synthesize argv[0] for the * JITed program. Returns NULL when no inputs are recorded. */ -const char* driver_inputs_first_name(const DriverInputs*); +const char *driver_inputs_first_name(const DriverInputs *); /* Load every input through env.file_io, compile sources via `pipe` with * `copts`, and JIT-link the result. `entry`, `extern_resolver`, and * `extern_resolver_user` populate the matching fields of the internal * CfreeLinkOptions. On success *out_jit owns the JIT image; on failure * an error has already been reported. Returns 0 on success, 1 otherwise. */ -int driver_inputs_compile_and_jit(DriverInputs*, CfreePipeline*, - const CfreeCompileOptions* copts, - const char* entry, - void* (*extern_resolver)(void*, const char*), - void* extern_resolver_user, - CfreeJit** out_jit); +int driver_inputs_compile_and_jit( + DriverInputs *, CfreePipeline *, const CfreeCompileOptions *copts, + const char *entry, void *(*extern_resolver)(void *, const char *), + void *extern_resolver_user, CfreeJit **out_jit); #endif diff --git a/include/cfree.h b/include/cfree.h @@ -60,11 +60,11 @@ typedef struct CfreeUnwindFrame { typedef struct CfreeHeap CfreeHeap; struct CfreeHeap { - void* (*alloc)(CfreeHeap*, size_t size, size_t align); - void* (*realloc)(CfreeHeap*, void* p, size_t old_size, size_t new_size, + void *(*alloc)(CfreeHeap *, size_t size, size_t align); + void *(*realloc)(CfreeHeap *, void *p, size_t old_size, size_t new_size, size_t align); - void (*free)(CfreeHeap*, void* p, size_t size); - void* user; + void (*free)(CfreeHeap *, void *p, size_t size); + void *user; }; typedef enum CfreeDiagKind { @@ -76,9 +76,9 @@ typedef enum CfreeDiagKind { typedef struct CfreeDiagSink CfreeDiagSink; struct CfreeDiagSink { - void (*emit)(CfreeDiagSink*, CfreeDiagKind, CfreeSrcLoc, const char* fmt, + void (*emit)(CfreeDiagSink *, CfreeDiagKind, CfreeSrcLoc, const char *fmt, va_list); - void* user; + void *user; /* libcfree maintains these counters; hosts may inspect, must not write. */ uint32_t errors; uint32_t warnings; @@ -86,13 +86,13 @@ struct CfreeDiagSink { typedef struct CfreeWriter CfreeWriter; struct CfreeWriter { - void (*write)(CfreeWriter*, const void* data, size_t n); - void (*seek)(CfreeWriter*, uint64_t offset); - uint64_t (*tell)(CfreeWriter*); - int (*error)(CfreeWriter*); + void (*write)(CfreeWriter *, const void *data, size_t n); + void (*seek)(CfreeWriter *, uint64_t offset); + uint64_t (*tell)(CfreeWriter *); + int (*error)(CfreeWriter *); /* close is responsible for any host-side teardown (closing fds, freeing * the enclosing struct). After close the pointer is invalid. */ - void (*close)(CfreeWriter*); + void (*close)(CfreeWriter *); }; /* ============================================================ @@ -200,15 +200,15 @@ typedef enum CfreeSymKind { * DWARF indices, which are sparse (e.g. 32..63 are unused on aarch64). */ typedef struct CfreeArchReg { uint32_t dwarf_idx; - const char* name; + const char *name; } CfreeArchReg; -const char* cfree_arch_register_name(CfreeArchKind, uint32_t dwarf_idx); -int cfree_arch_register_index(CfreeArchKind, const char* name, - uint32_t* idx_out); +const char *cfree_arch_register_name(CfreeArchKind, uint32_t dwarf_idx); +int cfree_arch_register_index(CfreeArchKind, const char *name, + uint32_t *idx_out); uint32_t cfree_arch_register_count(CfreeArchKind); -int cfree_arch_register_at(CfreeArchKind, uint32_t idx, CfreeArchReg* out); +int cfree_arch_register_at(CfreeArchKind, uint32_t idx, CfreeArchReg *out); /* ============================================================ * Host environment @@ -217,16 +217,16 @@ int cfree_arch_register_at(CfreeArchKind, uint32_t idx, CfreeArchReg* out); * freestanding core never takes paths; path-shaped helpers in the driver * feed bytes/Writers. */ typedef struct CfreeFileData { - const uint8_t* data; + const uint8_t *data; size_t size; - void* token; /* opaque ownership handle for release */ + void *token; /* opaque ownership handle for release */ } CfreeFileData; typedef struct CfreeFileIO { - int (*read_all)(void* user, const char* path, CfreeFileData* out); - void (*release)(void* user, CfreeFileData*); - CfreeWriter* (*open_writer)(void* user, const char* path); - void* user; + int (*read_all)(void *user, const char *path, CfreeFileData *out); + void (*release)(void *user, CfreeFileData *); + CfreeWriter *(*open_writer)(void *user, const char *path); + void *user; } CfreeFileIO; /* Executable-memory vtable. Required by the JIT mapper (cfree_jit_from_image) @@ -268,20 +268,20 @@ enum { }; typedef struct CfreeExecMemRegion { - void* write; /* RW alias for population; never has EXEC */ - void* runtime; /* runtime/execution alias; never has WRITE. + void *write; /* RW alias for population; never has EXEC */ + void *runtime; /* runtime/execution alias; never has WRITE. For non-EXEC reservations equals `write`. */ size_t size; /* page-aligned bytes */ - void* token; /* opaque host handle for release() */ + void *token; /* opaque host handle for release() */ } CfreeExecMemRegion; typedef struct CfreeExecMem { size_t page_size; - int (*reserve)(void* user, size_t size, int prot, CfreeExecMemRegion* out); - int (*protect)(void* user, void* addr, size_t size, int prot); - void (*release)(void* user, CfreeExecMemRegion* region); - void (*flush_icache)(void* user, void* addr, size_t size); - void* user; + int (*reserve)(void *user, size_t size, int prot, CfreeExecMemRegion *out); + int (*protect)(void *user, void *addr, size_t size, int prot); + void (*release)(void *user, CfreeExecMemRegion *region); + void (*flush_icache)(void *user, void *addr, size_t size); + void *user; } CfreeExecMem; /* Debugger OS vtable. Required by the JIT session (cfree_jit_session_new) so @@ -329,34 +329,34 @@ typedef struct CfreeExecMem { * this landing slot before delegating to * on_fault. */ typedef struct CfreeDbgSignalOps { - int (*on_fault)(void* session, int signo, CfreeUnwindFrame* regs); + int (*on_fault)(void *session, int signo, CfreeUnwindFrame *regs); } CfreeDbgSignalOps; typedef struct CfreeDbgOs { - int (*thread_start)(void* user, void (*fn)(void*), void* arg, - void** thread_out); - void (*thread_join)(void* user, void* thread); - int (*thread_interrupt)(void* user, void* thread); - - void* (*event_new)(void* user); - void (*event_free)(void* user, void* ev); - void (*event_wait)(void* user, void* ev); - void (*event_signal)(void* user, void* ev); - void (*event_reset)(void* user, void* ev); - - int (*signals_install)(void* user, const CfreeDbgSignalOps* ops, - void* session); - void (*signals_uninstall)(void* user); - int interrupt_signo; - - int (*code_write_begin)(void* user, void* runtime_addr, size_t n, - void** write_out); - void (*code_write_end)(void* user, void* runtime_addr, size_t n); - void (*flush_icache)(void* user, void* runtime_addr, size_t n); - - int (*guarded_copy)(void* user, void* dst, const void* src, size_t n); - - void* user; + int (*thread_start)(void *user, void (*fn)(void *), void *arg, + void **thread_out); + void (*thread_join)(void *user, void *thread); + int (*thread_interrupt)(void *user, void *thread); + + void *(*event_new)(void *user); + void (*event_free)(void *user, void *ev); + void (*event_wait)(void *user, void *ev); + void (*event_signal)(void *user, void *ev); + void (*event_reset)(void *user, void *ev); + + int (*signals_install)(void *user, const CfreeDbgSignalOps *ops, + void *session); + void (*signals_uninstall)(void *user); + int interrupt_signo; + + int (*code_write_begin)(void *user, void *runtime_addr, size_t n, + void **write_out); + void (*code_write_end)(void *user, void *runtime_addr, size_t n); + void (*flush_icache)(void *user, void *runtime_addr, size_t n); + + int (*guarded_copy)(void *user, void *dst, const void *src, size_t n); + + void *user; } CfreeDbgOs; /* Host vtable for the JIT TLV thunk on Mach-O targets. @@ -386,27 +386,27 @@ typedef struct CfreeDbgOs { * delete the pthread_key (POSIX runs per-thread * destructors then) and release the ctx storage. */ typedef struct CfreeJitTls { - void* (*ctx_new)(void* user, const void* init_bytes, size_t image_filesz, + void *(*ctx_new)(void *user, const void *init_bytes, size_t image_filesz, size_t image_size, size_t align); - void (*ctx_destroy)(void* user, void* ctx); - void* user; + void (*ctx_destroy)(void *user, void *ctx); + void *user; } CfreeJitTls; typedef struct CfreeMetrics { - void (*scope_begin)(void* user, const char* name); - void (*scope_end)(void* user, const char* name); - void (*count)(void* user, const char* name, uint64_t value); - void* user; + void (*scope_begin)(void *user, const char *name); + void (*scope_end)(void *user, const char *name); + void (*count)(void *user, const char *name, uint64_t value); + void *user; } CfreeMetrics; typedef struct CfreeEnv { - CfreeHeap* heap; - const CfreeFileIO* file_io; /* may be NULL for purely in-memory pipelines */ - CfreeDiagSink* diag; - const CfreeExecMem* execmem; /* NULL ok unless JIT/emu paths run */ - const CfreeDbgOs* dbg_os; /* NULL ok unless `cfree dbg` paths run */ - const CfreeJitTls* jit_tls; /* NULL ok unless JIT TLV paths run */ - const CfreeMetrics* metrics; /* optional scoped metrics sink */ + CfreeHeap *heap; + const CfreeFileIO *file_io; /* may be NULL for purely in-memory pipelines */ + CfreeDiagSink *diag; + const CfreeExecMem *execmem; /* NULL ok unless JIT/emu paths run */ + const CfreeDbgOs *dbg_os; /* NULL ok unless `cfree dbg` paths run */ + const CfreeJitTls *jit_tls; /* NULL ok unless JIT TLV paths run */ + const CfreeMetrics *metrics; /* optional scoped metrics sink */ /* Unix seconds since 1970-01-01 UTC, or negative for "no clock". Used * by the preprocessor for __DATE__ / __TIME__ (negative → C11 §6.10.8.1 * placeholders). The host decides the policy (SOURCE_DATE_EPOCH, @@ -417,9 +417,9 @@ typedef struct CfreeEnv { /* ============================================================ * Compiler lifecycle * ============================================================ */ -CfreeCompiler* cfree_compiler_new(CfreeTarget, const CfreeEnv*); -void cfree_compiler_free(CfreeCompiler*); -CfreeTarget cfree_compiler_target(CfreeCompiler*); +CfreeCompiler *cfree_compiler_new(CfreeTarget, const CfreeEnv *); +void cfree_compiler_free(CfreeCompiler *); +CfreeTarget cfree_compiler_target(CfreeCompiler *); /* Resolve a CfreeSrcLoc.file_id to the spelling used when the source was * registered (typically the path passed to FileIO.read_all, or a memory- @@ -427,16 +427,16 @@ CfreeTarget cfree_compiler_target(CfreeCompiler*); * registered file. The returned pointer is owned by the compiler and is * valid until cfree_compiler_free. Diagnostic sinks use this to print * `path:line:col` instead of the bare numeric `file_id`. */ -const char* cfree_compiler_file_name(CfreeCompiler*, uint32_t file_id); +const char *cfree_compiler_file_name(CfreeCompiler *, uint32_t file_id); /* Intern a string into the compiler's global symbol pool. The returned symbol * is stable until cfree_compiler_free and may be passed through public APIs * that traffic in pre-interned names. 0 is reserved for "no symbol"; this * entry never returns 0 for a non-NULL string. */ -CfreeSym cfree_sym_intern(CfreeCompiler*, const char* str); +CfreeSym cfree_sym_intern(CfreeCompiler *, const char *str); /* Returns the diagnostic sink registered at compiler construction. */ -CfreeDiagSink* cfree_compiler_diag_sink(CfreeCompiler*); +CfreeDiagSink *cfree_compiler_diag_sink(CfreeCompiler *); /* ============================================================ * Writer dispatch (inline) @@ -444,21 +444,21 @@ CfreeDiagSink* cfree_compiler_diag_sink(CfreeCompiler*); * Callers obtain CfreeWriter*s from CfreeFileIO.open_writer or from * cfree_writer_mem. The dispatch helpers below are pure inline thunks * over the vtable — libcfree itself uses the vtable directly. */ -static inline void cfree_writer_write(CfreeWriter* w, const void* d, size_t n) { +static inline void cfree_writer_write(CfreeWriter *w, const void *d, size_t n) { w->write(w, d, n); } -static inline void cfree_writer_seek(CfreeWriter* w, uint64_t off) { +static inline void cfree_writer_seek(CfreeWriter *w, uint64_t off) { w->seek(w, off); } -static inline uint64_t cfree_writer_tell(CfreeWriter* w) { return w->tell(w); } -static inline int cfree_writer_error(CfreeWriter* w) { return w->error(w); } -static inline void cfree_writer_close(CfreeWriter* w) { w->close(w); } +static inline uint64_t cfree_writer_tell(CfreeWriter *w) { return w->tell(w); } +static inline int cfree_writer_error(CfreeWriter *w) { return w->error(w); } +static inline void cfree_writer_close(CfreeWriter *w) { w->close(w); } /* In-memory writer backed by the supplied heap. Useful as a building * block; the buffer is owned by the Writer and cfree_writer_mem_bytes * returns its current contents (valid until the next write or close). */ -CfreeWriter* cfree_writer_mem(CfreeHeap*); -const uint8_t* cfree_writer_mem_bytes(CfreeWriter*, size_t* len_out); +CfreeWriter *cfree_writer_mem(CfreeHeap *); +const uint8_t *cfree_writer_mem_bytes(CfreeWriter *, size_t *len_out); /* ============================================================ * JIT @@ -468,17 +468,17 @@ const uint8_t* cfree_writer_mem_bytes(CfreeWriter*, size_t* len_out); * libcfree); dlsym-shaped — the caller casts to whatever function * signature the JITed symbol actually has (e.g. int(*)(int, char**) for * `main`). Returns NULL on miss. */ -void cfree_jit_free(CfreeJit*); -void* cfree_jit_lookup(CfreeJit*, const char* name); +void cfree_jit_free(CfreeJit *); +void *cfree_jit_lookup(CfreeJit *, const char *name); /* Experimental append-only JIT growth. Appends one finalized object into * reserved JIT slack without moving existing code/data. Returns nonzero on * duplicate strong definitions, unresolved references, capacity exhaustion, * or relocation/protection failure. */ -int cfree_jit_append_obj(CfreeJit*, CfreeObjBuilder*); -uint64_t cfree_jit_generation(CfreeJit*); +int cfree_jit_append_obj(CfreeJit *, CfreeObjBuilder *); +uint64_t cfree_jit_generation(CfreeJit *); /* Run all fini_array destructors in reverse order. Call after the last * use of JITed code, before cfree_jit_free. */ -void cfree_jit_run_dtors(CfreeJit*); +void cfree_jit_run_dtors(CfreeJit *); /* ----- JIT image inspection ----- * @@ -491,9 +491,9 @@ void cfree_jit_run_dtors(CfreeJit*); * PC to the enclosing global symbol. Returns 0 on success and 1 when no * symbol contains `addr`. The interned name string is valid until * cfree_jit_free. */ -const CfreeObjFile* cfree_jit_view(CfreeJit*); -int cfree_jit_addr_to_sym(CfreeJit*, uint64_t addr, const char** name_out, - uint64_t* off_out); +const CfreeObjFile *cfree_jit_view(CfreeJit *); +int cfree_jit_addr_to_sym(CfreeJit *, uint64_t addr, const char **name_out, + uint64_t *off_out); /* PC-space translation between the JIT's runtime address space (where * executable code actually lives) and the image-relative vaddr space @@ -511,8 +511,8 @@ int cfree_jit_addr_to_sym(CfreeJit*, uint64_t addr, const char** name_out, * stepping. * * Stable for the JIT's lifetime; constant-time over jit segment count. */ -uint64_t cfree_jit_runtime_to_image(CfreeJit*, uint64_t runtime_pc); -uint64_t cfree_jit_image_to_runtime(CfreeJit*, uint64_t image_vaddr); +uint64_t cfree_jit_runtime_to_image(CfreeJit *, uint64_t runtime_pc); +uint64_t cfree_jit_image_to_runtime(CfreeJit *, uint64_t image_vaddr); /* Enumerate every globally visible symbol in the resolved JIT image. * Drives `info functions` / `info variables` and tab completion in dbg. @@ -521,15 +521,15 @@ uint64_t cfree_jit_image_to_runtime(CfreeJit*, uint64_t image_vaddr); * etc.). */ typedef struct CfreeJitSymIter CfreeJitSymIter; typedef struct CfreeJitSym { - const char* name; + const char *name; uint64_t addr; uint64_t size; CfreeSymKind kind; } CfreeJitSym; -CfreeJitSymIter* cfree_jit_sym_iter_new(CfreeJit*); -int cfree_jit_sym_iter_next(CfreeJitSymIter*, CfreeJitSym* out); -void cfree_jit_sym_iter_free(CfreeJitSymIter*); +CfreeJitSymIter *cfree_jit_sym_iter_new(CfreeJit *); +int cfree_jit_sym_iter_next(CfreeJitSymIter *, CfreeJitSym *out); +void cfree_jit_sym_iter_free(CfreeJitSymIter *); /* ----- JIT session: controlled execution ----- * @@ -589,37 +589,37 @@ typedef enum CfreeEntryKind { CFREE_ENTRY_U64, /* uint64_t(uint64_t, ... up to 8 args) */ } CfreeEntryKind; -CfreeJitSession* cfree_jit_session_new(CfreeJit*); -void cfree_jit_session_free(CfreeJitSession*); +CfreeJitSession *cfree_jit_session_new(CfreeJit *); +void cfree_jit_session_free(CfreeJitSession *); /* Bind a DWARF consumer to the session. Required for the source-level * resume modes (STEP_LINE, NEXT_LINE, STEP_OUT). The CfreeDebugInfo must * outlive every session_resume that uses those modes; the session does * not take ownership and will not free it. Passing NULL detaches. * Returns 0 on success. */ -int cfree_jit_session_attach_dwarf(CfreeJitSession*, CfreeDebugInfo*); +int cfree_jit_session_attach_dwarf(CfreeJitSession *, CfreeDebugInfo *); /* Begin executing `entry` with `argv`. Blocks until the worker stops. * `entry` must be a pointer returned by cfree_jit_lookup (or otherwise * within the JIT image). Returns 0 on success (including an EXIT stop), * nonzero on internal failure (worker spawn, OOM). On success *stop is * populated. */ -int cfree_jit_session_call(CfreeJitSession*, void* entry, CfreeEntryKind, - int argc, char** argv, CfreeStopInfo* stop_out); -int cfree_jit_session_call_u64(CfreeJitSession*, void* entry, - const uint64_t* args, uint32_t nargs, - uint64_t* ret_out, CfreeStopInfo* stop_out); +int cfree_jit_session_call(CfreeJitSession *, void *entry, CfreeEntryKind, + int argc, char **argv, CfreeStopInfo *stop_out); +int cfree_jit_session_call_u64(CfreeJitSession *, void *entry, + const uint64_t *args, uint32_t nargs, + uint64_t *ret_out, CfreeStopInfo *stop_out); /* Resume the parked worker. Blocks until the next stop. Returns 0 on * success, nonzero if no worker is parked. */ -int cfree_jit_session_resume(CfreeJitSession*, CfreeResumeMode, - CfreeStopInfo* stop_out); +int cfree_jit_session_resume(CfreeJitSession *, CfreeResumeMode, + CfreeStopInfo *stop_out); /* Asynchronously interrupt a running worker. Async-signal-safe: callable * from a SIGINT handler in the host. The next stop event delivered to the * driving thread will be CFREE_STOP_INTERRUPT. Returns 0 on a queued * interrupt, nonzero if no worker is currently running. */ -int cfree_jit_session_interrupt(CfreeJitSession*); +int cfree_jit_session_interrupt(CfreeJitSession *); /* Read `n` bytes from the worker's address space starting at `addr` into * `dst`. Used by `p` and `x` in the dbg driver to dereference globals, @@ -627,34 +627,34 @@ int cfree_jit_session_interrupt(CfreeJitSession*); * and nonzero on a bad address or partial read; partial-read attempts do * not modify `dst`. Safe to call only while the worker is parked at a * stop. */ -int cfree_jit_session_read_mem(CfreeJitSession*, uint64_t addr, void* dst, +int cfree_jit_session_read_mem(CfreeJitSession *, uint64_t addr, void *dst, size_t n); /* Write `n` bytes from `src` into the worker's address space at `addr`. * Same constraints as the read variant: caller must be at a stop; partial * writes leave the target untouched and return nonzero. */ -int cfree_jit_session_write_mem(CfreeJitSession*, uint64_t addr, - const void* src, size_t n); +int cfree_jit_session_write_mem(CfreeJitSession *, uint64_t addr, + const void *src, size_t n); /* Read full register snapshot. Snapshot already lives in CfreeStopInfo; * this is for callers that want a refresh outside the stop event (e.g. * after a write). Returns 0 on success, nonzero if no worker is parked. */ -int cfree_jit_session_get_regs(CfreeJitSession*, CfreeUnwindFrame* out); +int cfree_jit_session_get_regs(CfreeJitSession *, CfreeUnwindFrame *out); /* Write back a register snapshot. The frame's `regs` are written into the * worker; `pc` and `cfa` are honored only when changed. The library * validates that `pc` lies inside the JIT image. Returns 0 on success, * nonzero on a bad pc or if no worker is parked. */ -int cfree_jit_session_set_regs(CfreeJitSession*, const CfreeUnwindFrame*); +int cfree_jit_session_set_regs(CfreeJitSession *, const CfreeUnwindFrame *); /* Set / clear a breakpoint at `addr` (which must lie within the JIT image). * On success, *bp_id_out is the session-local handle that future stop * events will report. Idempotent: setting at an address that already has * a breakpoint returns its existing handle. cfree_jit_session_breakpoint_clear * silently succeeds on an unknown handle. */ -int cfree_jit_session_breakpoint_set(CfreeJitSession*, uint64_t addr, - uint32_t* bp_id_out); -int cfree_jit_session_breakpoint_clear(CfreeJitSession*, uint32_t bp_id); +int cfree_jit_session_breakpoint_set(CfreeJitSession *, uint64_t addr, + uint32_t *bp_id_out); +int cfree_jit_session_breakpoint_clear(CfreeJitSession *, uint32_t bp_id); /* Extended breakpoint setter with skip count, hit cap, and an optional * in-process predicate. The plain breakpoint_set above is a convenience @@ -674,17 +674,17 @@ typedef struct CfreeBreakpointSpec { uint64_t addr; uint64_t skip_count; /* silent skips before the first stop */ uint64_t max_hits; /* 0 = unlimited */ - int (*condition)(void* user, const CfreeUnwindFrame* regs); - void* condition_user; + int (*condition)(void *user, const CfreeUnwindFrame *regs); + void *condition_user; } CfreeBreakpointSpec; -int cfree_jit_session_breakpoint_set_spec(CfreeJitSession*, - const CfreeBreakpointSpec*, - uint32_t* bp_id_out); +int cfree_jit_session_breakpoint_set_spec(CfreeJitSession *, + const CfreeBreakpointSpec *, + uint32_t *bp_id_out); /* Resolver invoked when the linker encounters an undefined symbol. Returning * NULL is an error. */ -typedef void* (*CfreeExternResolver)(void* user, const char* name); +typedef void *(*CfreeExternResolver)(void *user, const char *name); /* ============================================================ * Pipeline @@ -712,8 +712,8 @@ typedef void* (*CfreeExternResolver)(void* user, const char* name); * handler, and returns nonzero. */ typedef struct CfreeDefine { - const char* name; - const char* body; /* NULL means "1" */ + const char *name; + const char *body; /* NULL means "1" */ } CfreeDefine; /* Source language tag carried on CfreeBytesInput when the input is fed to @@ -732,12 +732,12 @@ typedef enum CfreeLanguage { CFREE_LANG_COUNT = 3, } CfreeLanguage; -typedef int (*CfreeCompileFn)(CfreeCompiler*, const CfreeCompileOptions*, - const CfreeBytesInput*, CfreeObjBuilder* out); +typedef int (*CfreeCompileFn)(CfreeCompiler *, const CfreeCompileOptions *, + const CfreeBytesInput *, CfreeObjBuilder *out); /* Register out-of-core language frontend hooks for this compiler instance. * Passing NULL clears the slot. Returns nonzero on bad args. */ -int cfree_register_frontend(CfreeCompiler*, CfreeLanguage, CfreeCompileFn); +int cfree_register_frontend(CfreeCompiler *, CfreeLanguage, CfreeCompileFn); /* Generic byte-buffer input. Used for source TUs (C/asm), encoded objects, * and archives. `name` is a diagnostic label (typically a path or pseudo- @@ -745,8 +745,8 @@ int cfree_register_frontend(CfreeCompiler*, CfreeLanguage, CfreeCompileFn); * content. `lang` is consulted only by source-consuming entries; other * entries ignore it. */ struct CfreeBytesInput { - const char* name; - const uint8_t* data; + const char *name; + const uint8_t *data; size_t len; CfreeLanguage lang; }; @@ -755,17 +755,17 @@ struct CfreeBytesInput { * CFREE_LANG_TOY, `.c`, `.cc`, `.cpp` and any other suffix (including a path * with no suffix) -> CFREE_LANG_C. `.S` (preprocessed asm) is not recognized * — drivers must preprocess first and submit the result as CFREE_LANG_ASM. */ -CfreeLanguage cfree_language_for_path(const char* path); +CfreeLanguage cfree_language_for_path(const char *path); /* Preprocessor configuration shared by compile_* and the convenience run. */ struct CfreePpOptions { - const char* const* include_dirs; + const char *const *include_dirs; uint32_t ninclude_dirs; - const char* const* system_include_dirs; + const char *const *system_include_dirs; uint32_t nsystem_include_dirs; - const CfreeDefine* defines; + const CfreeDefine *defines; uint32_t ndefines; - const char* const* undefines; + const char *const *undefines; uint32_t nundefines; }; @@ -773,8 +773,8 @@ struct CfreePpOptions { * path for DWARF emission (DW_AT_comp_dir, DW_AT_name, line program). The * first match wins. Diagnostic output uses original paths. */ typedef struct CfreePathPrefixMap { - const char* old_prefix; - const char* new_prefix; + const char *old_prefix; + const char *new_prefix; } CfreePathPrefixMap; /* Per-TU compile knobs. */ @@ -787,7 +787,7 @@ struct CfreeCompileOptions { * header, Mach-O LC_BUILD_VERSION, ar ar_date, DWARF producer). 0 means * write no timestamp at all (the default). */ uint64_t epoch; - const CfreePathPrefixMap* path_map; + const CfreePathPrefixMap *path_map; uint32_t npath_map; /* Diagnostic policy. * @@ -825,10 +825,10 @@ struct CfreeCompileOptions { * GAS-subset assembler; CfreeCompileOptions fields that are C-only * (CfreeCompileOptions.pp, opt_level) are ignored. Inline asm inside C TUs * is handled by the C parser internally — no separate entry. */ -int cfree_compile_obj(CfreeCompiler*, const CfreeCompileOptions*, - const CfreeBytesInput* input, CfreeObjBuilder** out); -int cfree_compile_obj_emit(CfreeCompiler*, const CfreeCompileOptions*, - const CfreeBytesInput* input, CfreeWriter* out); +int cfree_compile_obj(CfreeCompiler *, const CfreeCompileOptions *, + const CfreeBytesInput *input, CfreeObjBuilder **out); +int cfree_compile_obj_emit(CfreeCompiler *, const CfreeCompileOptions *, + const CfreeBytesInput *input, CfreeWriter *out); /* ----- Header-dependency iteration ----- * @@ -865,17 +865,17 @@ int cfree_compile_obj_emit(CfreeCompiler*, const CfreeCompileOptions*, typedef struct CfreeDepIter CfreeDepIter; typedef struct CfreeDepEdge { - const char* includer_name; /* resolved path; same string given to read_all */ - const char* included_name; /* resolved path; same string given to read_all */ + const char *includer_name; /* resolved path; same string given to read_all */ + const char *included_name; /* resolved path; same string given to read_all */ CfreeSrcLoc include_loc; uint8_t from_system_path; /* 1 if resolved via a system include path */ uint8_t bracketed; /* 1 if syntax was <…>; 0 for "…" */ uint8_t pad[2]; } CfreeDepEdge; -CfreeDepIter* cfree_dep_iter_new(CfreeCompiler*); -int cfree_dep_iter_next(CfreeDepIter*, CfreeDepEdge* out); -void cfree_dep_iter_free(CfreeDepIter*); +CfreeDepIter *cfree_dep_iter_new(CfreeCompiler *); +int cfree_dep_iter_next(CfreeDepIter *, CfreeDepEdge *out); +void cfree_dep_iter_free(CfreeDepIter *); /* Build-ID emission mode (ELF .note.gnu.build-id and friends). */ typedef enum CfreeBuildIdMode { @@ -927,7 +927,7 @@ struct CfreeLinkExpr { uint8_t kind; /* CfreeLinkExprKind */ union { int64_t int_val; - const char* name; + const char *name; struct { const CfreeLinkExpr *lhs, *rhs; } bin; @@ -944,15 +944,15 @@ typedef enum CfreeLinkRegionFlag { } CfreeLinkRegionFlag; typedef struct CfreeLinkRegion { - const char* name; + const char *name; uint8_t flags; /* CfreeLinkRegionFlag mask */ uint64_t origin; uint64_t length; } CfreeLinkRegion; typedef struct CfreeLinkInputMatch { - const char* file_pattern; /* NULL == "*" */ - const char* section_pattern; + const char *file_pattern; /* NULL == "*" */ + const char *section_pattern; int keep; /* nonzero: exempt from --gc-sections */ } CfreeLinkInputMatch; @@ -964,29 +964,29 @@ typedef enum CfreeLinkAsnKind { typedef struct CfreeLinkAssignment { uint8_t kind; /* CfreeLinkAsnKind */ - const char* sym; /* unused for CFREE_LAS_DOT */ - const CfreeLinkExpr* expr; + const char *sym; /* unused for CFREE_LAS_DOT */ + const CfreeLinkExpr *expr; } CfreeLinkAssignment; typedef struct CfreeLinkOutputSection { - const char* name; - const CfreeLinkExpr* vma; /* NULL: from region/dot */ - const CfreeLinkExpr* lma; /* NULL: equal to vma */ - const CfreeLinkInputMatch* inputs; + const char *name; + const CfreeLinkExpr *vma; /* NULL: from region/dot */ + const CfreeLinkExpr *lma; /* NULL: equal to vma */ + const CfreeLinkInputMatch *inputs; uint32_t ninputs; - const char* region; /* > REGION; NULL if absent */ - const char* load_region; /* AT> REGION; NULL if absent */ - const CfreeLinkAssignment* asns; + const char *region; /* > REGION; NULL if absent */ + const char *load_region; /* AT> REGION; NULL if absent */ + const CfreeLinkAssignment *asns; uint32_t nasns; } CfreeLinkOutputSection; typedef struct CfreeLinkScript { - const char* entry; /* NULL: use CfreeLinkOptions.entry */ - const CfreeLinkRegion* regions; + const char *entry; /* NULL: use CfreeLinkOptions.entry */ + const CfreeLinkRegion *regions; uint32_t nregions; - const CfreeLinkOutputSection* sections; /* in declaration order */ + const CfreeLinkOutputSection *sections; /* in declaration order */ uint32_t nsections; - const CfreeLinkAssignment* top_asns; /* outside any SECTIONS{} */ + const CfreeLinkAssignment *top_asns; /* outside any SECTIONS{} */ uint32_t ntop_asns; } CfreeLinkScript; @@ -1006,9 +1006,9 @@ typedef struct CfreeLinkScript { * OUTPUT_FORMAT, INPUT, GROUP, elaborate file patterns, other operators) * is rejected with a diagnostic and the call returns nonzero with *out * unchanged. Returns 0 on success. */ -int cfree_link_script_parse(CfreeCompiler*, const char* text, size_t len, - const CfreeLinkScript** out); -void cfree_link_script_free(CfreeCompiler*, const CfreeLinkScript*); +int cfree_link_script_parse(CfreeCompiler *, const char *text, size_t len, + const CfreeLinkScript **out); +void cfree_link_script_free(CfreeCompiler *, const CfreeLinkScript *); /* Per-archive resolution mode (mirrors GNU ld's -Bstatic / -Bdynamic / * --as-needed positional state). Object-file inputs keep the plain @@ -1044,11 +1044,11 @@ typedef struct CfreeBytesInputArchive { * CfreeLinkSharedOptions. Adding a new input shape lands here in one * place rather than in every options struct. */ typedef struct CfreeLinkInputs { - CfreeObjBuilder* const* objs; /* fresh-compiled, by reference */ + CfreeObjBuilder *const *objs; /* fresh-compiled, by reference */ uint32_t nobjs; - const CfreeBytesInput* obj_bytes; + const CfreeBytesInput *obj_bytes; uint32_t nobj_bytes; - const CfreeBytesInputArchive* archives; + const CfreeBytesInputArchive *archives; uint32_t narchives; /* Shared-object inputs (ELF ET_DYN). Each entry's bytes are parsed * via the linker's read_elf_dso path; the DSO contributes no @@ -1056,18 +1056,18 @@ typedef struct CfreeLinkInputs { * undef resolution so references against this DSO bind dynamically. * The DSO's DT_SONAME (or its filename if missing) is recorded in * the produced image's DT_NEEDED list. */ - const CfreeBytesInput* dso_bytes; + const CfreeBytesInput *dso_bytes; uint32_t ndso_bytes; /* Structured linker script. NULL means no script (target/format default * layout). Borrowed: must outlive the cfree_link_* call. */ - const CfreeLinkScript* linker_script; - const char* entry; /* NULL = format/target default */ + const CfreeLinkScript *linker_script; + const char *entry; /* NULL = format/target default */ CfreeExternResolver extern_resolver; - void* extern_resolver_user; + void *extern_resolver_user; /* Build-ID. `build_id_mode` is a CfreeBuildIdMode. `build_id_bytes` / * `build_id_len` are consulted only when mode == CFREE_BUILDID_USER. */ uint8_t build_id_mode; - const uint8_t* build_id_bytes; + const uint8_t *build_id_bytes; uint32_t build_id_len; } CfreeLinkInputs; @@ -1087,7 +1087,7 @@ typedef struct CfreeLinkOptions { * before transferring to the entry symbol. NULL `interp_path` with * `pie==0` and no DSO inputs preserves the static ET_EXEC path. */ int pie; - const char* interp_path; + const char *interp_path; } CfreeLinkOptions; /* Options for shared-library link. @@ -1106,12 +1106,12 @@ typedef struct CfreeLinkOptions { * reference to be resolved at link time. */ typedef struct CfreeLinkSharedOptions { CfreeLinkInputs inputs; - const char* soname; - const char* const* rpaths; + const char *soname; + const char *const *rpaths; uint32_t nrpaths; - const char* const* runpaths; + const char *const *runpaths; uint32_t nrunpaths; - const char* const* exports; + const char *const *exports; uint32_t nexports; int allow_undefined; /* Section GC. See CfreeLinkOptions.gc_sections. */ @@ -1124,18 +1124,19 @@ typedef struct CfreeLinkSharedOptions { /* Link to executable. Writer is not closed by the call. On nonzero return * the Writer may contain partial output and should not be consumed. */ -int cfree_link_exe(CfreeCompiler*, const CfreeLinkOptions*, CfreeWriter* out); +int cfree_link_exe(CfreeCompiler *, const CfreeLinkOptions *, CfreeWriter *out); /* Link to shared library / dylib in the format implied by Compiler.target * (ELF .so, Mach-O .dylib, PE .dll). Writer is not closed; on nonzero * return the Writer may contain partial output and should not be * consumed. */ -int cfree_link_shared(CfreeCompiler*, const CfreeLinkSharedOptions*, - CfreeWriter* out); +int cfree_link_shared(CfreeCompiler *, const CfreeLinkSharedOptions *, + CfreeWriter *out); /* Link as JIT. On success, *out_jit owns its image and mapped pages and * must be released with cfree_jit_free. */ -int cfree_link_jit(CfreeCompiler*, const CfreeLinkOptions*, CfreeJit** out_jit); +int cfree_link_jit(CfreeCompiler *, const CfreeLinkOptions *, + CfreeJit **out_jit); /* ============================================================ * Pipeline (stateful driver-facing API) @@ -1152,22 +1153,22 @@ int cfree_link_jit(CfreeCompiler*, const CfreeLinkOptions*, CfreeJit** out_jit); * cfree_pipeline_free reaps everything in one shot. Path-shaped source * loading is the driver's job — pipeline entries take CfreeBytesInput. */ -CfreePipeline* cfree_pipeline_new(CfreeTarget, const CfreeEnv*); -void cfree_pipeline_free(CfreePipeline*); +CfreePipeline *cfree_pipeline_new(CfreeTarget, const CfreeEnv *); +void cfree_pipeline_free(CfreePipeline *); /* Borrowed; must not be freed by callers. Valid until cfree_pipeline_free. */ -CfreeCompiler* cfree_pipeline_compiler(CfreePipeline*); +CfreeCompiler *cfree_pipeline_compiler(CfreePipeline *); -int cfree_pipeline_compile_obj(CfreePipeline*, const CfreeCompileOptions*, - const CfreeBytesInput* input, - CfreeObjBuilder** out); +int cfree_pipeline_compile_obj(CfreePipeline *, const CfreeCompileOptions *, + const CfreeBytesInput *input, + CfreeObjBuilder **out); -int cfree_pipeline_link_exe(CfreePipeline*, const CfreeLinkOptions*, - CfreeWriter* out); -int cfree_pipeline_link_shared(CfreePipeline*, const CfreeLinkSharedOptions*, - CfreeWriter* out); -int cfree_pipeline_link_jit(CfreePipeline*, const CfreeLinkOptions*, - CfreeJit** out_jit); +int cfree_pipeline_link_exe(CfreePipeline *, const CfreeLinkOptions *, + CfreeWriter *out); +int cfree_pipeline_link_shared(CfreePipeline *, const CfreeLinkSharedOptions *, + CfreeWriter *out); +int cfree_pipeline_link_jit(CfreePipeline *, const CfreeLinkOptions *, + CfreeJit **out_jit); /* ============================================================ * Emulator (cfree emu) @@ -1222,12 +1223,12 @@ typedef uint32_t CfreeEmuTraceFlags; * forwarded into the host process's fd table verbatim. */ typedef struct CfreeEmuOptions { CfreeEmuArch guest_arch; - const uint8_t* guest_elf_bytes; + const uint8_t *guest_elf_bytes; size_t guest_elf_len; int optimize; CfreeEmuTraceFlags trace; - const char* const* argv; /* NULL-terminated; may be NULL */ - const char* const* envp; /* NULL-terminated; may be NULL */ + const char *const *argv; /* NULL-terminated; may be NULL */ + const char *const *envp; /* NULL-terminated; may be NULL */ } CfreeEmuOptions; typedef struct CfreeEmu CfreeEmu; @@ -1236,7 +1237,7 @@ typedef struct CfreeEmu CfreeEmu; * with the guest's exit status. Returns 0 on a clean guest exit (including * a nonzero guest exit_code), nonzero on internal failure (decode/lift * failure, OOM, unsupported guest arch). */ -int cfree_emu_run(CfreeCompiler*, const CfreeEmuOptions*, int* out_exit_code); +int cfree_emu_run(CfreeCompiler *, const CfreeEmuOptions *, int *out_exit_code); /* Lower-level surface for dbg integration. Lifecycle: emu_new constructs * the runtime (reserves the code-cache VA region, maps guest segments, @@ -1245,10 +1246,10 @@ int cfree_emu_run(CfreeCompiler*, const CfreeEmuOptions*, int* out_exit_code); * if cold and returns its host entry (NULL on translation failure or an * unmapped guest_pc). emu_free releases the runtime, the JIT image, and * the guest address space. */ -CfreeEmu* cfree_emu_new(CfreeCompiler*, const CfreeEmuOptions*); -int cfree_emu_step(CfreeEmu*, uint32_t nblocks); -void* cfree_emu_lookup(CfreeEmu*, uint64_t guest_pc); -void cfree_emu_free(CfreeEmu*); +CfreeEmu *cfree_emu_new(CfreeCompiler *, const CfreeEmuOptions *); +int cfree_emu_step(CfreeEmu *, uint32_t nblocks); +void *cfree_emu_lookup(CfreeEmu *, uint64_t guest_pc); +void cfree_emu_free(CfreeEmu *); /* ============================================================ * Binary format detection @@ -1267,14 +1268,14 @@ typedef enum CfreeBinFmt { CFREE_BIN_WASM, } CfreeBinFmt; -CfreeBinFmt cfree_detect_fmt(const uint8_t* data, size_t len); +CfreeBinFmt cfree_detect_fmt(const uint8_t *data, size_t len); /* Derive a CfreeTarget from object-file magic + headers (ELF e_machine / * EI_CLASS / EI_DATA, COFF Machine, Mach-O cputype, WASM = wasm32). Returns * 0 on success and fills *out; returns 1 when the input is not a recognized * relocatable object or its magic carries insufficient information. AR * archives are not handled here — open a member to detect its target. */ -int cfree_detect_target(const uint8_t* data, size_t len, CfreeTarget* out); +int cfree_detect_target(const uint8_t *data, size_t len, CfreeTarget *out); /* ============================================================ * Object inspection @@ -1315,7 +1316,7 @@ typedef enum CfreeSecFlag { #define CFREE_SECTION_NONE UINT32_MAX typedef struct CfreeObjSecInfo { - const char* name; /* interned; valid until cfree_obj_close */ + const char *name; /* interned; valid until cfree_obj_close */ CfreeSecKind kind; uint32_t flags; /* bitmask of CfreeSecFlag */ uint32_t size; /* bytes; BSS uses virtual size */ @@ -1325,7 +1326,7 @@ typedef struct CfreeObjSecInfo { } CfreeObjSecInfo; typedef struct CfreeObjSymInfo { - const char* name; /* interned; valid until cfree_obj_close */ + const char *name; /* interned; valid until cfree_obj_close */ CfreeSymBind bind; CfreeSymKind kind; uint32_t section; /* 0-based index, or CFREE_SECTION_NONE */ @@ -1333,28 +1334,28 @@ typedef struct CfreeObjSymInfo { uint64_t size; } CfreeObjSymInfo; -CfreeObjFile* cfree_obj_open(const CfreeEnv*, const CfreeBytesInput*); -void cfree_obj_close(CfreeObjFile*); -CfreeObjFmt cfree_obj_fmt(const CfreeObjFile*); -CfreeTarget cfree_obj_target(const CfreeObjFile*); -uint32_t cfree_obj_nsections(const CfreeObjFile*); -CfreeObjSecInfo cfree_obj_section(const CfreeObjFile*, uint32_t idx); +CfreeObjFile *cfree_obj_open(const CfreeEnv *, const CfreeBytesInput *); +void cfree_obj_close(CfreeObjFile *); +CfreeObjFmt cfree_obj_fmt(const CfreeObjFile *); +CfreeTarget cfree_obj_target(const CfreeObjFile *); +uint32_t cfree_obj_nsections(const CfreeObjFile *); +CfreeObjSecInfo cfree_obj_section(const CfreeObjFile *, uint32_t idx); -CfreeObjSymIter* cfree_obj_symiter_new(CfreeObjFile*); -int cfree_obj_symiter_next(CfreeObjSymIter*, CfreeObjSymInfo* out); -void cfree_obj_symiter_free(CfreeObjSymIter*); +CfreeObjSymIter *cfree_obj_symiter_new(CfreeObjFile *); +int cfree_obj_symiter_next(CfreeObjSymIter *, CfreeObjSymInfo *out); +void cfree_obj_symiter_free(CfreeObjSymIter *); /* Raw bytes of a section. Returns a pointer aliasing storage owned by the * CfreeObjFile and valid until cfree_obj_close. For BSS (no in-file bytes), * returns NULL with `*len_out = 0`; the section's virtual size is on * CfreeObjSecInfo.size. Out-of-range idx returns NULL with `*len_out = 0`. */ -const uint8_t* cfree_obj_section_data(const CfreeObjFile*, uint32_t idx, - size_t* len_out); +const uint8_t *cfree_obj_section_data(const CfreeObjFile *, uint32_t idx, + size_t *len_out); /* Expose the underlying CfreeObjBuilder for use with cfree_disasm_iter_new * (so the disassembler can consult sym/reloc tables for annotation). The * pointer is owned by the CfreeObjFile and is valid until cfree_obj_close. */ -CfreeObjBuilder* cfree_obj_builder(const CfreeObjFile*); +CfreeObjBuilder *cfree_obj_builder(const CfreeObjFile *); /* Relocation iterator. Walks every relocation in the object across all * sections in section-then-offset order. Strings are interned and valid @@ -1363,17 +1364,17 @@ typedef struct CfreeObjReloc { uint32_t section; /* 0-based section index the reloc applies to */ uint64_t offset; /* offset within that section */ uint32_t sym; /* opaque symbol id; CFREE_SECTION_NONE if none */ - const char* sym_name; /* interned; "" when sym is none/anonymous */ + const char *sym_name; /* interned; "" when sym is none/anonymous */ int64_t addend; uint32_t kind; /* arch-specific reloc type code */ - const char* kind_name; /* interned, e.g. "R_X86_64_PC32" */ + const char *kind_name; /* interned, e.g. "R_X86_64_PC32" */ } CfreeObjReloc; typedef struct CfreeObjRelocIter CfreeObjRelocIter; -CfreeObjRelocIter* cfree_obj_reliter_new(CfreeObjFile*); -int cfree_obj_reliter_next(CfreeObjRelocIter*, CfreeObjReloc* out); -void cfree_obj_reliter_free(CfreeObjRelocIter*); +CfreeObjRelocIter *cfree_obj_reliter_new(CfreeObjFile *); +int cfree_obj_reliter_next(CfreeObjRelocIter *, CfreeObjReloc *out); +void cfree_obj_reliter_free(CfreeObjRelocIter *); /* ============================================================ * DWARF consumer @@ -1411,14 +1412,14 @@ void cfree_obj_reliter_free(CfreeObjRelocIter*); * `pc`. */ typedef struct CfreeDebugInfo CfreeDebugInfo; -CfreeDebugInfo* cfree_dwarf_open(CfreeCompiler*, const CfreeObjFile*); -void cfree_dwarf_close(CfreeDebugInfo*); +CfreeDebugInfo *cfree_dwarf_open(CfreeCompiler *, const CfreeObjFile *); +void cfree_dwarf_close(CfreeDebugInfo *); -int cfree_dwarf_addr_to_line(CfreeDebugInfo*, uint64_t pc, - const char** file_out, uint32_t* line_out, - uint32_t* col_out); -int cfree_dwarf_line_to_addr(CfreeDebugInfo*, const char* file, uint32_t line, - uint64_t* pc_out); +int cfree_dwarf_addr_to_line(CfreeDebugInfo *, uint64_t pc, + const char **file_out, uint32_t *line_out, + uint32_t *col_out); +int cfree_dwarf_line_to_addr(CfreeDebugInfo *, const char *file, uint32_t line, + uint64_t *pc_out); /* Disambiguation enumerator paired with cfree_dwarf_line_to_addr's * ambiguous return. `out[k]` is filled for the first `cap` distinct @@ -1427,14 +1428,14 @@ int cfree_dwarf_line_to_addr(CfreeDebugInfo*, const char* file, uint32_t line, * live until cfree_dwarf_close. Returns 0 on success, 1 on invalid args. */ typedef struct CfreeDwarfLineMatch { uint64_t pc; - const char* file; + const char *file; } CfreeDwarfLineMatch; -int cfree_dwarf_line_to_addr_all(CfreeDebugInfo*, const char* file, - uint32_t line, CfreeDwarfLineMatch* out, - uint32_t cap, uint32_t* n_out); -int cfree_dwarf_func_at(CfreeDebugInfo*, uint64_t pc, const char** name_out, - uint64_t* low_pc_out, uint64_t* high_pc_out); +int cfree_dwarf_line_to_addr_all(CfreeDebugInfo *, const char *file, + uint32_t line, CfreeDwarfLineMatch *out, + uint32_t cap, uint32_t *n_out); +int cfree_dwarf_func_at(CfreeDebugInfo *, uint64_t pc, const char **name_out, + uint64_t *low_pc_out, uint64_t *high_pc_out); /* Richer subprogram description for backtrace rendering. Returns the same * name and pc range as cfree_dwarf_func_at, plus the source location of the @@ -1442,17 +1443,22 @@ int cfree_dwarf_func_at(CfreeDebugInfo*, uint64_t pc, const char** name_out, * `pc` resolves to an inlined instance). Returns 0 on success, 1 if no * subprogram contains `pc`. cfree_dwarf_func_at is kept as a thin * convenience over this entry. */ +typedef struct CfreeDwarfType CfreeDwarfType; /* opaque */ + typedef struct CfreeDwarfSubprogram { - const char* name; + const char *name; uint64_t low_pc; uint64_t high_pc; - const char* decl_file; + const char *decl_file; uint32_t decl_line; + const CfreeDwarfType *return_type; uint8_t inlined; } CfreeDwarfSubprogram; -int cfree_dwarf_subprogram_at(CfreeDebugInfo*, uint64_t pc, - CfreeDwarfSubprogram* out); +int cfree_dwarf_subprogram_at(CfreeDebugInfo *, uint64_t pc, + CfreeDwarfSubprogram *out); +int cfree_dwarf_subprogram_named(CfreeDebugInfo *, const char *name, + CfreeDwarfSubprogram *out); /* CFI-driven unwind step. The caller seeds `frame->pc` (and any callee-saved * registers known at the leaf) and the consumer walks .eh_frame to compute @@ -1461,7 +1467,7 @@ int cfree_dwarf_subprogram_at(CfreeDebugInfo*, uint64_t pc, * follow the DWARF register numbering for the target arch (which matches * CfreeArchKind's canonical mapping). Returns 0 on a successful step, 1 at the * bottom of the stack (no caller), nonzero on decode error. */ -int cfree_dwarf_unwind_step(CfreeDebugInfo*, CfreeUnwindFrame*); +int cfree_dwarf_unwind_step(CfreeDebugInfo *, CfreeUnwindFrame *); /* ----- Variable locations ----- * @@ -1507,47 +1513,45 @@ typedef enum CfreeDwarfTypeKind { CFREE_DT_TYPEDEF, /* alias name + underlying */ } CfreeDwarfTypeKind; -typedef struct CfreeDwarfType CfreeDwarfType; /* opaque */ - typedef struct CfreeDwarfTypeInfo { CfreeDwarfTypeKind kind; uint32_t byte_size; /* 0 = unknown / void */ - const char* name; /* tag/typedef name; "" if anon */ + const char *name; /* tag/typedef name; "" if anon */ /* For ARRAY: element_count == 0 means flexible/unknown. */ uint32_t element_count; /* For PTR/ARRAY/TYPEDEF: the inner type (NULL otherwise). */ - const CfreeDwarfType* inner; + const CfreeDwarfType *inner; } CfreeDwarfTypeInfo; -CfreeDwarfTypeInfo cfree_dwarf_type_info(const CfreeDwarfType*); +CfreeDwarfTypeInfo cfree_dwarf_type_info(const CfreeDwarfType *); /* Struct/union field iterator. Yields each direct field; nested aggregates * are reached by recursing on field.type. */ typedef struct CfreeDwarfFieldIter CfreeDwarfFieldIter; typedef struct CfreeDwarfField { - const char* name; /* "" for anonymous */ + const char *name; /* "" for anonymous */ uint32_t byte_offset; uint32_t bit_offset; /* for bitfields; 0 otherwise */ uint32_t bit_size; /* for bitfields; 0 otherwise */ - const CfreeDwarfType* type; + const CfreeDwarfType *type; } CfreeDwarfField; -CfreeDwarfFieldIter* cfree_dwarf_field_iter_new(CfreeDebugInfo*, - const CfreeDwarfType*); -int cfree_dwarf_field_iter_next(CfreeDwarfFieldIter*, CfreeDwarfField* out); -void cfree_dwarf_field_iter_free(CfreeDwarfFieldIter*); +CfreeDwarfFieldIter *cfree_dwarf_field_iter_new(CfreeDebugInfo *, + const CfreeDwarfType *); +int cfree_dwarf_field_iter_next(CfreeDwarfFieldIter *, CfreeDwarfField *out); +void cfree_dwarf_field_iter_free(CfreeDwarfFieldIter *); /* Enum value iterator. */ typedef struct CfreeDwarfEnumIter CfreeDwarfEnumIter; typedef struct CfreeDwarfEnumVal { - const char* name; + const char *name; int64_t value; } CfreeDwarfEnumVal; -CfreeDwarfEnumIter* cfree_dwarf_enum_iter_new(CfreeDebugInfo*, - const CfreeDwarfType*); -int cfree_dwarf_enum_iter_next(CfreeDwarfEnumIter*, CfreeDwarfEnumVal* out); -void cfree_dwarf_enum_iter_free(CfreeDwarfEnumIter*); +CfreeDwarfEnumIter *cfree_dwarf_enum_iter_new(CfreeDebugInfo *, + const CfreeDwarfType *); +int cfree_dwarf_enum_iter_next(CfreeDwarfEnumIter *, CfreeDwarfEnumVal *out); +void cfree_dwarf_enum_iter_free(CfreeDwarfEnumIter *); typedef enum CfreeDwarfLocKind { CFREE_DLOC_REG, /* value lives in a register */ @@ -1562,13 +1566,13 @@ typedef struct CfreeDwarfVarLoc { /* DIE type of the variable. NULL when type information was not * recovered (e.g. stripped binary, hand-written symbol). When NULL, * callers should fall back to byte_size and treat the bytes opaquely. */ - const CfreeDwarfType* type; + const CfreeDwarfType *type; union { uint32_t reg; int32_t frame_ofs; uint64_t global; struct { - const uint8_t* bytes; + const uint8_t *bytes; size_t len; } expr; } v; @@ -1580,12 +1584,12 @@ typedef struct CfreeDwarfVarLoc { * resolves there (typo / out-of-scope). * 2 — `pc` is not covered by any subprogram (no debug info for this * frame); globals were still consulted before returning. */ -int cfree_dwarf_var_at(CfreeDebugInfo*, uint64_t pc, const char* name, - CfreeDwarfVarLoc* out); -int cfree_dwarf_loc_read(CfreeDebugInfo*, const CfreeDwarfVarLoc*, - const CfreeUnwindFrame*, - CfreeJitSession*, /* memory provider */ - void* dst, size_t cap, size_t* read_out); +int cfree_dwarf_var_at(CfreeDebugInfo *, uint64_t pc, const char *name, + CfreeDwarfVarLoc *out); +int cfree_dwarf_loc_read(CfreeDebugInfo *, const CfreeDwarfVarLoc *, + const CfreeUnwindFrame *, + CfreeJitSession *, /* memory provider */ + void *dst, size_t cap, size_t *read_out); /* ----- Locals, arguments, and parameters ----- * @@ -1604,26 +1608,28 @@ typedef enum CfreeDwarfVarRole { } CfreeDwarfVarRole; typedef struct CfreeDwarfVar { - const char* name; + const char *name; CfreeDwarfVarRole role; CfreeDwarfVarLoc loc; } CfreeDwarfVar; typedef struct CfreeDwarfVarIter CfreeDwarfVarIter; -CfreeDwarfVarIter* cfree_dwarf_vars_at_new(CfreeDebugInfo*, uint64_t pc, +CfreeDwarfVarIter *cfree_dwarf_vars_at_new(CfreeDebugInfo *, uint64_t pc, uint32_t role_mask); -int cfree_dwarf_vars_at_next(CfreeDwarfVarIter*, CfreeDwarfVar* out); -void cfree_dwarf_vars_at_free(CfreeDwarfVarIter*); +int cfree_dwarf_vars_at_next(CfreeDwarfVarIter *, CfreeDwarfVar *out); +void cfree_dwarf_vars_at_free(CfreeDwarfVarIter *); /* Iterate the formal parameters of the subprogram covering `pc`, in * declaration order. Drives gdb-style backtrace argument rendering. * Returns NULL if `pc` is not inside any subprogram. */ typedef struct CfreeDwarfParamIter CfreeDwarfParamIter; -CfreeDwarfParamIter* cfree_dwarf_param_iter_new(CfreeDebugInfo*, uint64_t pc); -int cfree_dwarf_param_iter_next(CfreeDwarfParamIter*, CfreeDwarfVar* out); -void cfree_dwarf_param_iter_free(CfreeDwarfParamIter*); +CfreeDwarfParamIter *cfree_dwarf_param_iter_new(CfreeDebugInfo *, uint64_t pc); +CfreeDwarfParamIter *cfree_dwarf_param_iter_new_named(CfreeDebugInfo *, + const char *name); +int cfree_dwarf_param_iter_next(CfreeDwarfParamIter *, CfreeDwarfVar *out); +void cfree_dwarf_param_iter_free(CfreeDwarfParamIter *); /* ============================================================ * Disassembler @@ -1644,17 +1650,18 @@ void cfree_dwarf_param_iter_free(CfreeDwarfParamIter*); typedef struct CfreeInsn { uint64_t vaddr; - const uint8_t* bytes; + const uint8_t *bytes; uint32_t nbytes; - const char* mnemonic; - const char* operands; /* pre-rendered; may be "" */ - const char* annotation; /* sym/reloc note; may be "" */ + const char *mnemonic; + const char *operands; /* pre-rendered; may be "" */ + const char *annotation; /* sym/reloc note; may be "" */ } CfreeInsn; /* Walk a relocatable object's text sections and write an objdump-style * listing to `out`. Convenience over the iterator. The Writer is not * closed. Returns 0 on success, nonzero on failure. */ -int cfree_obj_disasm(CfreeCompiler*, const CfreeBytesInput*, CfreeWriter* out); +int cfree_obj_disasm(CfreeCompiler *, const CfreeBytesInput *, + CfreeWriter *out); /* Iterate instructions in a byte buffer at virtual address `vaddr`. If * `obj` is non-NULL, the decoder consults its symbol and relocation tables @@ -1667,11 +1674,11 @@ int cfree_obj_disasm(CfreeCompiler*, const CfreeBytesInput*, CfreeWriter* out); * mnemonic so the listing stays in sync. */ typedef struct CfreeDisasmIter CfreeDisasmIter; -CfreeDisasmIter* cfree_disasm_iter_new(CfreeCompiler*, const uint8_t* bytes, +CfreeDisasmIter *cfree_disasm_iter_new(CfreeCompiler *, const uint8_t *bytes, size_t len, uint64_t vaddr, - CfreeObjBuilder* obj /* may be NULL */); -int cfree_disasm_iter_next(CfreeDisasmIter*, CfreeInsn* out); -void cfree_disasm_iter_free(CfreeDisasmIter*); + CfreeObjBuilder *obj /* may be NULL */); +int cfree_disasm_iter_next(CfreeDisasmIter *, CfreeInsn *out); +void cfree_disasm_iter_free(CfreeDisasmIter *); /* ============================================================ * Archive (ar) file @@ -1716,7 +1723,7 @@ void cfree_disasm_iter_free(CfreeDisasmIter*); * in iterator-owned storage and is valid only until the next iter_next * call on the same iterator. */ typedef struct CfreeArMemberSymbols { - const char* const* names; /* count entries; each NUL-terminated */ + const char *const *names; /* count entries; each NUL-terminated */ uint32_t count; } CfreeArMemberSymbols; @@ -1726,28 +1733,28 @@ typedef struct CfreeArWriteOptions { int long_names; /* emit '//' long-name table when needed */ /* Parallel to the `members` array; NULL means "no symbols anywhere". * Only consulted when symbol_index is nonzero. */ - const CfreeArMemberSymbols* member_symbols; + const CfreeArMemberSymbols *member_symbols; } CfreeArWriteOptions; -int cfree_ar_write(CfreeWriter* out, const CfreeBytesInput* members, - uint32_t nmembers, const CfreeArWriteOptions* opts); -int cfree_ar_list(const CfreeBytesInput* archive, CfreeWriter* out); +int cfree_ar_write(CfreeWriter *out, const CfreeBytesInput *members, + uint32_t nmembers, const CfreeArWriteOptions *opts); +int cfree_ar_list(const CfreeBytesInput *archive, CfreeWriter *out); typedef struct CfreeArIter { - const uint8_t* _p; - const uint8_t* _end; - const uint8_t* _longnames; /* `//` table bytes, NULL until seen */ + const uint8_t *_p; + const uint8_t *_end; + const uint8_t *_longnames; /* `//` table bytes, NULL until seen */ size_t _longnames_len; char _namebuf[256]; /* iterator-owned scratch for member name */ } CfreeArIter; typedef struct CfreeArMember { - const char* name; /* iterator-owned; valid until next iter_next */ - const uint8_t* data; /* points into archive bytes */ + const char *name; /* iterator-owned; valid until next iter_next */ + const uint8_t *data; /* points into archive bytes */ size_t size; } CfreeArMember; -int cfree_ar_iter_init(CfreeArIter*, const CfreeBytesInput* archive); -int cfree_ar_iter_next(CfreeArIter*, CfreeArMember* out); +int cfree_ar_iter_init(CfreeArIter *, const CfreeBytesInput *archive); +int cfree_ar_iter_next(CfreeArIter *, CfreeArMember *out); #endif diff --git a/src/api/cg.c b/src/api/cg.c @@ -13,6 +13,7 @@ #include "core/heap.h" #include "core/pool.h" #include "core/segvec.h" +#include "debug/debug.h" #include "obj/obj.h" #include "opt/opt.h" @@ -33,9 +34,9 @@ typedef struct CgApiType { u32 flags; u32 address_space; u64 array_count; - const CfreeCgField* fields; - const CfreeCgEnumValue* values; - const CfreeCgParam* params; + const CfreeCgField *fields; + const CfreeCgEnumValue *values; + const CfreeCgParam *params; CfreeCgAbiAttrs ret_attrs; CfreeCgCallConv call_conv; u8 kind; @@ -46,7 +47,7 @@ typedef struct CgApiType { SEGVEC_DEFINE(CgApiTypes, CgApiType, CG_API_TYPE_SEG_SHIFT); typedef struct CgApiState { - Heap* heap; + Heap *heap; CgApiTypes types; CgType builtins[CFREE_CG_BUILTIN_COUNT]; u8 builtins_init; @@ -62,10 +63,11 @@ static CfreeCgTypeId builtin_id(CfreeCgBuiltinType t) { return type_id_from_tuple(CG_API_TYPE_BUILTIN_SEG, (u32)t); } -static int decode_user_id(CfreeCgTypeId id, u32* index_out) { +static int decode_user_id(CfreeCgTypeId id, u32 *index_out) { u32 seg = id >> CG_API_TYPE_SEG_SHIFT; u32 off = id & CG_API_TYPE_SEG_MASK; - if (seg < CG_API_TYPE_USER_SEG_BIAS) return 0; + if (seg < CG_API_TYPE_USER_SEG_BIAS) + return 0; *index_out = ((seg - CG_API_TYPE_USER_SEG_BIAS) << CG_API_TYPE_SEG_SHIFT) | off; return 1; @@ -90,90 +92,94 @@ static u64 cg_align_to(u64 n, u32 align) { return ((n + a - 1u) / a) * a; } -static void builtin_cg_type_init(Compiler* c, CgType* out, +static void builtin_cg_type_init(Compiler *c, CgType *out, CfreeCgBuiltinType t) { memset(out, 0, sizeof(*out)); switch (t) { - case CFREE_CG_BUILTIN_VOID: - out->kind = CFREE_CG_TYPE_VOID; - out->align = 1; - break; - case CFREE_CG_BUILTIN_BOOL: - out->kind = CFREE_CG_TYPE_BOOL; - out->size = 1; - out->align = 1; - out->integer.width = 8; - break; - case CFREE_CG_BUILTIN_I8: - out->kind = CFREE_CG_TYPE_INT; - out->size = 1; - out->align = 1; - out->integer.width = 8; - break; - case CFREE_CG_BUILTIN_I16: - out->kind = CFREE_CG_TYPE_INT; - out->size = 2; - out->align = 2; - out->integer.width = 16; - break; - case CFREE_CG_BUILTIN_I32: - out->kind = CFREE_CG_TYPE_INT; - out->size = 4; - out->align = 4; - out->integer.width = 32; - break; - case CFREE_CG_BUILTIN_I64: - out->kind = CFREE_CG_TYPE_INT; - out->size = 8; - out->align = 8; - out->integer.width = 64; - break; - case CFREE_CG_BUILTIN_I128: - out->kind = CFREE_CG_TYPE_INT; - out->size = 16; - out->align = 16; - out->integer.width = 128; - break; - case CFREE_CG_BUILTIN_F32: - out->kind = CFREE_CG_TYPE_FLOAT; - out->size = 4; - out->align = 4; - out->fp.width = 32; - break; - case CFREE_CG_BUILTIN_F64: - out->kind = CFREE_CG_TYPE_FLOAT; - out->size = 8; - out->align = 8; - out->fp.width = 64; - break; - case CFREE_CG_BUILTIN_VARARG_STATE: { - ABITypeInfo info = abi_va_list_info(c->abi); - out->kind = CFREE_CG_TYPE_VARARG_STATE; - out->size = info.size; - out->align = info.align ? info.align : 1; - break; - } - case CFREE_CG_BUILTIN_COUNT: - break; - } -} - -static void cg_api_init_builtins(Compiler* c, CgApiState* s) { - if (s->builtins_init) return; + case CFREE_CG_BUILTIN_VOID: + out->kind = CFREE_CG_TYPE_VOID; + out->align = 1; + break; + case CFREE_CG_BUILTIN_BOOL: + out->kind = CFREE_CG_TYPE_BOOL; + out->size = 1; + out->align = 1; + out->integer.width = 8; + break; + case CFREE_CG_BUILTIN_I8: + out->kind = CFREE_CG_TYPE_INT; + out->size = 1; + out->align = 1; + out->integer.width = 8; + break; + case CFREE_CG_BUILTIN_I16: + out->kind = CFREE_CG_TYPE_INT; + out->size = 2; + out->align = 2; + out->integer.width = 16; + break; + case CFREE_CG_BUILTIN_I32: + out->kind = CFREE_CG_TYPE_INT; + out->size = 4; + out->align = 4; + out->integer.width = 32; + break; + case CFREE_CG_BUILTIN_I64: + out->kind = CFREE_CG_TYPE_INT; + out->size = 8; + out->align = 8; + out->integer.width = 64; + break; + case CFREE_CG_BUILTIN_I128: + out->kind = CFREE_CG_TYPE_INT; + out->size = 16; + out->align = 16; + out->integer.width = 128; + break; + case CFREE_CG_BUILTIN_F32: + out->kind = CFREE_CG_TYPE_FLOAT; + out->size = 4; + out->align = 4; + out->fp.width = 32; + break; + case CFREE_CG_BUILTIN_F64: + out->kind = CFREE_CG_TYPE_FLOAT; + out->size = 8; + out->align = 8; + out->fp.width = 64; + break; + case CFREE_CG_BUILTIN_VARARG_STATE: { + ABITypeInfo info = abi_va_list_info(c->abi); + out->kind = CFREE_CG_TYPE_VARARG_STATE; + out->size = info.size; + out->align = info.align ? info.align : 1; + break; + } + case CFREE_CG_BUILTIN_COUNT: + break; + } +} + +static void cg_api_init_builtins(Compiler *c, CgApiState *s) { + if (s->builtins_init) + return; for (u32 i = 0; i < CFREE_CG_BUILTIN_COUNT; ++i) { builtin_cg_type_init(c, &s->builtins[i], (CfreeCgBuiltinType)i); } s->builtins_init = 1; } -static CgApiState* cg_api_get(Compiler* c) { - Heap* h; - CgApiState* s; - if (!c) return NULL; - if (c->cg_api) return (CgApiState*)c->cg_api; - h = (Heap*)c->env->heap; - s = (CgApiState*)h->alloc(h, sizeof(*s), _Alignof(CgApiState)); - if (!s) return NULL; +static CgApiState *cg_api_get(Compiler *c) { + Heap *h; + CgApiState *s; + if (!c) + return NULL; + if (c->cg_api) + return (CgApiState *)c->cg_api; + h = (Heap *)c->env->heap; + s = (CgApiState *)h->alloc(h, sizeof(*s), _Alignof(CgApiState)); + if (!s) + return NULL; memset(s, 0, sizeof(*s)); s->heap = h; CgApiTypes_init(&s->types, h); @@ -183,20 +189,23 @@ static CgApiState* cg_api_get(Compiler* c) { return s; } -static CgApiType* api_type_from_id(Compiler* c, CfreeCgTypeId id); +static CgApiType *api_type_from_id(Compiler *c, CfreeCgTypeId id); -const CgType* cg_type_get(Compiler* c, CfreeCgTypeId id) { +const CgType *cg_type_get(Compiler *c, CfreeCgTypeId id) { u32 seg; u32 off; - CgApiState* s; - CgApiType* e; - if (!c || id == CFREE_CG_TYPE_NONE) return NULL; + CgApiState *s; + CgApiType *e; + if (!c || id == CFREE_CG_TYPE_NONE) + return NULL; seg = id >> CG_API_TYPE_SEG_SHIFT; off = id & CG_API_TYPE_SEG_MASK; if (seg == CG_API_TYPE_BUILTIN_SEG) { - if (off >= CFREE_CG_BUILTIN_COUNT) return NULL; + if (off >= CFREE_CG_BUILTIN_COUNT) + return NULL; s = cg_api_get(c); - if (!s) return NULL; + if (!s) + return NULL; cg_api_init_builtins(c, s); return &s->builtins[off]; } @@ -204,105 +213,116 @@ const CgType* cg_type_get(Compiler* c, CfreeCgTypeId id) { return e ? &e->cg : NULL; } -uint64_t cg_type_size(Compiler* c, CfreeCgTypeId id) { - const CgType* ty = cg_type_get(c, id); +uint64_t cg_type_size(Compiler *c, CfreeCgTypeId id) { + const CgType *ty = cg_type_get(c, id); return ty ? ty->size : 0; } -uint32_t cg_type_align(Compiler* c, CfreeCgTypeId id) { - const CgType* ty = cg_type_get(c, id); +uint32_t cg_type_align(Compiler *c, CfreeCgTypeId id) { + const CgType *ty = cg_type_get(c, id); return ty ? ty->align : 0; } -int cg_type_is_int(Compiler* c, CfreeCgTypeId id) { - const CgType* ty = cg_type_get(c, id); +int cg_type_is_int(Compiler *c, CfreeCgTypeId id) { + const CgType *ty = cg_type_get(c, id); if (ty && ty->kind == CFREE_CG_TYPE_ALIAS) { return cg_type_is_int(c, ty->alias.base); } - return ty && (ty->kind == CFREE_CG_TYPE_INT || - ty->kind == CFREE_CG_TYPE_BOOL || - ty->kind == CFREE_CG_TYPE_ENUM); + return ty && + (ty->kind == CFREE_CG_TYPE_INT || ty->kind == CFREE_CG_TYPE_BOOL || + ty->kind == CFREE_CG_TYPE_ENUM); } -int cg_type_is_float(Compiler* c, CfreeCgTypeId id) { - const CgType* ty = cg_type_get(c, id); +int cg_type_is_float(Compiler *c, CfreeCgTypeId id) { + const CgType *ty = cg_type_get(c, id); if (ty && ty->kind == CFREE_CG_TYPE_ALIAS) { return cg_type_is_float(c, ty->alias.base); } return ty && ty->kind == CFREE_CG_TYPE_FLOAT; } -int cg_type_is_ptr(Compiler* c, CfreeCgTypeId id) { - const CgType* ty = cg_type_get(c, id); +int cg_type_is_ptr(Compiler *c, CfreeCgTypeId id) { + const CgType *ty = cg_type_get(c, id); if (ty && ty->kind == CFREE_CG_TYPE_ALIAS) { return cg_type_is_ptr(c, ty->alias.base); } return ty && ty->kind == CFREE_CG_TYPE_PTR; } -int cg_type_is_record(Compiler* c, CfreeCgTypeId id) { - const CgType* ty = cg_type_get(c, id); +int cg_type_is_record(Compiler *c, CfreeCgTypeId id) { + const CgType *ty = cg_type_get(c, id); if (ty && ty->kind == CFREE_CG_TYPE_ALIAS) { return cg_type_is_record(c, ty->alias.base); } return ty && ty->kind == CFREE_CG_TYPE_RECORD; } -static int cg_type_is_void(Compiler* c, CfreeCgTypeId id) { - const CgType* ty = cg_type_get(c, id); - if (ty && ty->kind == CFREE_CG_TYPE_ALIAS) return cg_type_is_void(c, ty->alias.base); +static int cg_type_is_void(Compiler *c, CfreeCgTypeId id) { + const CgType *ty = cg_type_get(c, id); + if (ty && ty->kind == CFREE_CG_TYPE_ALIAS) + return cg_type_is_void(c, ty->alias.base); return ty && ty->kind == CFREE_CG_TYPE_VOID; } -static int cg_type_is_aggregate(Compiler* c, CfreeCgTypeId id) { +static int cg_type_is_aggregate(Compiler *c, CfreeCgTypeId id) { return cg_type_is_record(c, id); } -static CfreeCgTypeId cg_type_ptr_to(Compiler* c, CfreeCgTypeId pointee) { +static CfreeCgTypeId cg_type_ptr_to(Compiler *c, CfreeCgTypeId pointee) { return cfree_cg_type_ptr(c, pointee, 0); } -static CfreeCgTypeId cg_type_pointee(Compiler* c, CfreeCgTypeId id) { - const CgType* ty = cg_type_get(c, id); - if (ty && ty->kind == CFREE_CG_TYPE_ALIAS) return cg_type_pointee(c, ty->alias.base); - return ty && ty->kind == CFREE_CG_TYPE_PTR ? ty->ptr.pointee : CFREE_CG_TYPE_NONE; +static CfreeCgTypeId cg_type_pointee(Compiler *c, CfreeCgTypeId id) { + const CgType *ty = cg_type_get(c, id); + if (ty && ty->kind == CFREE_CG_TYPE_ALIAS) + return cg_type_pointee(c, ty->alias.base); + return ty && ty->kind == CFREE_CG_TYPE_PTR ? ty->ptr.pointee + : CFREE_CG_TYPE_NONE; } -static CfreeCgTypeId cg_type_func_ret_id(Compiler* c, CfreeCgTypeId id) { - const CgType* ty = cg_type_get(c, id); - if (ty && ty->kind == CFREE_CG_TYPE_ALIAS) return cg_type_func_ret_id(c, ty->alias.base); - return ty && ty->kind == CFREE_CG_TYPE_FUNC ? ty->func.ret : CFREE_CG_TYPE_NONE; +static CfreeCgTypeId cg_type_func_ret_id(Compiler *c, CfreeCgTypeId id) { + const CgType *ty = cg_type_get(c, id); + if (ty && ty->kind == CFREE_CG_TYPE_ALIAS) + return cg_type_func_ret_id(c, ty->alias.base); + return ty && ty->kind == CFREE_CG_TYPE_FUNC ? ty->func.ret + : CFREE_CG_TYPE_NONE; } -static CfreeCgTypeId cg_type_func_param_id(Compiler* c, CfreeCgTypeId id, +static CfreeCgTypeId cg_type_func_param_id(Compiler *c, CfreeCgTypeId id, u32 index) { - const CgType* ty = cg_type_get(c, id); - if (ty && ty->kind == CFREE_CG_TYPE_ALIAS) return cg_type_func_param_id(c, ty->alias.base, index); - if (!ty || ty->kind != CFREE_CG_TYPE_FUNC || index >= ty->func.nparams) return CFREE_CG_TYPE_NONE; + const CgType *ty = cg_type_get(c, id); + if (ty && ty->kind == CFREE_CG_TYPE_ALIAS) + return cg_type_func_param_id(c, ty->alias.base, index); + if (!ty || ty->kind != CFREE_CG_TYPE_FUNC || index >= ty->func.nparams) + return CFREE_CG_TYPE_NONE; return ty->func.params[index].type; } -static CgApiType* type_alloc(Compiler* c, CfreeCgTypeId* id_out) { - CgApiState* s = cg_api_get(c); - CgApiType* e; +static CgApiType *type_alloc(Compiler *c, CfreeCgTypeId *id_out) { + CgApiState *s = cg_api_get(c); + CgApiType *e; u32 index; - if (!s) return NULL; + if (!s) + return NULL; e = CgApiTypes_push(&s->types, &index); - if (!e) return NULL; + if (!e) + return NULL; *id_out = user_id_from_index(index); - if (*id_out == CFREE_CG_TYPE_NONE) return NULL; + if (*id_out == CFREE_CG_TYPE_NONE) + return NULL; return e; } -static CfreeCgTypeId find_ptr_type_id(Compiler* c, CfreeCgTypeId pointee, +static CfreeCgTypeId find_ptr_type_id(Compiler *c, CfreeCgTypeId pointee, u32 address_space) { - CgApiState* s; + CgApiState *s; u32 n; - if (!c || !c->cg_api) return CFREE_CG_TYPE_NONE; - s = (CgApiState*)c->cg_api; + if (!c || !c->cg_api) + return CFREE_CG_TYPE_NONE; + s = (CgApiState *)c->cg_api; n = CgApiTypes_count(&s->types); for (u32 i = 0; i < n; ++i) { - CgApiType* e = CgApiTypes_at(&s->types, i); + CgApiType *e = CgApiTypes_at(&s->types, i); if (e && e->kind == CG_API_TYPE_PTR && e->base == pointee && e->address_space == address_space) return type_id_for_user_index(i); @@ -310,15 +330,16 @@ static CfreeCgTypeId find_ptr_type_id(Compiler* c, CfreeCgTypeId pointee, return CFREE_CG_TYPE_NONE; } -static CfreeCgTypeId find_array_type_id(Compiler* c, CfreeCgTypeId elem, +static CfreeCgTypeId find_array_type_id(Compiler *c, CfreeCgTypeId elem, u64 count) { - CgApiState* s; + CgApiState *s; u32 n; - if (!c || !c->cg_api) return CFREE_CG_TYPE_NONE; - s = (CgApiState*)c->cg_api; + if (!c || !c->cg_api) + return CFREE_CG_TYPE_NONE; + s = (CgApiState *)c->cg_api; n = CgApiTypes_count(&s->types); for (u32 i = 0; i < n; ++i) { - CgApiType* e = CgApiTypes_at(&s->types, i); + CgApiType *e = CgApiTypes_at(&s->types, i); if (e && e->kind == CG_API_TYPE_ARRAY && e->base == elem && e->array_count == count) return type_id_for_user_index(i); @@ -326,7 +347,7 @@ static CfreeCgTypeId find_array_type_id(Compiler* c, CfreeCgTypeId elem, return CFREE_CG_TYPE_NONE; } -static int cg_params_eq(const CfreeCgParam* a, const CfreeCgParam* b, u32 n) { +static int cg_params_eq(const CfreeCgParam *a, const CfreeCgParam *b, u32 n) { for (u32 i = 0; i < n; ++i) if (a[i].type != b[i].type || memcmp(&a[i].attrs, &b[i].attrs, sizeof(a[i].attrs)) != 0) { @@ -335,18 +356,23 @@ static int cg_params_eq(const CfreeCgParam* a, const CfreeCgParam* b, u32 n) { return 1; } -static CfreeCgTypeId find_func_type_id(Compiler* c, CfreeCgFuncSig sig) { - CgApiState* s; +static CfreeCgTypeId find_func_type_id(Compiler *c, CfreeCgFuncSig sig) { + CgApiState *s; u32 n; - if (!c || !c->cg_api) return CFREE_CG_TYPE_NONE; - s = (CgApiState*)c->cg_api; + if (!c || !c->cg_api) + return CFREE_CG_TYPE_NONE; + s = (CgApiState *)c->cg_api; n = CgApiTypes_count(&s->types); for (u32 i = 0; i < n; ++i) { - CgApiType* e = CgApiTypes_at(&s->types, i); - if (!e || e->kind != CG_API_TYPE_FUNC) continue; - if (e->base != sig.ret || e->count != sig.nparams) continue; - if (e->abi_variadic != (sig.abi_variadic != 0)) continue; - if (e->call_conv != sig.call_conv) continue; + CgApiType *e = CgApiTypes_at(&s->types, i); + if (!e || e->kind != CG_API_TYPE_FUNC) + continue; + if (e->base != sig.ret || e->count != sig.nparams) + continue; + if (e->abi_variadic != (sig.abi_variadic != 0)) + continue; + if (e->call_conv != sig.call_conv) + continue; if (memcmp(&e->ret_attrs, &sig.ret_attrs, sizeof(e->ret_attrs)) != 0) { continue; } @@ -358,41 +384,51 @@ static CfreeCgTypeId find_func_type_id(Compiler* c, CfreeCgFuncSig sig) { return CFREE_CG_TYPE_NONE; } -static CgApiType* api_type_from_id(Compiler* c, CfreeCgTypeId id) { +static CgApiType *api_type_from_id(Compiler *c, CfreeCgTypeId id) { u32 index; - CgApiState* s; - CgApiType* e; - if (!c || id == CFREE_CG_TYPE_NONE) return NULL; - if ((id >> CG_API_TYPE_SEG_SHIFT) == CG_API_TYPE_BUILTIN_SEG) return NULL; - if (!decode_user_id(id, &index)) return NULL; - s = (CgApiState*)c->cg_api; - if (!s) return NULL; + CgApiState *s; + CgApiType *e; + if (!c || id == CFREE_CG_TYPE_NONE) + return NULL; + if ((id >> CG_API_TYPE_SEG_SHIFT) == CG_API_TYPE_BUILTIN_SEG) + return NULL; + if (!decode_user_id(id, &index)) + return NULL; + s = (CgApiState *)c->cg_api; + if (!s) + return NULL; e = CgApiTypes_at(&s->types, index); return e; } -static CfreeCgTypeId resolve_type(Compiler* c, CfreeCgTypeId id) { +static CfreeCgTypeId resolve_type(Compiler *c, CfreeCgTypeId id) { return cg_type_get(c, id) ? id : CFREE_CG_TYPE_NONE; } -static CfreeCgParam* copy_cg_params(Compiler* c, const CfreeCgParam* src, +static CfreeCgParam *copy_cg_params(Compiler *c, const CfreeCgParam *src, u32 n) { - CfreeCgParam* dst; - if (!n) return NULL; - if (!src) return NULL; + CfreeCgParam *dst; + if (!n) + return NULL; + if (!src) + return NULL; dst = arena_array(&c->global->arena, CfreeCgParam, n); - if (!dst) return NULL; + if (!dst) + return NULL; memcpy(dst, src, sizeof(*dst) * n); return dst; } -static CgTypeField* copy_cg_fields(Compiler* c, const CfreeCgField* src, +static CgTypeField *copy_cg_fields(Compiler *c, const CfreeCgField *src, u32 n) { - CgTypeField* dst; - if (!n) return NULL; - if (!src) return NULL; + CgTypeField *dst; + if (!n) + return NULL; + if (!src) + return NULL; dst = arena_array(&c->global->arena, CgTypeField, n); - if (!dst) return NULL; + if (!dst) + return NULL; memset(dst, 0, sizeof(*dst) * n); for (u32 i = 0; i < n; ++i) { dst[i].name = src[i].name; @@ -402,39 +438,46 @@ static CgTypeField* copy_cg_fields(Compiler* c, const CfreeCgField* src, return dst; } -static int cg_type_layout_record(Compiler* c, CgType* cg) { +static int cg_type_layout_record(Compiler *c, CgType *cg) { u32 max_align = 1; u64 size = 0; - if (!c || !cg || cg->kind != CFREE_CG_TYPE_RECORD) return 0; - if (cg->record.nfields && !cg->record.fields) return 0; + if (!c || !cg || cg->kind != CFREE_CG_TYPE_RECORD) + return 0; + if (cg->record.nfields && !cg->record.fields) + return 0; if (cg->record.is_union) { for (u32 i = 0; i < cg->record.nfields; ++i) { - CgTypeField* f = &cg->record.fields[i]; + CgTypeField *f = &cg->record.fields[i]; u64 fsize = cg_type_size(c, f->type); u32 falign = cg_type_align(c, f->type); - if (!falign) return 0; + if (!falign) + return 0; if (f->align_override == 1u) { falign = 1; } else if (f->align_override > falign) { falign = f->align_override; } - if (falign > max_align) max_align = falign; - if (fsize > size) size = fsize; + if (falign > max_align) + max_align = falign; + if (fsize > size) + size = fsize; f->offset = 0; } } else { u64 off = 0; for (u32 i = 0; i < cg->record.nfields; ++i) { - CgTypeField* f = &cg->record.fields[i]; + CgTypeField *f = &cg->record.fields[i]; u64 fsize = cg_type_size(c, f->type); u32 falign = cg_type_align(c, f->type); - if (!falign) return 0; + if (!falign) + return 0; if (f->align_override == 1u) { falign = 1; } else if (f->align_override > falign) { falign = f->align_override; } - if (falign > max_align) max_align = falign; + if (falign > max_align) + max_align = falign; off = cg_align_to(off, falign); f->offset = off; off += fsize; @@ -449,11 +492,12 @@ static int cg_type_layout_record(Compiler* c, CgType* cg) { return 1; } -static int cg_type_set_ptr(Compiler* c, CgApiType* e, CfreeCgTypeId pointee, +static int cg_type_set_ptr(Compiler *c, CgApiType *e, CfreeCgTypeId pointee, u32 address_space) { u32 ptr_size; u32 ptr_align; - if (!cg_type_get(c, pointee)) return 0; + if (!cg_type_get(c, pointee)) + return 0; memset(&e->cg, 0, sizeof(e->cg)); ptr_size = c->target.ptr_size ? c->target.ptr_size : 8; ptr_align = c->target.ptr_align ? c->target.ptr_align : ptr_size; @@ -465,10 +509,11 @@ static int cg_type_set_ptr(Compiler* c, CgApiType* e, CfreeCgTypeId pointee, return 1; } -static int cg_type_set_array(Compiler* c, CgApiType* e, CfreeCgTypeId elem, +static int cg_type_set_array(Compiler *c, CgApiType *e, CfreeCgTypeId elem, u64 count) { - const CgType* ety = cg_type_get(c, elem); - if (!ety) return 0; + const CgType *ety = cg_type_get(c, elem); + if (!ety) + return 0; memset(&e->cg, 0, sizeof(e->cg)); e->cg.kind = CFREE_CG_TYPE_ARRAY; e->cg.size = ety->size * count; @@ -478,10 +523,11 @@ static int cg_type_set_array(Compiler* c, CgApiType* e, CfreeCgTypeId elem, return 1; } -static int cg_type_set_alias(Compiler* c, CgApiType* e, CfreeSym name, +static int cg_type_set_alias(Compiler *c, CgApiType *e, CfreeSym name, CfreeCgTypeId base) { - const CgType* bty = cg_type_get(c, base); - if (!bty) return 0; + const CgType *bty = cg_type_get(c, base); + if (!bty) + return 0; memset(&e->cg, 0, sizeof(e->cg)); e->cg.kind = CFREE_CG_TYPE_ALIAS; e->cg.size = bty->size; @@ -491,11 +537,12 @@ static int cg_type_set_alias(Compiler* c, CgApiType* e, CfreeSym name, return 1; } -static int cg_type_set_record(Compiler* c, CgApiType* e, CfreeSym tag, - const CfreeCgField* fields, u32 nfields, +static int cg_type_set_record(Compiler *c, CgApiType *e, CfreeSym tag, + const CfreeCgField *fields, u32 nfields, int is_union, u32 align_override, u32 flags) { - CgTypeField* copied = copy_cg_fields(c, fields, nfields); - if (nfields && !copied) return 0; + CgTypeField *copied = copy_cg_fields(c, fields, nfields); + if (nfields && !copied) + return 0; memset(&e->cg, 0, sizeof(e->cg)); e->cg.kind = CFREE_CG_TYPE_RECORD; e->cg.record.tag = tag; @@ -507,14 +554,15 @@ static int cg_type_set_record(Compiler* c, CgApiType* e, CfreeSym tag, return cg_type_layout_record(c, &e->cg); } -static int cg_type_set_enum(Compiler* c, CgApiType* e, CfreeSym tag, - CfreeCgTypeId base, CfreeCgEnumValue* values, +static int cg_type_set_enum(Compiler *c, CgApiType *e, CfreeSym tag, + CfreeCgTypeId base, CfreeCgEnumValue *values, u32 nvalues) { - const CgType* bty; - if (base == CFREE_CG_TYPE_NONE) base = builtin_id(CFREE_CG_BUILTIN_I32); + const CgType *bty; + if (base == CFREE_CG_TYPE_NONE) + base = builtin_id(CFREE_CG_BUILTIN_I32); bty = cg_type_get(c, base); - if (!bty || !(bty->kind == CFREE_CG_TYPE_INT || - bty->kind == CFREE_CG_TYPE_BOOL)) { + if (!bty || + !(bty->kind == CFREE_CG_TYPE_INT || bty->kind == CFREE_CG_TYPE_BOOL)) { return 0; } memset(&e->cg, 0, sizeof(e->cg)); @@ -528,11 +576,13 @@ static int cg_type_set_enum(Compiler* c, CgApiType* e, CfreeSym tag, return 1; } -static int cg_type_set_func(Compiler* c, CgApiType* e, CfreeCgFuncSig sig, - CfreeCgParam* params) { - if (!cg_type_get(c, sig.ret)) return 0; +static int cg_type_set_func(Compiler *c, CgApiType *e, CfreeCgFuncSig sig, + CfreeCgParam *params) { + if (!cg_type_get(c, sig.ret)) + return 0; for (u32 i = 0; i < sig.nparams; ++i) { - if (!cg_type_get(c, sig.params[i].type)) return 0; + if (!cg_type_get(c, sig.params[i].type)) + return 0; } memset(&e->cg, 0, sizeof(e->cg)); e->cg.kind = CFREE_CG_TYPE_FUNC; @@ -547,7 +597,7 @@ static int cg_type_set_func(Compiler* c, CgApiType* e, CfreeCgFuncSig sig, return 1; } -CfreeCgBuiltinTypes cfree_cg_builtin_types(CfreeCompiler* c) { +CfreeCgBuiltinTypes cfree_cg_builtin_types(CfreeCompiler *c) { CfreeCgBuiltinTypes out; (void)c; memset(&out, 0, sizeof(out)); @@ -557,15 +607,18 @@ CfreeCgBuiltinTypes cfree_cg_builtin_types(CfreeCompiler* c) { return out; } -CfreeCgTypeId cfree_cg_type_ptr(CfreeCompiler* c, CfreeCgTypeId pointee, +CfreeCgTypeId cfree_cg_type_ptr(CfreeCompiler *c, CfreeCgTypeId pointee, uint32_t address_space) { CfreeCgTypeId id; - CgApiType* e; - if (!cg_type_get(c, pointee)) return CFREE_CG_TYPE_NONE; + CgApiType *e; + if (!cg_type_get(c, pointee)) + return CFREE_CG_TYPE_NONE; id = find_ptr_type_id(c, pointee, address_space); - if (id != CFREE_CG_TYPE_NONE) return id; + if (id != CFREE_CG_TYPE_NONE) + return id; e = type_alloc(c, &id); - if (!e) return CFREE_CG_TYPE_NONE; + if (!e) + return CFREE_CG_TYPE_NONE; e->base = pointee; e->address_space = address_space; e->kind = CG_API_TYPE_PTR; @@ -575,15 +628,18 @@ CfreeCgTypeId cfree_cg_type_ptr(CfreeCompiler* c, CfreeCgTypeId pointee, return id; } -CfreeCgTypeId cfree_cg_type_array(CfreeCompiler* c, CfreeCgTypeId elem, +CfreeCgTypeId cfree_cg_type_array(CfreeCompiler *c, CfreeCgTypeId elem, uint64_t count) { CfreeCgTypeId id; - CgApiType* e; - if (!cg_type_get(c, elem) || count > UINT32_MAX) return CFREE_CG_TYPE_NONE; + CgApiType *e; + if (!cg_type_get(c, elem) || count > UINT32_MAX) + return CFREE_CG_TYPE_NONE; id = find_array_type_id(c, elem, count); - if (id != CFREE_CG_TYPE_NONE) return id; + if (id != CFREE_CG_TYPE_NONE) + return id; e = type_alloc(c, &id); - if (!e) return CFREE_CG_TYPE_NONE; + if (!e) + return CFREE_CG_TYPE_NONE; e->base = elem; e->array_count = count; e->kind = CG_API_TYPE_ARRAY; @@ -593,21 +649,23 @@ CfreeCgTypeId cfree_cg_type_array(CfreeCompiler* c, CfreeCgTypeId elem, return id; } -CfreeCgTypeId cfree_cg_type_alias(CfreeCompiler* c, CfreeSym name, +CfreeCgTypeId cfree_cg_type_alias(CfreeCompiler *c, CfreeSym name, CfreeCgTypeId base) { CfreeCgTypeId id; - CgApiType* e; - if (!cg_type_get(c, base)) return CFREE_CG_TYPE_NONE; + CgApiType *e; + if (!cg_type_get(c, base)) + return CFREE_CG_TYPE_NONE; e = type_alloc(c, &id); - if (!e) return CFREE_CG_TYPE_NONE; + if (!e) + return CFREE_CG_TYPE_NONE; e->base = base; e->name = name; e->kind = CG_API_TYPE_ALIAS; return cg_type_set_alias(c, e, name, base) ? id : CFREE_CG_TYPE_NONE; } -CfreeCgTypeId cfree_cg_type_record(CfreeCompiler* c, CfreeSym tag, - const CfreeCgField* fields, +CfreeCgTypeId cfree_cg_type_record(CfreeCompiler *c, CfreeSym tag, + const CfreeCgField *fields, uint32_t nfields) { CfreeCgRecordDesc desc; memset(&desc, 0, sizeof desc); @@ -617,55 +675,62 @@ CfreeCgTypeId cfree_cg_type_record(CfreeCompiler* c, CfreeSym tag, return cfree_cg_type_record_ex(c, &desc); } -CfreeCgTypeId cfree_cg_type_record_ex(CfreeCompiler* c, - const CfreeCgRecordDesc* desc) { +CfreeCgTypeId cfree_cg_type_record_ex(CfreeCompiler *c, + const CfreeCgRecordDesc *desc) { CfreeCgTypeId id; - CgApiType* e; - CfreeCgField* copied = NULL; + CgApiType *e; + CfreeCgField *copied = NULL; if (!c || !desc || (desc->nfields && !desc->fields) || desc->nfields > UINT16_MAX) { return CFREE_CG_TYPE_NONE; } if (desc->nfields) { copied = arena_array(&c->global->arena, CfreeCgField, desc->nfields); - if (!copied) return CFREE_CG_TYPE_NONE; + if (!copied) + return CFREE_CG_TYPE_NONE; } for (u32 i = 0; i < desc->nfields; ++i) { - if (!cg_type_get(c, desc->fields[i].type)) return CFREE_CG_TYPE_NONE; + if (!cg_type_get(c, desc->fields[i].type)) + return CFREE_CG_TYPE_NONE; copied[i] = desc->fields[i]; } e = type_alloc(c, &id); - if (!e) return CFREE_CG_TYPE_NONE; + if (!e) + return CFREE_CG_TYPE_NONE; e->name = desc->tag; e->count = desc->nfields; e->fields = copied; e->kind = CG_API_TYPE_RECORD; if (!cg_type_set_record(c, e, desc->tag, desc->fields, desc->nfields, - desc->is_union, desc->align_override, - 0)) { + desc->is_union, desc->align_override, 0)) { return CFREE_CG_TYPE_NONE; } return id; } -CfreeCgTypeId cfree_cg_type_enum(CfreeCompiler* c, CfreeSym tag, +CfreeCgTypeId cfree_cg_type_enum(CfreeCompiler *c, CfreeSym tag, CfreeCgTypeId base, - const CfreeCgEnumValue* values, + const CfreeCgEnumValue *values, uint32_t nvalues) { - CfreeCgEnumValue* copied = NULL; + CfreeCgEnumValue *copied = NULL; CfreeCgTypeId id; - CgApiType* e; - if (!c || (nvalues && !values)) return CFREE_CG_TYPE_NONE; - if (base == CFREE_CG_TYPE_NONE) base = builtin_id(CFREE_CG_BUILTIN_I32); - if (!cg_type_is_int(c, base)) return CFREE_CG_TYPE_NONE; + CgApiType *e; + if (!c || (nvalues && !values)) + return CFREE_CG_TYPE_NONE; + if (base == CFREE_CG_TYPE_NONE) + base = builtin_id(CFREE_CG_BUILTIN_I32); + if (!cg_type_is_int(c, base)) + return CFREE_CG_TYPE_NONE; if (nvalues) { copied = arena_array(&c->global->arena, CfreeCgEnumValue, nvalues); - if (!copied) return CFREE_CG_TYPE_NONE; + if (!copied) + return CFREE_CG_TYPE_NONE; memcpy(copied, values, sizeof(*copied) * nvalues); } e = type_alloc(c, &id); - if (!e) return CFREE_CG_TYPE_NONE; + if (!e) + return CFREE_CG_TYPE_NONE; e->base = base; e->name = tag; e->count = nvalues; @@ -677,25 +742,29 @@ CfreeCgTypeId cfree_cg_type_enum(CfreeCompiler* c, CfreeSym tag, return id; } -CfreeCgTypeId cfree_cg_type_func(CfreeCompiler* c, CfreeCgFuncSig sig) { - CfreeCgParam* copied = NULL; +CfreeCgTypeId cfree_cg_type_func(CfreeCompiler *c, CfreeCgFuncSig sig) { + CfreeCgParam *copied = NULL; CfreeCgTypeId id; - CgApiType* e; + CgApiType *e; if (!c || !cg_type_get(c, sig.ret) || (sig.nparams && !sig.params) || sig.nparams > UINT16_MAX) { return CFREE_CG_TYPE_NONE; } id = find_func_type_id(c, sig); - if (id != CFREE_CG_TYPE_NONE) return id; + if (id != CFREE_CG_TYPE_NONE) + return id; if (sig.nparams) { copied = copy_cg_params(c, sig.params, sig.nparams); - if (!copied) return CFREE_CG_TYPE_NONE; + if (!copied) + return CFREE_CG_TYPE_NONE; for (u32 i = 0; i < sig.nparams; ++i) { - if (!cg_type_get(c, sig.params[i].type)) return CFREE_CG_TYPE_NONE; + if (!cg_type_get(c, sig.params[i].type)) + return CFREE_CG_TYPE_NONE; } } e = type_alloc(c, &id); - if (!e) return CFREE_CG_TYPE_NONE; + if (!e) + return CFREE_CG_TYPE_NONE; e->base = sig.ret; e->count = sig.nparams; e->params = copied; @@ -709,22 +778,23 @@ CfreeCgTypeId cfree_cg_type_func(CfreeCompiler* c, CfreeCgFuncSig sig) { return id; } -uint64_t cfree_cg_type_size(CfreeCompiler* c, CfreeCgTypeId id) { +uint64_t cfree_cg_type_size(CfreeCompiler *c, CfreeCgTypeId id) { return cg_type_size(c, id); } -uint32_t cfree_cg_type_align(CfreeCompiler* c, CfreeCgTypeId id) { +uint32_t cfree_cg_type_align(CfreeCompiler *c, CfreeCgTypeId id) { return cg_type_align(c, id); } -CfreeCgTypeKind cfree_cg_type_kind(CfreeCompiler* c, CfreeCgTypeId id) { - const CgType* ty = cg_type_get(c, id); +CfreeCgTypeKind cfree_cg_type_kind(CfreeCompiler *c, CfreeCgTypeId id) { + const CgType *ty = cg_type_get(c, id); return ty ? ty->kind : CFREE_CG_TYPE_VOID; } -uint32_t cfree_cg_type_int_width(CfreeCompiler* c, CfreeCgTypeId id) { - const CgType* ty = cg_type_get(c, id); - if (!ty) return 0; +uint32_t cfree_cg_type_int_width(CfreeCompiler *c, CfreeCgTypeId id) { + const CgType *ty = cg_type_get(c, id); + if (!ty) + return 0; if (ty->kind == CFREE_CG_TYPE_INT || ty->kind == CFREE_CG_TYPE_BOOL) { return ty->integer.width; } @@ -737,60 +807,62 @@ uint32_t cfree_cg_type_int_width(CfreeCompiler* c, CfreeCgTypeId id) { return 0; } -uint32_t cfree_cg_type_float_width(CfreeCompiler* c, CfreeCgTypeId id) { - const CgType* ty = cg_type_get(c, id); - if (!ty) return 0; - if (ty->kind == CFREE_CG_TYPE_FLOAT) return ty->fp.width; +uint32_t cfree_cg_type_float_width(CfreeCompiler *c, CfreeCgTypeId id) { + const CgType *ty = cg_type_get(c, id); + if (!ty) + return 0; + if (ty->kind == CFREE_CG_TYPE_FLOAT) + return ty->fp.width; if (ty->kind == CFREE_CG_TYPE_ALIAS) { return cfree_cg_type_float_width(c, ty->alias.base); } return 0; } -CfreeCgTypeId cfree_cg_type_ptr_pointee(CfreeCompiler* c, CfreeCgTypeId id) { - const CgType* ty = cg_type_get(c, id); +CfreeCgTypeId cfree_cg_type_ptr_pointee(CfreeCompiler *c, CfreeCgTypeId id) { + const CgType *ty = cg_type_get(c, id); return (ty && ty->kind == CFREE_CG_TYPE_PTR) ? ty->ptr.pointee : CFREE_CG_TYPE_NONE; } -CfreeCgTypeId cfree_cg_type_array_elem(CfreeCompiler* c, CfreeCgTypeId id) { - const CgType* ty = cg_type_get(c, id); +CfreeCgTypeId cfree_cg_type_array_elem(CfreeCompiler *c, CfreeCgTypeId id) { + const CgType *ty = cg_type_get(c, id); return (ty && ty->kind == CFREE_CG_TYPE_ARRAY) ? ty->array.elem : CFREE_CG_TYPE_NONE; } -uint32_t cfree_cg_type_ptr_address_space(CfreeCompiler* c, CfreeCgTypeId id) { - const CgType* ty = cg_type_get(c, id); +uint32_t cfree_cg_type_ptr_address_space(CfreeCompiler *c, CfreeCgTypeId id) { + const CgType *ty = cg_type_get(c, id); return (ty && ty->kind == CFREE_CG_TYPE_PTR) ? ty->ptr.address_space : 0u; } -uint64_t cfree_cg_type_array_count(CfreeCompiler* c, CfreeCgTypeId id) { - const CgType* ty = cg_type_get(c, id); +uint64_t cfree_cg_type_array_count(CfreeCompiler *c, CfreeCgTypeId id) { + const CgType *ty = cg_type_get(c, id); return (ty && ty->kind == CFREE_CG_TYPE_ARRAY) ? ty->array.count : 0u; } -CfreeCgTypeId cfree_cg_type_func_ret(CfreeCompiler* c, CfreeCgTypeId id) { - const CgType* ty = cg_type_get(c, id); +CfreeCgTypeId cfree_cg_type_func_ret(CfreeCompiler *c, CfreeCgTypeId id) { + const CgType *ty = cg_type_get(c, id); return (ty && ty->kind == CFREE_CG_TYPE_FUNC) ? ty->func.ret : CFREE_CG_TYPE_NONE; } -uint32_t cfree_cg_type_func_nparams(CfreeCompiler* c, CfreeCgTypeId id) { - const CgType* ty = cg_type_get(c, id); +uint32_t cfree_cg_type_func_nparams(CfreeCompiler *c, CfreeCgTypeId id) { + const CgType *ty = cg_type_get(c, id); return (ty && ty->kind == CFREE_CG_TYPE_FUNC) ? ty->func.nparams : 0; } -CfreeCgAbiAttrs cfree_cg_type_func_ret_attrs(CfreeCompiler* c, +CfreeCgAbiAttrs cfree_cg_type_func_ret_attrs(CfreeCompiler *c, CfreeCgTypeId id) { - const CgType* ty = cg_type_get(c, id); + const CgType *ty = cg_type_get(c, id); CfreeCgAbiAttrs empty; memset(&empty, 0, sizeof(empty)); return (ty && ty->kind == CFREE_CG_TYPE_FUNC) ? ty->func.ret_attrs : empty; } -CfreeCgParam cfree_cg_type_func_param(CfreeCompiler* c, CfreeCgTypeId id, +CfreeCgParam cfree_cg_type_func_param(CfreeCompiler *c, CfreeCgTypeId id, uint32_t index) { - const CgType* ty = cg_type_get(c, id); + const CgType *ty = cg_type_get(c, id); CfreeCgParam empty; memset(&empty, 0, sizeof(empty)); if (!ty || ty->kind != CFREE_CG_TYPE_FUNC || index >= ty->func.nparams) { @@ -799,30 +871,29 @@ CfreeCgParam cfree_cg_type_func_param(CfreeCompiler* c, CfreeCgTypeId id, return ty->func.params[index]; } -CfreeCgCallConv cfree_cg_type_func_call_conv(CfreeCompiler* c, +CfreeCgCallConv cfree_cg_type_func_call_conv(CfreeCompiler *c, CfreeCgTypeId id) { - const CgType* ty = cg_type_get(c, id); + const CgType *ty = cg_type_get(c, id); return (ty && ty->kind == CFREE_CG_TYPE_FUNC) ? ty->func.call_conv : CFREE_CG_CC_TARGET_C; } -int cfree_cg_type_func_is_variadic(CfreeCompiler* c, CfreeCgTypeId id) { - const CgType* ty = cg_type_get(c, id); +int cfree_cg_type_func_is_variadic(CfreeCompiler *c, CfreeCgTypeId id) { + const CgType *ty = cg_type_get(c, id); return ty && ty->kind == CFREE_CG_TYPE_FUNC && ty->func.abi_variadic; } -uint32_t cfree_cg_type_record_nfields(CfreeCompiler* c, CfreeCgTypeId id) { - const CgType* ty = cg_type_get(c, id); +uint32_t cfree_cg_type_record_nfields(CfreeCompiler *c, CfreeCgTypeId id) { + const CgType *ty = cg_type_get(c, id); return (ty && ty->kind == CFREE_CG_TYPE_RECORD) ? ty->record.nfields : 0; } -int cfree_cg_type_record_field(CfreeCompiler* c, CfreeCgTypeId id, - uint32_t index, CfreeCgField* out, - uint64_t* offset_out) { - const CgType* ty = cg_type_get(c, id); - const CgTypeField* f; - if (!ty || ty->kind != CFREE_CG_TYPE_RECORD || - index >= ty->record.nfields) { +int cfree_cg_type_record_field(CfreeCompiler *c, CfreeCgTypeId id, + uint32_t index, CfreeCgField *out, + uint64_t *offset_out) { + const CgType *ty = cg_type_get(c, id); + const CgTypeField *f; + if (!ty || ty->kind != CFREE_CG_TYPE_RECORD || index >= ty->record.nfields) { return 1; } f = &ty->record.fields[index]; @@ -831,58 +902,62 @@ int cfree_cg_type_record_field(CfreeCompiler* c, CfreeCgTypeId id, out->type = f->type; out->align_override = f->align_override; } - if (offset_out) *offset_out = f->offset; + if (offset_out) + *offset_out = f->offset; return 0; } -int cfree_cg_target_supports_call_conv(CfreeCompiler* c, CfreeCgCallConv cc) { - if (!c) return 0; +int cfree_cg_target_supports_call_conv(CfreeCompiler *c, CfreeCgCallConv cc) { + if (!c) + return 0; switch (cc) { - case CFREE_CG_CC_TARGET_C: - return 1; - case CFREE_CG_CC_SYSV: - return c->target.arch == CFREE_ARCH_X86_64 && - c->target.os != CFREE_OS_WINDOWS; - case CFREE_CG_CC_WIN64: - return c->target.arch == CFREE_ARCH_X86_64 && - c->target.os == CFREE_OS_WINDOWS; - case CFREE_CG_CC_AAPCS: - return c->target.arch == CFREE_ARCH_ARM_32 || - c->target.arch == CFREE_ARCH_ARM_64; - case CFREE_CG_CC_WASM: - return c->target.arch == CFREE_ARCH_WASM; - case CFREE_CG_CC_INTERRUPT: - return 0; + case CFREE_CG_CC_TARGET_C: + return 1; + case CFREE_CG_CC_SYSV: + return c->target.arch == CFREE_ARCH_X86_64 && + c->target.os != CFREE_OS_WINDOWS; + case CFREE_CG_CC_WIN64: + return c->target.arch == CFREE_ARCH_X86_64 && + c->target.os == CFREE_OS_WINDOWS; + case CFREE_CG_CC_AAPCS: + return c->target.arch == CFREE_ARCH_ARM_32 || + c->target.arch == CFREE_ARCH_ARM_64; + case CFREE_CG_CC_WASM: + return c->target.arch == CFREE_ARCH_WASM; + case CFREE_CG_CC_INTERRUPT: + return 0; } return 0; } -int cfree_cg_target_supports_symbol_feature(CfreeCompiler* c, +int cfree_cg_target_supports_symbol_feature(CfreeCompiler *c, CfreeCgSymbolFeature feat) { - if (!c) return 0; + if (!c) + return 0; switch (feat) { - case CFREE_CG_SYMFEAT_WEAK: - case CFREE_CG_SYMFEAT_PROTECTED_VISIBILITY: - case CFREE_CG_SYMFEAT_COMDAT: - case CFREE_CG_SYMFEAT_COMMON: - return 1; - case CFREE_CG_SYMFEAT_TLS_LOCAL_EXEC: - case CFREE_CG_SYMFEAT_TLS_INITIAL_EXEC: - case CFREE_CG_SYMFEAT_TLS_LOCAL_DYNAMIC: - case CFREE_CG_SYMFEAT_TLS_GENERAL_DYNAMIC: - return c->target.obj == CFREE_OBJ_ELF || c->target.obj == CFREE_OBJ_MACHO; - case CFREE_CG_SYMFEAT_DLLIMPORT: - case CFREE_CG_SYMFEAT_DLLEXPORT: - case CFREE_CG_SYMFEAT_MERGE_SECTIONS: - case CFREE_CG_SYMFEAT_CONSTRUCTOR_PRIORITY: - return 0; + case CFREE_CG_SYMFEAT_WEAK: + case CFREE_CG_SYMFEAT_PROTECTED_VISIBILITY: + case CFREE_CG_SYMFEAT_COMDAT: + case CFREE_CG_SYMFEAT_COMMON: + return 1; + case CFREE_CG_SYMFEAT_TLS_LOCAL_EXEC: + case CFREE_CG_SYMFEAT_TLS_INITIAL_EXEC: + case CFREE_CG_SYMFEAT_TLS_LOCAL_DYNAMIC: + case CFREE_CG_SYMFEAT_TLS_GENERAL_DYNAMIC: + return c->target.obj == CFREE_OBJ_ELF || c->target.obj == CFREE_OBJ_MACHO; + case CFREE_CG_SYMFEAT_DLLIMPORT: + case CFREE_CG_SYMFEAT_DLLEXPORT: + case CFREE_CG_SYMFEAT_MERGE_SECTIONS: + case CFREE_CG_SYMFEAT_CONSTRUCTOR_PRIORITY: + return 0; } return 0; } -uint64_t cfree_cg_target_backend_features(CfreeCompiler* c) { +uint64_t cfree_cg_target_backend_features(CfreeCompiler *c) { uint64_t out = 0; - if (!c) return 0; + if (!c) + return 0; if (c->target.arch == CFREE_ARCH_X86_64 || c->target.arch == CFREE_ARCH_X86_32) { out |= CFREE_CG_BACKEND_UNALIGNED_MEMORY; @@ -894,10 +969,11 @@ uint64_t cfree_cg_target_backend_features(CfreeCompiler* c) { return out; } -void cg_api_fini(Compiler* c) { - CgApiState* s; - if (!c || !c->cg_api) return; - s = (CgApiState*)c->cg_api; +void cg_api_fini(Compiler *c) { + CgApiState *s; + if (!c || !c->cg_api) + return; + s = (CgApiState *)c->cg_api; CgApiTypes_fini(&s->types); s->heap->free(s->heap, s, sizeof(*s)); c->cg_api = NULL; @@ -942,37 +1018,38 @@ typedef struct ApiCgScope { #define API_CG_MAX_SCOPES 64 struct CfreeCg { - Compiler* c; - ObjBuilder* obj; - CGTarget* target; - MCEmitter* mc; + Compiler *c; + ObjBuilder *obj; + CGTarget *target; + MCEmitter *mc; + Debug *debug; CGSimpleRegAlloc regalloc; - ApiSValue* stack; + ApiSValue *stack; u32 sp; u32 cap; - CfreeCgTypeId* slot_types; + CfreeCgTypeId *slot_types; u32 slot_types_cap; struct { - FrameSlot* free; + FrameSlot *free; u32 n; u32 cap; } slot_pools[3]; - CGABIValue* avs_in_flight; + CGABIValue *avs_in_flight; u32 avs_in_flight_n; CfreeCgTypeId fn_ret_type; - const ABIFuncInfo* fn_abi; + const ABIFuncInfo *fn_abi; SrcLoc cur_loc; CGFuncDesc fn_desc; CGParamDesc fn_params[64]; - CfreeCgTypeId* sym_types; - CfreeCgDecl* sym_attrs; + CfreeCgTypeId *sym_types; + CfreeCgDecl *sym_attrs; u32 sym_cap; ApiCgScope scopes[API_CG_MAX_SCOPES]; @@ -987,6 +1064,96 @@ struct CfreeCg { u64 data_size; }; +static DebugTypeId api_debug_type(CfreeCg *g, CfreeCgTypeId id) { + const CgType *ty; + if (!g || !g->debug) + return DEBUG_TYPE_NONE; + ty = cg_type_get(g->c, id); + if (!ty) + return DEBUG_TYPE_NONE; + switch (ty->kind) { + case CFREE_CG_TYPE_VOID: + return debug_type_void(g->debug); + case CFREE_CG_TYPE_BOOL: + return debug_type_base(g->debug, pool_intern_cstr(g->c->global, "_Bool"), + DEBUG_BE_BOOL, 1); + case CFREE_CG_TYPE_INT: { + const char *name = "long long"; + if (ty->integer.width <= 8) + name = "char"; + else if (ty->integer.width <= 16) + name = "short"; + else if (ty->integer.width <= 32) + name = "int"; + return debug_type_base(g->debug, pool_intern_cstr(g->c->global, name), + DEBUG_BE_SIGNED, + (u32)((ty->integer.width + 7u) / 8u)); + } + case CFREE_CG_TYPE_FLOAT: { + const char *name = ty->fp.width <= 32 ? "float" : "double"; + return debug_type_base(g->debug, pool_intern_cstr(g->c->global, name), + DEBUG_BE_FLOAT, (u32)((ty->fp.width + 7u) / 8u)); + } + case CFREE_CG_TYPE_PTR: { + DebugTypeId pointee = api_debug_type(g, ty->ptr.pointee); + if (pointee == DEBUG_TYPE_NONE) + pointee = debug_type_void(g->debug); + return debug_type_ptr(g->debug, pointee); + } + case CFREE_CG_TYPE_ARRAY: { + DebugTypeId elem = api_debug_type(g, ty->array.elem); + u32 count = ty->array.count > UINT32_MAX ? 0u : (u32)ty->array.count; + if (elem == DEBUG_TYPE_NONE) + elem = debug_type_void(g->debug); + return debug_type_array(g->debug, elem, count); + } + case CFREE_CG_TYPE_FUNC: { + Heap *h = (Heap *)g->c->env->heap; + DebugTypeId ret = api_debug_type(g, ty->func.ret); + DebugTypeId *params = NULL; + DebugTypeId fn; + if (ret == DEBUG_TYPE_NONE) + ret = debug_type_void(g->debug); + if (ty->func.nparams) { + params = (DebugTypeId *)h->alloc(h, sizeof(*params) * ty->func.nparams, + _Alignof(DebugTypeId)); + if (!params) + return DEBUG_TYPE_NONE; + for (u32 i = 0; i < ty->func.nparams; ++i) { + params[i] = api_debug_type(g, ty->func.params[i].type); + if (params[i] == DEBUG_TYPE_NONE) + params[i] = debug_type_void(g->debug); + } + } + fn = debug_type_func(g->debug, ret, params, ty->func.nparams, + ty->func.abi_variadic); + if (params) + h->free(h, params, sizeof(*params) * ty->func.nparams); + return fn; + } + case CFREE_CG_TYPE_RECORD: { + DebugTypeBuilder *b = + debug_type_record_begin(g->debug, (Sym)ty->record.tag, + ty->record.is_union, (u32)ty->size, ty->align); + if (!b) + return DEBUG_TYPE_NONE; + return debug_type_record_end(b); + } + case CFREE_CG_TYPE_ENUM: + return debug_type_base(g->debug, pool_intern_cstr(g->c->global, "int"), + DEBUG_BE_SIGNED, ty->size ? (u32)ty->size : 4u); + case CFREE_CG_TYPE_ALIAS: { + DebugTypeId base = api_debug_type(g, ty->alias.base); + if (base == DEBUG_TYPE_NONE) + base = debug_type_void(g->debug); + return debug_type_typedef(g->debug, (Sym)ty->alias.name, base); + } + case CFREE_CG_TYPE_VARARG_STATE: + return debug_type_void(g->debug); + } + return DEBUG_TYPE_NONE; +} + /* ---- value stack helpers ---- */ static u8 api_type_class(CfreeCgTypeId ty) { @@ -1049,8 +1216,9 @@ static Operand api_op_indirect(Reg base, i32 ofs, CfreeCgTypeId ty) { return o; } -static u8 api_residency_for(const Operand* o) { - if (o->kind == OPK_REG || o->kind == OPK_INDIRECT) return RES_REG; +static u8 api_residency_for(const Operand *o) { + if (o->kind == OPK_REG || o->kind == OPK_INDIRECT) + return RES_REG; return RES_INHERENT; } @@ -1070,26 +1238,28 @@ static ApiSValue api_make_lv(Operand op, CfreeCgTypeId ty) { return sv; } -static CfreeCgTypeId api_sv_type(const ApiSValue* sv) { +static CfreeCgTypeId api_sv_type(const ApiSValue *sv) { return sv->type ? sv->type : sv->op.type; } -static int api_operand_can_address(const Operand* o) { +static int api_operand_can_address(const Operand *o) { return o->kind == OPK_LOCAL || o->kind == OPK_GLOBAL || o->kind == OPK_INDIRECT; } -static int api_is_lvalue_sv(const ApiSValue* sv) { +static int api_is_lvalue_sv(const ApiSValue *sv) { return sv->lvalue && api_operand_can_address(&sv->op); } -static void api_stack_grow(CfreeCg* g, u32 want) { - Heap* h = g->c->env->heap; +static void api_stack_grow(CfreeCg *g, u32 want) { + Heap *h = g->c->env->heap; u32 cap = g->cap; - ApiSValue* nb; - if (cap >= want) return; - while (cap < want) cap = cap ? cap * 2u : API_CG_STACK_INITIAL; - nb = (ApiSValue*)h->alloc(h, sizeof(ApiSValue) * cap, _Alignof(ApiSValue)); + ApiSValue *nb; + if (cap >= want) + return; + while (cap < want) + cap = cap ? cap * 2u : API_CG_STACK_INITIAL; + nb = (ApiSValue *)h->alloc(h, sizeof(ApiSValue) * cap, _Alignof(ApiSValue)); if (g->stack) { memcpy(nb, g->stack, sizeof(ApiSValue) * g->sp); h->free(h, g->stack, sizeof(ApiSValue) * g->cap); @@ -1098,31 +1268,35 @@ static void api_stack_grow(CfreeCg* g, u32 want) { g->cap = cap; } -static void api_push(CfreeCg* g, ApiSValue v) { +static void api_push(CfreeCg *g, ApiSValue v) { api_stack_grow(g, g->sp + 1); g->stack[g->sp++] = v; } -static ApiSValue api_pop(CfreeCg* g) { +static ApiSValue api_pop(CfreeCg *g) { if (g->sp == 0) { compiler_panic(g->c, g->cur_loc, "CfreeCg: stack underflow"); } return g->stack[--g->sp]; } -static void api_remember_slot_type(CfreeCg* g, FrameSlot slot, CfreeCgTypeId ty) { - Heap* h = g->c->env->heap; - CfreeCgTypeId* nb; +static void api_remember_slot_type(CfreeCg *g, FrameSlot slot, + CfreeCgTypeId ty) { + Heap *h = g->c->env->heap; + CfreeCgTypeId *nb; u32 cap; - if (slot == FRAME_SLOT_NONE) return; + if (slot == FRAME_SLOT_NONE) + return; if (slot < g->slot_types_cap) { g->slot_types[slot] = ty; return; } cap = g->slot_types_cap ? g->slot_types_cap : 16; - while (cap <= slot) cap *= 2u; - nb = (CfreeCgTypeId*)h->alloc(h, sizeof(*nb) * cap, _Alignof(CfreeCgTypeId)); - if (!nb) return; + while (cap <= slot) + cap *= 2u; + nb = (CfreeCgTypeId *)h->alloc(h, sizeof(*nb) * cap, _Alignof(CfreeCgTypeId)); + if (!nb) + return; memset(nb, 0, sizeof(*nb) * cap); if (g->slot_types) { memcpy(nb, g->slot_types, sizeof(*nb) * g->slot_types_cap); @@ -1133,7 +1307,7 @@ static void api_remember_slot_type(CfreeCg* g, FrameSlot slot, CfreeCgTypeId ty) g->slot_types[slot] = ty; } -static CfreeCgTypeId api_slot_type(CfreeCg* g, FrameSlot slot) { +static CfreeCgTypeId api_slot_type(CfreeCg *g, FrameSlot slot) { if (slot == FRAME_SLOT_NONE || slot >= g->slot_types_cap) { return CFREE_CG_TYPE_NONE; } @@ -1142,28 +1316,33 @@ static CfreeCgTypeId api_slot_type(CfreeCg* g, FrameSlot slot) { /* ---- register class helpers ---- */ -static u8 api_class_of_sv(const ApiSValue* sv) { - if (sv->op.kind == OPK_INDIRECT) return RC_INT; - if (sv->op.kind == OPK_IMM || sv->op.kind == OPK_REG) return sv->op.cls; +static u8 api_class_of_sv(const ApiSValue *sv) { + if (sv->op.kind == OPK_INDIRECT) + return RC_INT; + if (sv->op.kind == OPK_IMM || sv->op.kind == OPK_REG) + return sv->op.cls; return api_type_class(api_sv_type(sv)); } -static Reg api_reg_of_sv(const ApiSValue* sv) { - if (sv->op.kind == OPK_REG) return sv->op.v.reg; - if (sv->op.kind == OPK_INDIRECT) return sv->op.v.ind.base; +static Reg api_reg_of_sv(const ApiSValue *sv) { + if (sv->op.kind == OPK_REG) + return sv->op.v.reg; + if (sv->op.kind == OPK_INDIRECT) + return sv->op.v.ind.base; return (Reg)REG_NONE; } -static void api_set_owned_reg(ApiSValue* sv, Reg r) { +static void api_set_owned_reg(ApiSValue *sv, Reg r) { if (sv->op.kind == OPK_REG) sv->op.v.reg = r; else if (sv->op.kind == OPK_INDIRECT) sv->op.v.ind.base = r; } -static CfreeCgTypeId api_owned_reg_type(CfreeCg* g, const ApiSValue* sv) { +static CfreeCgTypeId api_owned_reg_type(CfreeCg *g, const ApiSValue *sv) { if (sv->op.kind == OPK_INDIRECT) { - CfreeCgTypeId base = sv->type ? sv->type : builtin_id(CFREE_CG_BUILTIN_VOID); + CfreeCgTypeId base = + sv->type ? sv->type : builtin_id(CFREE_CG_BUILTIN_VOID); return cg_type_ptr_to(g->c, base); } return api_sv_type(sv); @@ -1171,8 +1350,8 @@ static CfreeCgTypeId api_owned_reg_type(CfreeCg* g, const ApiSValue* sv) { /* ---- spill slot management ---- */ -static void api_take_spill_slot_alloc(CfreeCg* g, u8 cls, FrameSlot* out) { - CGTarget* T = g->target; +static void api_take_spill_slot_alloc(CfreeCg *g, u8 cls, FrameSlot *out) { + CGTarget *T = g->target; FrameSlotDesc fsd; memset(&fsd, 0, sizeof fsd); fsd.kind = FS_SPILL; @@ -1181,7 +1360,7 @@ static void api_take_spill_slot_alloc(CfreeCg* g, u8 cls, FrameSlot* out) { *out = T->frame_slot(T, &fsd); } -static FrameSlot api_take_spill_slot(CfreeCg* g, u8 cls) { +static FrameSlot api_take_spill_slot(CfreeCg *g, u8 cls) { if (cls < 3 && g->slot_pools[cls].n > 0) { return g->slot_pools[cls].free[--g->slot_pools[cls].n]; } @@ -1190,15 +1369,17 @@ static FrameSlot api_take_spill_slot(CfreeCg* g, u8 cls) { return s; } -static void api_return_spill_slot(CfreeCg* g, FrameSlot s, u8 cls) { - Heap* h; - if (s == FRAME_SLOT_NONE) return; - if (cls >= 3) return; +static void api_return_spill_slot(CfreeCg *g, FrameSlot s, u8 cls) { + Heap *h; + if (s == FRAME_SLOT_NONE) + return; + if (cls >= 3) + return; h = g->c->env->heap; if (g->slot_pools[cls].n >= g->slot_pools[cls].cap) { u32 new_cap = g->slot_pools[cls].cap ? g->slot_pools[cls].cap * 2 : 8; - FrameSlot* nb = (FrameSlot*)h->alloc(h, sizeof(FrameSlot) * new_cap, - _Alignof(FrameSlot)); + FrameSlot *nb = (FrameSlot *)h->alloc(h, sizeof(FrameSlot) * new_cap, + _Alignof(FrameSlot)); if (g->slot_pools[cls].free) { memcpy(nb, g->slot_pools[cls].free, sizeof(FrameSlot) * g->slot_pools[cls].n); @@ -1213,27 +1394,29 @@ static void api_return_spill_slot(CfreeCg* g, FrameSlot s, u8 cls) { /* ---- register allocation / spill ---- */ -static ApiSValue* api_pick_victim(CfreeCg* g, u8 cls) { +static ApiSValue *api_pick_victim(CfreeCg *g, u8 cls) { for (u32 i = 0; i < g->sp; ++i) { - ApiSValue* sv = &g->stack[i]; - if (sv->res != RES_REG || sv->pinned) continue; - if (api_class_of_sv(sv) != cls) continue; + ApiSValue *sv = &g->stack[i]; + if (sv->res != RES_REG || sv->pinned) + continue; + if (api_class_of_sv(sv) != cls) + continue; return sv; } return NULL; } -static MemAccess api_mem_for_spill(CfreeCg* g, const ApiSValue* sv); +static MemAccess api_mem_for_spill(CfreeCg *g, const ApiSValue *sv); -static void api_regalloc_begin(CfreeCg* g) { - CGTarget* T = g->target; +static void api_regalloc_begin(CfreeCg *g) { + CGTarget *T = g->target; if (T->virtual_regs) { cg_simple_regalloc_init_virtual(&g->regalloc); return; } cg_simple_regalloc_init(&g->regalloc); for (u32 c = 0; c < 3u; ++c) { - const Reg* regs = NULL; + const Reg *regs = NULL; u32 nregs = 0; if (T->get_allocable_regs) T->get_allocable_regs(T, (RegClass)c, &regs, &nregs); @@ -1242,18 +1425,21 @@ static void api_regalloc_begin(CfreeCg* g) { } } -static void api_regalloc_finish(CfreeCg* g) { - if (cg_simple_regalloc_is_virtual(&g->regalloc)) return; - if (!g->target->reserve_hard_regs) return; +static void api_regalloc_finish(CfreeCg *g) { + if (cg_simple_regalloc_is_virtual(&g->regalloc)) + return; + if (!g->target->reserve_hard_regs) + return; for (u32 c = 0; c < 3u; ++c) { Reg used[CG_SIMPLE_REGALLOC_MAX_REGS]; u32 nused = cg_simple_regalloc_used_regs(&g->regalloc, (RegClass)c, used, CG_SIMPLE_REGALLOC_MAX_REGS); - if (nused) g->target->reserve_hard_regs(g->target, (RegClass)c, used, nused); + if (nused) + g->target->reserve_hard_regs(g->target, (RegClass)c, used, nused); } } -static Reg api_alloc_reg(CfreeCg* g, u8 cls) { +static Reg api_alloc_reg(CfreeCg *g, u8 cls) { Reg r = cg_simple_regalloc_alloc(&g->regalloc, (RegClass)cls); if (r == (Reg)REG_NONE && cg_simple_regalloc_is_virtual(&g->regalloc)) { compiler_panic(g->c, g->cur_loc, "CfreeCg: virtual regalloc exhausted"); @@ -1261,28 +1447,33 @@ static Reg api_alloc_reg(CfreeCg* g, u8 cls) { return r; } -static void api_free_reg(CfreeCg* g, Reg r, u8 cls) { +static void api_free_reg(CfreeCg *g, Reg r, u8 cls) { int rc; - if (r == (Reg)REG_NONE) return; + if (r == (Reg)REG_NONE) + return; rc = cg_simple_regalloc_free(&g->regalloc, (RegClass)cls, r); - if (rc == 1) return; + if (rc == 1) + return; if (rc == -1) { compiler_panic(g->c, g->cur_loc, "CfreeCg: regalloc - reg %u already free in class %u", (unsigned)r, (unsigned)cls); } compiler_panic(g->c, g->cur_loc, - "CfreeCg: regalloc - reg %u not in class %u pool", - (unsigned)r, (unsigned)cls); + "CfreeCg: regalloc - reg %u not in class %u pool", (unsigned)r, + (unsigned)cls); } -static int api_spill_avs_victim(CfreeCg* g, u8 cls) { - CGTarget* T = g->target; - if (!g->avs_in_flight) return 0; +static int api_spill_avs_victim(CfreeCg *g, u8 cls) { + CGTarget *T = g->target; + if (!g->avs_in_flight) + return 0; for (u32 i = 0; i < g->avs_in_flight_n; ++i) { - CGABIValue* av = &g->avs_in_flight[i]; - if (av->storage.kind != OPK_REG) continue; - if (av->storage.cls != cls) continue; + CGABIValue *av = &g->avs_in_flight[i]; + if (av->storage.kind != OPK_REG) + continue; + if (av->storage.cls != cls) + continue; FrameSlot slot = api_take_spill_slot(g, cls); ApiSValue tmp = api_make_sv(av->storage, av->type); T->spill_reg(T, av->storage, slot, api_mem_for_spill(g, &tmp)); @@ -1295,7 +1486,7 @@ static int api_spill_avs_victim(CfreeCg* g, u8 cls) { return 0; } -static MemAccess api_mem_for_lvalue(CfreeCg* g, const Operand* lv, +static MemAccess api_mem_for_lvalue(CfreeCg *g, const Operand *lv, CfreeCgTypeId ty) { MemAccess m; memset(&m, 0, sizeof m); @@ -1314,20 +1505,22 @@ static MemAccess api_mem_for_lvalue(CfreeCg* g, const Operand* lv, return m; } -static MemAccess api_mem_from_access(CfreeCg* g, const Operand* lv, +static MemAccess api_mem_from_access(CfreeCg *g, const Operand *lv, CfreeCgMemAccess access) { CfreeCgTypeId ty = resolve_type(g->c, access.type); MemAccess m = api_mem_for_lvalue(g, lv, ty); - if (access.align) m.align = access.align; + if (access.align) + m.align = access.align; m.addr_space = (u16)access.address_space; - if (access.flags & CFREE_CG_MEM_VOLATILE) m.flags |= MF_VOLATILE; + if (access.flags & CFREE_CG_MEM_VOLATILE) + m.flags |= MF_VOLATILE; if (!access.align || (ty && access.align < abi_cg_alignof(g->c->abi, ty))) { m.flags |= MF_UNALIGNED; } return m; } -static MemAccess api_mem_for_spill(CfreeCg* g, const ApiSValue* sv) { +static MemAccess api_mem_for_spill(CfreeCg *g, const ApiSValue *sv) { CfreeCgTypeId ty = api_owned_reg_type(g, sv); MemAccess m; memset(&m, 0, sizeof m); @@ -1338,14 +1531,15 @@ static MemAccess api_mem_for_spill(CfreeCg* g, const ApiSValue* sv) { return m; } -static Reg api_alloc_reg_or_spill(CfreeCg* g, u8 cls, CfreeCgTypeId ty) { - CGTarget* T = g->target; +static Reg api_alloc_reg_or_spill(CfreeCg *g, u8 cls, CfreeCgTypeId ty) { + CGTarget *T = g->target; Reg r; (void)ty; r = api_alloc_reg(g, cls); - if (r != (Reg)REG_NONE) return r; + if (r != (Reg)REG_NONE) + return r; - ApiSValue* victim = api_pick_victim(g, cls); + ApiSValue *victim = api_pick_victim(g, cls); if (victim) { FrameSlot slot = api_take_spill_slot(g, cls); CfreeCgTypeId rty = api_owned_reg_type(g, victim); @@ -1370,13 +1564,14 @@ static Reg api_alloc_reg_or_spill(CfreeCg* g, u8 cls, CfreeCgTypeId ty) { return r; } -static void api_ensure_reg(CfreeCg* g, ApiSValue* sv) { - if (sv->res != RES_SPILLED) return; - CGTarget* T = g->target; +static void api_ensure_reg(CfreeCg *g, ApiSValue *sv) { + if (sv->res != RES_SPILLED) + return; + CGTarget *T = g->target; u8 cls = api_class_of_sv(sv); CfreeCgTypeId ty = api_owned_reg_type(g, sv); - Reg r = - api_alloc_reg_or_spill(g, cls, ty ? ty : builtin_id(CFREE_CG_BUILTIN_I32)); + Reg r = api_alloc_reg_or_spill(g, cls, + ty ? ty : builtin_id(CFREE_CG_BUILTIN_I32)); T->reload_reg(T, api_op_reg(r, ty), sv->spill_slot, api_mem_for_spill(g, sv)); api_return_spill_slot(g, sv->spill_slot, cls); sv->spill_slot = FRAME_SLOT_NONE; @@ -1388,10 +1583,11 @@ static void api_ensure_reg(CfreeCg* g, ApiSValue* sv) { sv->res = RES_REG; } -static Operand api_force_reg(CfreeCg* g, ApiSValue* v, CfreeCgTypeId ty) { - CGTarget* T = g->target; +static Operand api_force_reg(CfreeCg *g, ApiSValue *v, CfreeCgTypeId ty) { + CGTarget *T = g->target; api_ensure_reg(g, v); - if (v->op.kind == OPK_REG) return v->op; + if (v->op.kind == OPK_REG) + return v->op; Reg r = api_alloc_reg_or_spill(g, api_type_class(ty), ty); Operand dst = api_op_reg(r, ty); if (v->op.kind == OPK_IMM) { @@ -1412,13 +1608,14 @@ static Operand api_force_reg(CfreeCg* g, ApiSValue* v, CfreeCgTypeId ty) { return dst; } -static Operand api_force_reg_unless_imm(CfreeCg* g, ApiSValue* v, +static Operand api_force_reg_unless_imm(CfreeCg *g, ApiSValue *v, CfreeCgTypeId ty) { - if (v->op.kind == OPK_IMM) return v->op; + if (v->op.kind == OPK_IMM) + return v->op; return api_force_reg(g, v, ty); } -static void api_release(CfreeCg* g, ApiSValue* sv) { +static void api_release(CfreeCg *g, ApiSValue *sv) { if (sv->res == RES_REG) { api_free_reg(g, (Reg)api_reg_of_sv(sv), api_class_of_sv(sv)); } else if (sv->res == RES_SPILLED) { @@ -1428,12 +1625,13 @@ static void api_release(CfreeCg* g, ApiSValue* sv) { sv->res = RES_INHERENT; } -static void api_release_arg_storage(CfreeCg* g, Operand* storage) { +static void api_release_arg_storage(CfreeCg *g, Operand *storage) { if (storage->kind == OPK_REG) { api_free_reg(g, storage->v.reg, storage->cls); } else if (storage->kind == OPK_LOCAL && storage->cls < 3) { CfreeCgTypeId ty = storage->type; - if (cg_type_is_aggregate(g->c, ty)) return; + if (cg_type_is_aggregate(g->c, ty)) + return; api_return_spill_slot(g, storage->v.frame_slot, storage->cls); } else if (storage->kind == OPK_INDIRECT) { api_free_reg(g, storage->v.ind.base, RC_INT); @@ -1444,160 +1642,160 @@ static void api_release_arg_storage(CfreeCg* g, Operand* storage) { static BinOp api_map_int_binop(CfreeCgIntBinOp op) { switch (op) { - case CFREE_CG_INT_ADD: - return BO_IADD; - case CFREE_CG_INT_SUB: - return BO_ISUB; - case CFREE_CG_INT_MUL: - return BO_IMUL; - case CFREE_CG_INT_SDIV: - return BO_SDIV; - case CFREE_CG_INT_UDIV: - return BO_UDIV; - case CFREE_CG_INT_SREM: - return BO_SREM; - case CFREE_CG_INT_UREM: - return BO_UREM; - case CFREE_CG_INT_AND: - return BO_AND; - case CFREE_CG_INT_OR: - return BO_OR; - case CFREE_CG_INT_XOR: - return BO_XOR; - case CFREE_CG_INT_SHL: - return BO_SHL; - case CFREE_CG_INT_LSHR: - return BO_SHR_U; - case CFREE_CG_INT_ASHR: - return BO_SHR_S; + case CFREE_CG_INT_ADD: + return BO_IADD; + case CFREE_CG_INT_SUB: + return BO_ISUB; + case CFREE_CG_INT_MUL: + return BO_IMUL; + case CFREE_CG_INT_SDIV: + return BO_SDIV; + case CFREE_CG_INT_UDIV: + return BO_UDIV; + case CFREE_CG_INT_SREM: + return BO_SREM; + case CFREE_CG_INT_UREM: + return BO_UREM; + case CFREE_CG_INT_AND: + return BO_AND; + case CFREE_CG_INT_OR: + return BO_OR; + case CFREE_CG_INT_XOR: + return BO_XOR; + case CFREE_CG_INT_SHL: + return BO_SHL; + case CFREE_CG_INT_LSHR: + return BO_SHR_U; + case CFREE_CG_INT_ASHR: + return BO_SHR_S; } return BO_IADD; } static BinOp api_map_fp_binop(CfreeCgFpBinOp op) { switch (op) { - case CFREE_CG_FP_ADD: - return BO_FADD; - case CFREE_CG_FP_SUB: - return BO_FSUB; - case CFREE_CG_FP_MUL: - return BO_FMUL; - case CFREE_CG_FP_DIV: - return BO_FDIV; - case CFREE_CG_FP_REM: - return BO_FDIV; + case CFREE_CG_FP_ADD: + return BO_FADD; + case CFREE_CG_FP_SUB: + return BO_FSUB; + case CFREE_CG_FP_MUL: + return BO_FMUL; + case CFREE_CG_FP_DIV: + return BO_FDIV; + case CFREE_CG_FP_REM: + return BO_FDIV; } return BO_FADD; } static UnOp api_map_int_unop(CfreeCgIntUnOp op) { switch (op) { - case CFREE_CG_INT_NEG: - return UO_NEG; - case CFREE_CG_INT_NOT: - return UO_NOT; - case CFREE_CG_INT_BNOT: - return UO_BNOT; + case CFREE_CG_INT_NEG: + return UO_NEG; + case CFREE_CG_INT_NOT: + return UO_NOT; + case CFREE_CG_INT_BNOT: + return UO_BNOT; } return UO_NEG; } static CmpOp api_map_int_cmp(CfreeCgIntCmpOp op) { switch (op) { - case CFREE_CG_INT_EQ: - return CMP_EQ; - case CFREE_CG_INT_NE: - return CMP_NE; - case CFREE_CG_INT_LT_S: - return CMP_LT_S; - case CFREE_CG_INT_LE_S: - return CMP_LE_S; - case CFREE_CG_INT_GT_S: - return CMP_GT_S; - case CFREE_CG_INT_GE_S: - return CMP_GE_S; - case CFREE_CG_INT_LT_U: - return CMP_LT_U; - case CFREE_CG_INT_LE_U: - return CMP_LE_U; - case CFREE_CG_INT_GT_U: - return CMP_GT_U; - case CFREE_CG_INT_GE_U: - return CMP_GE_U; + case CFREE_CG_INT_EQ: + return CMP_EQ; + case CFREE_CG_INT_NE: + return CMP_NE; + case CFREE_CG_INT_LT_S: + return CMP_LT_S; + case CFREE_CG_INT_LE_S: + return CMP_LE_S; + case CFREE_CG_INT_GT_S: + return CMP_GT_S; + case CFREE_CG_INT_GE_S: + return CMP_GE_S; + case CFREE_CG_INT_LT_U: + return CMP_LT_U; + case CFREE_CG_INT_LE_U: + return CMP_LE_U; + case CFREE_CG_INT_GT_U: + return CMP_GT_U; + case CFREE_CG_INT_GE_U: + return CMP_GE_U; } return CMP_EQ; } static CmpOp api_map_fp_cmp(CfreeCgFpCmpOp op) { switch (op) { - case CFREE_CG_FP_OEQ: - case CFREE_CG_FP_UEQ: - return CMP_EQ; - case CFREE_CG_FP_ONE: - case CFREE_CG_FP_UNE: - return CMP_NE; - case CFREE_CG_FP_OLT: - case CFREE_CG_FP_ULT: - return CMP_LT_F; - case CFREE_CG_FP_OLE: - case CFREE_CG_FP_ULE: - return CMP_LE_F; - case CFREE_CG_FP_OGT: - case CFREE_CG_FP_UGT: - return CMP_GT_F; - case CFREE_CG_FP_OGE: - case CFREE_CG_FP_UGE: - return CMP_GE_F; + case CFREE_CG_FP_OEQ: + case CFREE_CG_FP_UEQ: + return CMP_EQ; + case CFREE_CG_FP_ONE: + case CFREE_CG_FP_UNE: + return CMP_NE; + case CFREE_CG_FP_OLT: + case CFREE_CG_FP_ULT: + return CMP_LT_F; + case CFREE_CG_FP_OLE: + case CFREE_CG_FP_ULE: + return CMP_LE_F; + case CFREE_CG_FP_OGT: + case CFREE_CG_FP_UGT: + return CMP_GT_F; + case CFREE_CG_FP_OGE: + case CFREE_CG_FP_UGE: + return CMP_GE_F; } return CMP_EQ; } static AtomicOp api_map_atomic_op(CfreeCgAtomicOp op) { switch (op) { - case CFREE_CG_ATOMIC_XCHG: - return AO_XCHG; - case CFREE_CG_ATOMIC_ADD: - return AO_ADD; - case CFREE_CG_ATOMIC_SUB: - return AO_SUB; - case CFREE_CG_ATOMIC_AND: - return AO_AND; - case CFREE_CG_ATOMIC_OR: - return AO_OR; - case CFREE_CG_ATOMIC_XOR: - return AO_XOR; - case CFREE_CG_ATOMIC_NAND: - return AO_NAND; + case CFREE_CG_ATOMIC_XCHG: + return AO_XCHG; + case CFREE_CG_ATOMIC_ADD: + return AO_ADD; + case CFREE_CG_ATOMIC_SUB: + return AO_SUB; + case CFREE_CG_ATOMIC_AND: + return AO_AND; + case CFREE_CG_ATOMIC_OR: + return AO_OR; + case CFREE_CG_ATOMIC_XOR: + return AO_XOR; + case CFREE_CG_ATOMIC_NAND: + return AO_NAND; } return AO_XCHG; } static MemOrder api_map_mem_order(CfreeCgMemOrder order) { switch (order) { - case CFREE_CG_MO_RELAXED: - return MO_RELAXED; - case CFREE_CG_MO_CONSUME: - return MO_CONSUME; - case CFREE_CG_MO_ACQUIRE: - return MO_ACQUIRE; - case CFREE_CG_MO_RELEASE: - return MO_RELEASE; - case CFREE_CG_MO_ACQ_REL: - return MO_ACQ_REL; - case CFREE_CG_MO_SEQ_CST: - return MO_SEQ_CST; + case CFREE_CG_MO_RELAXED: + return MO_RELAXED; + case CFREE_CG_MO_CONSUME: + return MO_CONSUME; + case CFREE_CG_MO_ACQUIRE: + return MO_ACQUIRE; + case CFREE_CG_MO_RELEASE: + return MO_RELEASE; + case CFREE_CG_MO_ACQ_REL: + return MO_ACQ_REL; + case CFREE_CG_MO_SEQ_CST: + return MO_SEQ_CST; } return MO_RELAXED; } static AsmDir api_map_asm_dir(uint8_t dir) { switch ((CfreeCgAsmDir)dir) { - case CFREE_CG_ASM_IN: - return ASM_IN; - case CFREE_CG_ASM_OUT: - return ASM_OUT; - case CFREE_CG_ASM_INOUT: - return ASM_INOUT; + case CFREE_CG_ASM_IN: + return ASM_IN; + case CFREE_CG_ASM_OUT: + return ASM_OUT; + case CFREE_CG_ASM_INOUT: + return ASM_INOUT; } return ASM_IN; } @@ -1606,44 +1804,47 @@ static AsmDir api_map_asm_dir(uint8_t dir) { static SymBind api_map_bind(CfreeSymBind b) { switch (b) { - case CFREE_SB_LOCAL: - return SB_LOCAL; - case CFREE_SB_GLOBAL: - return SB_GLOBAL; - case CFREE_SB_WEAK: - return SB_WEAK; + case CFREE_SB_LOCAL: + return SB_LOCAL; + case CFREE_SB_GLOBAL: + return SB_GLOBAL; + case CFREE_SB_WEAK: + return SB_WEAK; } return SB_LOCAL; } static SymVis api_map_vis(CfreeCgVisibility v) { switch (v) { - case CFREE_CG_VIS_DEFAULT: - return SV_DEFAULT; - case CFREE_CG_VIS_HIDDEN: - return SV_HIDDEN; - case CFREE_CG_VIS_PROTECTED: - return SV_PROTECTED; + case CFREE_CG_VIS_DEFAULT: + return SV_DEFAULT; + case CFREE_CG_VIS_HIDDEN: + return SV_HIDDEN; + case CFREE_CG_VIS_PROTECTED: + return SV_PROTECTED; } return SV_DEFAULT; } static SymKind api_decl_sym_kind(CfreeCgDecl decl) { if (decl.kind == CFREE_CG_DECL_FUNC) { - if (decl.as.func.flags & CFREE_CG_FUNC_IFUNC) return SK_IFUNC; + if (decl.as.func.flags & CFREE_CG_FUNC_IFUNC) + return SK_IFUNC; return SK_FUNC; } - if (decl.as.object.flags & CFREE_CG_OBJ_TLS) return SK_TLS; + if (decl.as.object.flags & CFREE_CG_OBJ_TLS) + return SK_TLS; return SK_OBJ; } -static void api_remember_sym(CfreeCg* g, ObjSymId sym, CfreeCgTypeId ty, +static void api_remember_sym(CfreeCg *g, ObjSymId sym, CfreeCgTypeId ty, CfreeCgDecl decl) { - Heap* h; - CfreeCgTypeId* nts; - CfreeCgDecl* nas; + Heap *h; + CfreeCgTypeId *nts; + CfreeCgDecl *nas; u32 cap; - if (!g || sym == OBJ_SYM_NONE) return; + if (!g || sym == OBJ_SYM_NONE) + return; if (sym < g->sym_cap) { g->sym_types[sym] = ty; g->sym_attrs[sym] = decl; @@ -1651,12 +1852,16 @@ static void api_remember_sym(CfreeCg* g, ObjSymId sym, CfreeCgTypeId ty, } h = g->c->env->heap; cap = g->sym_cap ? g->sym_cap : 16u; - while (cap <= sym) cap *= 2u; - nts = (CfreeCgTypeId*)h->alloc(h, sizeof(*nts) * cap, _Alignof(CfreeCgTypeId)); - nas = (CfreeCgDecl*)h->alloc(h, sizeof(*nas) * cap, _Alignof(CfreeCgDecl)); + while (cap <= sym) + cap *= 2u; + nts = + (CfreeCgTypeId *)h->alloc(h, sizeof(*nts) * cap, _Alignof(CfreeCgTypeId)); + nas = (CfreeCgDecl *)h->alloc(h, sizeof(*nas) * cap, _Alignof(CfreeCgDecl)); if (!nts || !nas) { - if (nts) h->free(h, nts, sizeof(*nts) * cap); - if (nas) h->free(h, nas, sizeof(*nas) * cap); + if (nts) + h->free(h, nts, sizeof(*nts) * cap); + if (nas) + h->free(h, nas, sizeof(*nas) * cap); return; } memset(nts, 0, sizeof(*nts) * cap); @@ -1676,24 +1881,25 @@ static void api_remember_sym(CfreeCg* g, ObjSymId sym, CfreeCgTypeId ty, g->sym_attrs[sym] = decl; } -static CfreeCgTypeId api_sym_type(CfreeCg* g, CfreeCgSym sym) { +static CfreeCgTypeId api_sym_type(CfreeCg *g, CfreeCgSym sym) { if (!g || sym == CFREE_CG_SYM_NONE || sym >= g->sym_cap) { return CFREE_CG_TYPE_NONE; } return g->sym_types[sym]; } -static CfreeCgDecl api_sym_attrs(CfreeCg* g, CfreeCgSym sym) { +static CfreeCgDecl api_sym_attrs(CfreeCg *g, CfreeCgSym sym) { CfreeCgDecl decl; memset(&decl, 0, sizeof(decl)); decl.kind = CFREE_CG_DECL_OBJECT; decl.sym.bind = CFREE_SB_GLOBAL; decl.sym.visibility = CFREE_CG_VIS_DEFAULT; - if (!g || sym == CFREE_CG_SYM_NONE || sym >= g->sym_cap) return decl; + if (!g || sym == CFREE_CG_SYM_NONE || sym >= g->sym_cap) + return decl; return g->sym_attrs[sym]; } -static int api_sym_is_tls(CfreeCg* g, CfreeCgSym sym) { +static int api_sym_is_tls(CfreeCg *g, CfreeCgSym sym) { CfreeCgDecl decl = api_sym_attrs(g, sym); return decl.kind == CFREE_CG_DECL_OBJECT && (decl.as.object.flags & CFREE_CG_OBJ_TLS); @@ -1701,11 +1907,15 @@ static int api_sym_is_tls(CfreeCg* g, CfreeCgSym sym) { static RelocKind api_data_reloc_kind(int pcrel, uint32_t width) { if (pcrel) { - if (width == 4) return R_PC32; - if (width == 8) return R_PC64; + if (width == 4) + return R_PC32; + if (width == 8) + return R_PC64; } else { - if (width == 4) return R_ABS32; - if (width == 8) return R_ABS64; + if (width == 4) + return R_ABS32; + if (width == 8) + return R_ABS64; } return R_NONE; } @@ -1722,51 +1932,76 @@ static SrcLoc api_no_loc(void) { return loc; } -CfreeCg* cfree_cg_new(CfreeCompiler* c, CfreeObjBuilder* out, - const CfreeCompileOptions* opts) { - Heap* h; - CfreeCg* g; - MCEmitter* mc; - CGTarget* target; +CfreeCg *cfree_cg_new(CfreeCompiler *c, CfreeObjBuilder *out, + const CfreeCompileOptions *opts) { + Heap *h; + CfreeCg *g; + MCEmitter *mc; + CGTarget *target; + Debug *debug = NULL; int opt_level = opts ? opts->opt_level : 0; - if (!c || !out) return NULL; + if (!c || !out) + return NULL; if (opt_level < 0 || opt_level > 2) { - compiler_panic((Compiler*)c, api_no_loc(), + compiler_panic((Compiler *)c, api_no_loc(), "CfreeCg: unsupported opt_level %d", opt_level); } - h = (Heap*)c->env->heap; - mc = mc_new((Compiler*)c, (ObjBuilder*)out); - if (!mc) return NULL; - target = cgtarget_new((Compiler*)c, (ObjBuilder*)out, mc); + h = (Heap *)c->env->heap; + mc = mc_new((Compiler *)c, (ObjBuilder *)out); + if (!mc) + return NULL; + if (opts && opts->debug_info) { + debug = debug_new((Compiler *)c, (ObjBuilder *)out); + if (!debug) { + mc_free(mc); + return NULL; + } + mc->debug = debug; + } + target = cgtarget_new((Compiler *)c, (ObjBuilder *)out, mc); if (!target) { + if (debug) + debug_free(debug); mc_free(mc); return NULL; } + target->debug = debug; if (opt_level > 0) { - target = opt_cgtarget_new((Compiler*)c, target, opt_level); + target = opt_cgtarget_new((Compiler *)c, target, opt_level); + if (target) + target->debug = debug; } - g = (CfreeCg*)h->alloc(h, sizeof(CfreeCg), _Alignof(CfreeCg)); + g = (CfreeCg *)h->alloc(h, sizeof(CfreeCg), _Alignof(CfreeCg)); if (!g) { + if (debug) + debug_free(debug); cgtarget_free(target); mc_free(mc); return NULL; } memset(g, 0, sizeof *g); - g->c = (Compiler*)c; - g->obj = (ObjBuilder*)out; + g->c = (Compiler *)c; + g->obj = (ObjBuilder *)out; g->target = target; g->mc = mc; + g->debug = debug; return g; } -void cfree_cg_free(CfreeCg* g) { - Heap* h; - if (!g) return; +void cfree_cg_free(CfreeCg *g) { + Heap *h; + if (!g) + return; cgtarget_finalize(g->target); + if (g->debug) { + debug_emit(g->debug); + debug_free(g->debug); + } cgtarget_free(g->target); mc_free(g->mc); h = g->c->env->heap; - if (g->stack) h->free(h, g->stack, sizeof(ApiSValue) * g->cap); + if (g->stack) + h->free(h, g->stack, sizeof(ApiSValue) * g->cap); if (g->slot_types) { h->free(h, g->slot_types, sizeof(*g->slot_types) * g->slot_types_cap); } @@ -1789,26 +2024,32 @@ void cfree_cg_free(CfreeCg* g) { * Source location * ============================================================ */ -void cfree_cg_set_loc(CfreeCg* g, CfreeSrcLoc loc) { - if (!g) return; - g->cur_loc = *(SrcLoc*)&loc; - if (g->target->set_loc) g->target->set_loc(g->target, *(SrcLoc*)&loc); +void cfree_cg_set_loc(CfreeCg *g, CfreeSrcLoc loc) { + if (!g) + return; + g->cur_loc = *(SrcLoc *)&loc; + if (g->debug) + debug_set_pending_loc(g->debug, *(SrcLoc *)&loc); + if (g->target->set_loc) + g->target->set_loc(g->target, *(SrcLoc *)&loc); } /* ============================================================ * Function lifecycle * ============================================================ */ -CfreeCgSym cfree_cg_decl(CfreeCg* g, CfreeCgDecl decl) { - Compiler* c; - ObjBuilder* ob; +CfreeCgSym cfree_cg_decl(CfreeCg *g, CfreeCgDecl decl) { + Compiler *c; + ObjBuilder *ob; ObjSymId sym; CfreeCgTypeId ty; - if (!g || !decl.linkage_name) return CFREE_CG_SYM_NONE; + if (!g || !decl.linkage_name) + return CFREE_CG_SYM_NONE; c = g->c; ob = g->obj; ty = resolve_type(c, decl.type); - if (!ty) return CFREE_CG_SYM_NONE; + if (!ty) + return CFREE_CG_SYM_NONE; sym = obj_symbol_find(ob, (Sym)decl.linkage_name); if (sym == OBJ_SYM_NONE) { sym = obj_symbol_ex(ob, (Sym)decl.linkage_name, api_map_bind(decl.sym.bind), @@ -1822,10 +2063,10 @@ CfreeCgSym cfree_cg_decl(CfreeCg* g, CfreeCgDecl decl) { return (CfreeCgSym)sym; } -CfreeCgSym cfree_cg_alias(CfreeCg* g, CfreeCgAlias alias) { - ObjBuilder* ob; +CfreeCgSym cfree_cg_alias(CfreeCg *g, CfreeCgAlias alias) { + ObjBuilder *ob; ObjSymId sym; - const ObjSym* ts; + const ObjSym *ts; CfreeCgDecl decl_attrs; if (!g || !alias.linkage_name || alias.target == CFREE_CG_SYM_NONE) { return CFREE_CG_SYM_NONE; @@ -1833,7 +2074,8 @@ CfreeCgSym cfree_cg_alias(CfreeCg* g, CfreeCgAlias alias) { ob = g->obj; sym = obj_symbol_find(ob, (Sym)alias.linkage_name); ts = obj_symbol_get(ob, (ObjSymId)alias.target); - if (!ts) return CFREE_CG_SYM_NONE; + if (!ts) + return CFREE_CG_SYM_NONE; if (sym == OBJ_SYM_NONE) { sym = obj_symbol_ex(ob, (Sym)alias.linkage_name, api_map_bind(alias.sym.bind), @@ -1842,29 +2084,32 @@ CfreeCgSym cfree_cg_alias(CfreeCg* g, CfreeCgAlias alias) { } else if (ts->section_id != OBJ_SEC_NONE) { obj_symbol_define(ob, sym, ts->section_id, ts->value, ts->size); } - if (alias.sym.flags) obj_symbol_set_flags(ob, sym, (u16)alias.sym.flags); + if (alias.sym.flags) + obj_symbol_set_flags(ob, sym, (u16)alias.sym.flags); decl_attrs = api_sym_attrs(g, alias.target); decl_attrs.sym = alias.sym; api_remember_sym(g, sym, api_sym_type(g, alias.target), decl_attrs); return (CfreeCgSym)sym; } -void cfree_cg_func_begin(CfreeCg* g, CfreeCgSym cg_sym) { - Compiler* c; - ObjBuilder* ob; - CGTarget* T; +void cfree_cg_func_begin(CfreeCg *g, CfreeCgSym cg_sym) { + Compiler *c; + ObjBuilder *ob; + CGTarget *T; ObjSymId sym; ObjSecId text_sec; CfreeCgTypeId fty; - const ABIFuncInfo* abi; + const ABIFuncInfo *abi; CfreeCgDecl attrs; - if (!g) return; + if (!g) + return; c = g->c; ob = g->obj; T = g->target; sym = (ObjSymId)cg_sym; fty = api_sym_type(g, cg_sym); - if (!fty) return; + if (!fty) + return; attrs = api_sym_attrs(g, cg_sym); abi = abi_cg_func_info(c->abi, fty); @@ -1889,18 +2134,27 @@ void cfree_cg_func_begin(CfreeCg* g, CfreeCgSym cg_sym) { g->fn_ret_type = cg_type_func_ret_id(c, fty); g->fn_abi = abi; g->sp = 0; - for (u32 i = 0; i < 3; ++i) g->slot_pools[i].n = 0; + for (u32 i = 0; i < 3; ++i) + g->slot_pools[i].n = 0; g->avs_in_flight = NULL; g->avs_in_flight_n = 0; + if (g->debug) { + DebugTypeId dt = api_debug_type(g, fty); + if (dt != DEBUG_TYPE_NONE) + debug_func_begin(g->debug, sym, dt, g->cur_loc); + } T->func_begin(T, &g->fn_desc); api_regalloc_begin(g); } -void cfree_cg_func_end(CfreeCg* g) { - if (!g) return; +void cfree_cg_func_end(CfreeCg *g) { + if (!g) + return; api_regalloc_finish(g); g->target->func_end(g->target); + if (g->debug) + debug_func_end(g->debug); g->fn_abi = NULL; g->fn_ret_type = CFREE_CG_TYPE_NONE; g->nscopes = 0; @@ -1911,14 +2165,16 @@ void cfree_cg_func_end(CfreeCg* g) { * Local / param slots * ============================================================ */ -CfreeCgSlot cfree_cg_local_slot(CfreeCg* g, CfreeCgTypeId type, +CfreeCgSlot cfree_cg_local_slot(CfreeCg *g, CfreeCgTypeId type, CfreeCgSlotAttrs attrs) { CfreeCgTypeId ty; FrameSlotDesc fsd; FrameSlot slot; - if (!g) return 0; + if (!g) + return 0; ty = resolve_type(g->c, type); - if (!ty) return 0; + if (!ty) + return 0; memset(&fsd, 0, sizeof fsd); fsd.type = ty; fsd.name = (Sym)attrs.name; @@ -1926,21 +2182,24 @@ CfreeCgSlot cfree_cg_local_slot(CfreeCg* g, CfreeCgTypeId type, fsd.size = abi_cg_sizeof(g->c->abi, type); fsd.align = attrs.align ? attrs.align : abi_cg_alignof(g->c->abi, type); fsd.kind = FS_LOCAL; - if (attrs.flags & CFREE_CG_SLOT_ADDRESS_TAKEN) fsd.flags |= FSF_ADDR_TAKEN; + if (attrs.flags & CFREE_CG_SLOT_ADDRESS_TAKEN) + fsd.flags |= FSF_ADDR_TAKEN; slot = g->target->frame_slot(g->target, &fsd); api_remember_slot_type(g, slot, ty); return (CfreeCgSlot)slot; } -CfreeCgSlot cfree_cg_param_slot(CfreeCg* g, uint32_t index, CfreeCgTypeId type, +CfreeCgSlot cfree_cg_param_slot(CfreeCg *g, uint32_t index, CfreeCgTypeId type, CfreeCgSlotAttrs attrs) { CfreeCgTypeId ty; FrameSlot slot; CGParamDesc pd; FrameSlotDesc fsd; - if (!g) return 0; + if (!g) + return 0; ty = resolve_type(g->c, type); - if (!ty) return 0; + if (!ty) + return 0; memset(&fsd, 0, sizeof fsd); fsd.type = ty; @@ -1949,7 +2208,8 @@ CfreeCgSlot cfree_cg_param_slot(CfreeCg* g, uint32_t index, CfreeCgTypeId type, fsd.size = abi_cg_sizeof(g->c->abi, type); fsd.align = attrs.align ? attrs.align : abi_cg_alignof(g->c->abi, type); fsd.kind = FS_PARAM; - if (attrs.flags & CFREE_CG_SLOT_ADDRESS_TAKEN) fsd.flags |= FSF_ADDR_TAKEN; + if (attrs.flags & CFREE_CG_SLOT_ADDRESS_TAKEN) + fsd.flags |= FSF_ADDR_TAKEN; slot = g->target->frame_slot(g->target, &fsd); api_remember_slot_type(g, slot, ty); @@ -1971,17 +2231,19 @@ CfreeCgSlot cfree_cg_param_slot(CfreeCg* g, uint32_t index, CfreeCgTypeId type, * Push operations * ============================================================ */ -void cfree_cg_push_int(CfreeCg* g, uint64_t value, CfreeCgTypeId type) { +void cfree_cg_push_int(CfreeCg *g, uint64_t value, CfreeCgTypeId type) { CfreeCgTypeId ty; - if (!g) return; + if (!g) + return; ty = resolve_type(g->c, type); - if (!ty) return; + if (!ty) + return; api_push(g, api_make_sv(api_op_imm((i64)value, ty), ty)); } -void cfree_cg_push_float(CfreeCg* g, double value, CfreeCgTypeId type) { +void cfree_cg_push_float(CfreeCg *g, double value, CfreeCgTypeId type) { CfreeCgTypeId ty; - CGTarget* T; + CGTarget *T; ConstBytes cb; union { double d; @@ -1990,9 +2252,11 @@ void cfree_cg_push_float(CfreeCg* g, double value, CfreeCgTypeId type) { } u; Reg r; Operand dst; - if (!g) return; + if (!g) + return; ty = resolve_type(g->c, type); - if (!ty) return; + if (!ty) + return; T = g->target; cb.type = ty; cb.size = (u32)abi_cg_sizeof(g->c->abi, type); @@ -2008,18 +2272,20 @@ void cfree_cg_push_float(CfreeCg* g, double value, CfreeCgTypeId type) { api_push(g, api_make_sv(dst, ty)); } -void cfree_cg_push_null(CfreeCg* g, CfreeCgTypeId ptr_type) { +void cfree_cg_push_null(CfreeCg *g, CfreeCgTypeId ptr_type) { CfreeCgTypeId ty; - if (!g) return; + if (!g) + return; ty = resolve_type(g->c, ptr_type); - if (!ty) return; + if (!ty) + return; api_push(g, api_make_sv(api_op_imm(0, ty), ty)); } -CfreeCgSym cfree_cg_const_data(CfreeCg* g, const uint8_t* data, size_t len, +CfreeCgSym cfree_cg_const_data(CfreeCg *g, const uint8_t *data, size_t len, uint32_t align, CfreeCgTypeId pointee_type) { - Compiler* c; - ObjBuilder* ob; + Compiler *c; + ObjBuilder *ob; CfreeCgTypeId pty; Sym sec_name; ObjSecId sec; @@ -2028,11 +2294,13 @@ CfreeCgSym cfree_cg_const_data(CfreeCg* g, const uint8_t* data, size_t len, Sym anon_name; ObjSymId sym; CfreeCgDecl attrs; - if (!g) return CFREE_CG_SYM_NONE; + if (!g) + return CFREE_CG_SYM_NONE; c = g->c; ob = g->obj; pty = resolve_type(c, pointee_type); - if (!pty) return CFREE_CG_SYM_NONE; + if (!pty) + return CFREE_CG_SYM_NONE; sec_name = pool_intern_cstr(c->global, ".rodata"); sec = obj_section(ob, sec_name, SEC_RODATA, SF_ALLOC, align ? align : (u32)abi_cg_alignof(c->abi, pointee_type)); @@ -2051,19 +2319,22 @@ CfreeCgSym cfree_cg_const_data(CfreeCg* g, const uint8_t* data, size_t len, return (CfreeCgSym)sym; } -void cfree_cg_push_local(CfreeCg* g, CfreeCgSlot slot) { +void cfree_cg_push_local(CfreeCg *g, CfreeCgSlot slot) { CfreeCgTypeId ty; - if (!g) return; + if (!g) + return; ty = api_slot_type(g, (FrameSlot)slot); api_push(g, api_make_lv(api_op_local((FrameSlot)slot, ty), ty)); } -void cfree_cg_push_symbol_addr(CfreeCg* g, CfreeCgSym sym, int64_t addend) { +void cfree_cg_push_symbol_addr(CfreeCg *g, CfreeCgSym sym, int64_t addend) { CfreeCgTypeId ty; CfreeCgTypeId ptr_ty; - if (!g) return; + if (!g) + return; ty = api_sym_type(g, sym); - if (!ty) ty = builtin_id(CFREE_CG_BUILTIN_VOID); + if (!ty) + ty = builtin_id(CFREE_CG_BUILTIN_VOID); ptr_ty = cg_type_ptr_to(g->c, ty); if (api_sym_is_tls(g, sym)) { Reg r = api_alloc_reg_or_spill(g, RC_INT, ptr_ty); @@ -2076,11 +2347,13 @@ void cfree_cg_push_symbol_addr(CfreeCg* g, CfreeCgSym sym, int64_t addend) { } } -void cfree_cg_push_symbol_lvalue(CfreeCg* g, CfreeCgSym sym, int64_t addend) { +void cfree_cg_push_symbol_lvalue(CfreeCg *g, CfreeCgSym sym, int64_t addend) { CfreeCgTypeId ty; - if (!g) return; + if (!g) + return; ty = api_sym_type(g, sym); - if (!ty) return; + if (!ty) + return; if (api_sym_is_tls(g, sym)) { CfreeCgTypeId ptr_ty = cg_type_ptr_to(g->c, ty); Reg r = api_alloc_reg_or_spill(g, RC_INT, ptr_ty); @@ -2092,7 +2365,7 @@ void cfree_cg_push_symbol_lvalue(CfreeCg* g, CfreeCgSym sym, int64_t addend) { } } -void cfree_cg_addr_offset(CfreeCg* g, int64_t byte_offset, +void cfree_cg_addr_offset(CfreeCg *g, int64_t byte_offset, CfreeCgTypeId result_type) { ApiSValue v; CfreeCgTypeId rty; @@ -2100,16 +2373,18 @@ void cfree_cg_addr_offset(CfreeCg* g, int64_t byte_offset, Operand base; Operand result; Reg rr; - if (!g) return; + if (!g) + return; rty = resolve_type(g->c, result_type); - if (!rty) return; + if (!rty) + return; v = api_pop(g); api_ensure_reg(g, &v); if (v.op.kind == OPK_GLOBAL) { result = api_op_global(v.op.v.global.sym, v.op.v.global.addend + byte_offset, rty); api_push(g, cg_type_is_ptr(g->c, rty) ? api_make_sv(result, rty) - : api_make_lv(result, rty)); + : api_make_lv(result, rty)); return; } if (v.op.kind == OPK_INDIRECT) { @@ -2117,12 +2392,12 @@ void cfree_cg_addr_offset(CfreeCg* g, int64_t byte_offset, if (ofs >= INT32_MIN && ofs <= INT32_MAX) { result = api_op_indirect(v.op.v.ind.base, (i32)ofs, rty); api_push(g, cg_type_is_ptr(g->c, rty) ? api_make_sv(result, rty) - : api_make_lv(result, rty)); + : api_make_lv(result, rty)); return; } } ptr_ty = cg_type_is_ptr(g->c, api_sv_type(&v)) ? api_sv_type(&v) - : cg_type_ptr_to(g->c, rty); + : cg_type_ptr_to(g->c, rty); base = api_is_lvalue_sv(&v) ? api_force_reg(g, &v, ptr_ty) : api_force_reg(g, &v, ptr_ty); rr = api_alloc_reg_or_spill(g, RC_INT, ptr_ty); @@ -2142,11 +2417,12 @@ void cfree_cg_addr_offset(CfreeCg* g, int64_t byte_offset, * Load / addr / store * ============================================================ */ -void cfree_cg_load(CfreeCg* g, CfreeCgMemAccess access) { +void cfree_cg_load(CfreeCg *g, CfreeCgMemAccess access) { ApiSValue v; CfreeCgTypeId ty; Operand dst; - if (!g) return; + if (!g) + return; v = api_pop(g); api_ensure_reg(g, &v); if (!api_is_lvalue_sv(&v)) { @@ -2154,18 +2430,20 @@ void cfree_cg_load(CfreeCg* g, CfreeCgMemAccess access) { return; } ty = resolve_type(g->c, access.type); - if (!ty) ty = api_sv_type(&v); + if (!ty) + ty = api_sv_type(&v); dst = api_force_reg(g, &v, ty); dst.type = ty; api_push(g, api_make_sv(dst, ty)); } -void cfree_cg_indirect(CfreeCg* g) { +void cfree_cg_indirect(CfreeCg *g) { ApiSValue ptr; CfreeCgTypeId pty; CfreeCgTypeId pointee; Operand ptr_op; - if (!g) return; + if (!g) + return; ptr = api_pop(g); pty = api_sv_type(&ptr); pointee = cg_type_pointee(g->c, pty); @@ -2178,13 +2456,14 @@ void cfree_cg_indirect(CfreeCg* g) { api_push(g, api_make_lv(api_op_indirect(ptr_op.v.reg, 0, pointee), pointee)); } -void cfree_cg_addr(CfreeCg* g) { +void cfree_cg_addr(CfreeCg *g) { ApiSValue v; - CGTarget* T; + CGTarget *T; CfreeCgTypeId pty; Reg r; Operand dst; - if (!g) return; + if (!g) + return; T = g->target; v = api_pop(g); api_ensure_reg(g, &v); @@ -2200,12 +2479,13 @@ void cfree_cg_addr(CfreeCg* g) { api_push(g, api_make_sv(dst, pty)); } -void cfree_cg_store(CfreeCg* g, CfreeCgMemAccess access) { +void cfree_cg_store(CfreeCg *g, CfreeCgMemAccess access) { ApiSValue lv, rv; - CGTarget* T; + CGTarget *T; CfreeCgTypeId ty; Operand src; - if (!g) return; + if (!g) + return; T = g->target; rv = api_pop(g); lv = api_pop(g); @@ -2217,7 +2497,8 @@ void cfree_cg_store(CfreeCg* g, CfreeCgMemAccess access) { return; } ty = resolve_type(g->c, access.type); - if (!ty) ty = api_sv_type(&lv); + if (!ty) + ty = api_sv_type(&lv); if (rv.op.kind == OPK_IMM || rv.op.kind == OPK_REG) { src = rv.op; } else { @@ -2232,13 +2513,14 @@ void cfree_cg_store(CfreeCg* g, CfreeCgMemAccess access) { * Stack manipulation * ============================================================ */ -void cfree_cg_dup(CfreeCg* g) { +void cfree_cg_dup(CfreeCg *g) { ApiSValue v, dup; - ApiSValue* top; + ApiSValue *top; CfreeCgTypeId ty; Reg r; Operand dst; - if (!g || g->sp == 0) return; + if (!g || g->sp == 0) + return; top = &g->stack[g->sp - 1]; api_ensure_reg(g, top); v = *top; @@ -2260,24 +2542,27 @@ void cfree_cg_dup(CfreeCg* g) { api_push(g, dup); } -void cfree_cg_swap(CfreeCg* g) { +void cfree_cg_swap(CfreeCg *g) { ApiSValue tmp; - if (!g || g->sp < 2) return; + if (!g || g->sp < 2) + return; tmp = g->stack[g->sp - 1]; g->stack[g->sp - 1] = g->stack[g->sp - 2]; g->stack[g->sp - 2] = tmp; } -void cfree_cg_drop(CfreeCg* g) { +void cfree_cg_drop(CfreeCg *g) { ApiSValue v; - if (!g) return; + if (!g) + return; v = api_pop(g); api_release(g, &v); } -void cfree_cg_rot3(CfreeCg* g) { +void cfree_cg_rot3(CfreeCg *g) { ApiSValue a, b, c; - if (!g || g->sp < 3) return; + if (!g || g->sp < 3) + return; a = g->stack[g->sp - 3]; b = g->stack[g->sp - 2]; c = g->stack[g->sp - 1]; @@ -2290,14 +2575,15 @@ void cfree_cg_rot3(CfreeCg* g) { * Arithmetic / compare / convert * ============================================================ */ -static void api_cg_binop(CfreeCg* g, BinOp iop) { +static void api_cg_binop(CfreeCg *g, BinOp iop) { ApiSValue b, a; - CGTarget* T; + CGTarget *T; CfreeCgTypeId ty; Operand ra, rb; Reg rr; Operand dst; - if (!g) return; + if (!g) + return; T = g->target; b = api_pop(g); a = api_pop(g); @@ -2313,14 +2599,15 @@ static void api_cg_binop(CfreeCg* g, BinOp iop) { api_push(g, api_make_sv(dst, ty)); } -static void api_cg_unop(CfreeCg* g, UnOp iop) { +static void api_cg_unop(CfreeCg *g, UnOp iop) { ApiSValue a; - CGTarget* T; + CGTarget *T; CfreeCgTypeId ty; Operand ra; Reg rr; Operand dst; - if (!g) return; + if (!g) + return; T = g->target; a = api_pop(g); ty = a.type ? a.type : a.op.type; @@ -2333,15 +2620,16 @@ static void api_cg_unop(CfreeCg* g, UnOp iop) { api_push(g, api_make_sv(dst, ty)); } -static void api_cg_cmp(CfreeCg* g, CmpOp cop) { +static void api_cg_cmp(CfreeCg *g, CmpOp cop) { ApiSValue b, a; - CGTarget* T; + CGTarget *T; CfreeCgTypeId opty; CfreeCgTypeId i32; Operand ra, rb; Reg rr; Operand dst; - if (!g) return; + if (!g) + return; T = g->target; b = api_pop(g); a = api_pop(g); @@ -2358,19 +2646,21 @@ static void api_cg_cmp(CfreeCg* g, CmpOp cop) { api_push(g, api_make_sv(dst, i32)); } -static void api_cg_convert_kind(CfreeCg* g, CfreeCgTypeId dst_type, +static void api_cg_convert_kind(CfreeCg *g, CfreeCgTypeId dst_type, ConvKind ck) { ApiSValue v; - CGTarget* T; + CGTarget *T; CfreeCgTypeId sty; CfreeCgTypeId dty; Operand src; Reg rr; Operand dst; - if (!g) return; + if (!g) + return; T = g->target; dty = resolve_type(g->c, dst_type); - if (!dty) return; + if (!dty) + return; v = api_pop(g); sty = v.type ? v.type : v.op.type; if (sty == dty) { @@ -2394,21 +2684,21 @@ static void api_cg_convert_kind(CfreeCg* g, CfreeCgTypeId dst_type, api_push(g, api_make_sv(dst, dty)); } -void cfree_cg_int_binop(CfreeCg* g, CfreeCgIntBinOp op, uint32_t flags) { +void cfree_cg_int_binop(CfreeCg *g, CfreeCgIntBinOp op, uint32_t flags) { (void)flags; api_cg_binop(g, api_map_int_binop(op)); } -void cfree_cg_int_unop(CfreeCg* g, CfreeCgIntUnOp op, uint32_t flags) { +void cfree_cg_int_unop(CfreeCg *g, CfreeCgIntUnOp op, uint32_t flags) { (void)flags; api_cg_unop(g, api_map_int_unop(op)); } -void cfree_cg_int_cmp(CfreeCg* g, CfreeCgIntCmpOp op) { +void cfree_cg_int_cmp(CfreeCg *g, CfreeCgIntCmpOp op) { api_cg_cmp(g, api_map_int_cmp(op)); } -void cfree_cg_fp_binop(CfreeCg* g, CfreeCgFpBinOp op, uint32_t flags) { +void cfree_cg_fp_binop(CfreeCg *g, CfreeCgFpBinOp op, uint32_t flags) { (void)flags; if (op == CFREE_CG_FP_REM) { compiler_panic(g->c, g->cur_loc, "CfreeCg: FP remainder is unsupported"); @@ -2417,67 +2707,67 @@ void cfree_cg_fp_binop(CfreeCg* g, CfreeCgFpBinOp op, uint32_t flags) { api_cg_binop(g, api_map_fp_binop(op)); } -void cfree_cg_fp_unop(CfreeCg* g, CfreeCgFpUnOp op, uint32_t flags) { +void cfree_cg_fp_unop(CfreeCg *g, CfreeCgFpUnOp op, uint32_t flags) { (void)flags; (void)op; api_cg_unop(g, UO_NEG); } -void cfree_cg_fp_cmp(CfreeCg* g, CfreeCgFpCmpOp op) { +void cfree_cg_fp_cmp(CfreeCg *g, CfreeCgFpCmpOp op) { api_cg_cmp(g, api_map_fp_cmp(op)); } -void cfree_cg_sext(CfreeCg* g, CfreeCgTypeId dst) { +void cfree_cg_sext(CfreeCg *g, CfreeCgTypeId dst) { api_cg_convert_kind(g, dst, CV_SEXT); } -void cfree_cg_zext(CfreeCg* g, CfreeCgTypeId dst) { +void cfree_cg_zext(CfreeCg *g, CfreeCgTypeId dst) { api_cg_convert_kind(g, dst, CV_ZEXT); } -void cfree_cg_trunc(CfreeCg* g, CfreeCgTypeId dst) { +void cfree_cg_trunc(CfreeCg *g, CfreeCgTypeId dst) { api_cg_convert_kind(g, dst, CV_TRUNC); } -void cfree_cg_ptr_to_int(CfreeCg* g, CfreeCgTypeId dst) { +void cfree_cg_ptr_to_int(CfreeCg *g, CfreeCgTypeId dst) { api_cg_convert_kind(g, dst, CV_BITCAST); } -void cfree_cg_int_to_ptr(CfreeCg* g, CfreeCgTypeId dst) { +void cfree_cg_int_to_ptr(CfreeCg *g, CfreeCgTypeId dst) { api_cg_convert_kind(g, dst, CV_BITCAST); } -void cfree_cg_bitcast(CfreeCg* g, CfreeCgTypeId dst) { +void cfree_cg_bitcast(CfreeCg *g, CfreeCgTypeId dst) { api_cg_convert_kind(g, dst, CV_BITCAST); } -void cfree_cg_fpext(CfreeCg* g, CfreeCgTypeId dst) { +void cfree_cg_fpext(CfreeCg *g, CfreeCgTypeId dst) { api_cg_convert_kind(g, dst, CV_FEXT); } -void cfree_cg_fptrunc(CfreeCg* g, CfreeCgTypeId dst) { +void cfree_cg_fptrunc(CfreeCg *g, CfreeCgTypeId dst) { api_cg_convert_kind(g, dst, CV_FTRUNC); } -void cfree_cg_sint_to_float(CfreeCg* g, CfreeCgTypeId dst, +void cfree_cg_sint_to_float(CfreeCg *g, CfreeCgTypeId dst, CfreeCgRounding rounding) { (void)rounding; api_cg_convert_kind(g, dst, CV_ITOF_S); } -void cfree_cg_uint_to_float(CfreeCg* g, CfreeCgTypeId dst, +void cfree_cg_uint_to_float(CfreeCg *g, CfreeCgTypeId dst, CfreeCgRounding rounding) { (void)rounding; api_cg_convert_kind(g, dst, CV_ITOF_U); } -void cfree_cg_float_to_sint(CfreeCg* g, CfreeCgTypeId dst, +void cfree_cg_float_to_sint(CfreeCg *g, CfreeCgTypeId dst, CfreeCgRounding rounding) { (void)rounding; api_cg_convert_kind(g, dst, CV_FTOI_S); } -void cfree_cg_float_to_uint(CfreeCg* g, CfreeCgTypeId dst, +void cfree_cg_float_to_uint(CfreeCg *g, CfreeCgTypeId dst, CfreeCgRounding rounding) { (void)rounding; api_cg_convert_kind(g, dst, CV_FTOI_U); @@ -2487,61 +2777,63 @@ void cfree_cg_float_to_uint(CfreeCg* g, CfreeCgTypeId dst, * Intrinsics (stub) * ============================================================ */ -static IntrinKind api_map_intrinsic(CfreeCg* g, CfreeCgIntrinsic intrin, +static IntrinKind api_map_intrinsic(CfreeCg *g, CfreeCgIntrinsic intrin, CfreeCgTypeId result_type) { u32 size = result_type ? abi_cg_sizeof(g->c->abi, result_type) : 0; switch (intrin) { - case CFREE_CG_INTRIN_TRAP: - return INTRIN_TRAP; - case CFREE_CG_INTRIN_CLZ: - return INTRIN_CLZ; - case CFREE_CG_INTRIN_CTZ: - return INTRIN_CTZ; - case CFREE_CG_INTRIN_POPCOUNT: - return INTRIN_POPCOUNT; - case CFREE_CG_INTRIN_BSWAP: - if (size <= 2) return INTRIN_BSWAP16; - if (size <= 4) return INTRIN_BSWAP32; - return INTRIN_BSWAP64; - case CFREE_CG_INTRIN_SETJMP: - return INTRIN_SETJMP; - case CFREE_CG_INTRIN_LONGJMP: - return INTRIN_LONGJMP; - case CFREE_CG_INTRIN_SADD_OVERFLOW: - case CFREE_CG_INTRIN_UADD_OVERFLOW: - return INTRIN_ADD_OVERFLOW; - case CFREE_CG_INTRIN_SSUB_OVERFLOW: - case CFREE_CG_INTRIN_USUB_OVERFLOW: - return INTRIN_SUB_OVERFLOW; - case CFREE_CG_INTRIN_SMUL_OVERFLOW: - case CFREE_CG_INTRIN_UMUL_OVERFLOW: - return INTRIN_MUL_OVERFLOW; - case CFREE_CG_INTRIN_PREFETCH: - return INTRIN_PREFETCH; - case CFREE_CG_INTRIN_EXPECT: - return INTRIN_EXPECT; - case CFREE_CG_INTRIN_ASSUME_ALIGNED: - return INTRIN_ASSUME_ALIGNED; - case CFREE_CG_INTRIN_FMA: - case CFREE_CG_INTRIN_SYSCALL: - case CFREE_CG_INTRIN_IRQ_SAVE: - case CFREE_CG_INTRIN_IRQ_RESTORE: - case CFREE_CG_INTRIN_IRQ_DISABLE: - case CFREE_CG_INTRIN_IRQ_ENABLE: - case CFREE_CG_INTRIN_DMB: - case CFREE_CG_INTRIN_DSB: - case CFREE_CG_INTRIN_ISB: - case CFREE_CG_INTRIN_DCACHE_CLEAN: - case CFREE_CG_INTRIN_DCACHE_INVALIDATE: - case CFREE_CG_INTRIN_DCACHE_CLEAN_INVALIDATE: - case CFREE_CG_INTRIN_ICACHE_INVALIDATE: - case CFREE_CG_INTRIN_CPU_NOP: - case CFREE_CG_INTRIN_CPU_YIELD: - case CFREE_CG_INTRIN_WFI: - case CFREE_CG_INTRIN_WFE: - case CFREE_CG_INTRIN_SEV: - case CFREE_CG_INTRIN_CORO_SWITCH: - return INTRIN_NONE; + case CFREE_CG_INTRIN_TRAP: + return INTRIN_TRAP; + case CFREE_CG_INTRIN_CLZ: + return INTRIN_CLZ; + case CFREE_CG_INTRIN_CTZ: + return INTRIN_CTZ; + case CFREE_CG_INTRIN_POPCOUNT: + return INTRIN_POPCOUNT; + case CFREE_CG_INTRIN_BSWAP: + if (size <= 2) + return INTRIN_BSWAP16; + if (size <= 4) + return INTRIN_BSWAP32; + return INTRIN_BSWAP64; + case CFREE_CG_INTRIN_SETJMP: + return INTRIN_SETJMP; + case CFREE_CG_INTRIN_LONGJMP: + return INTRIN_LONGJMP; + case CFREE_CG_INTRIN_SADD_OVERFLOW: + case CFREE_CG_INTRIN_UADD_OVERFLOW: + return INTRIN_ADD_OVERFLOW; + case CFREE_CG_INTRIN_SSUB_OVERFLOW: + case CFREE_CG_INTRIN_USUB_OVERFLOW: + return INTRIN_SUB_OVERFLOW; + case CFREE_CG_INTRIN_SMUL_OVERFLOW: + case CFREE_CG_INTRIN_UMUL_OVERFLOW: + return INTRIN_MUL_OVERFLOW; + case CFREE_CG_INTRIN_PREFETCH: + return INTRIN_PREFETCH; + case CFREE_CG_INTRIN_EXPECT: + return INTRIN_EXPECT; + case CFREE_CG_INTRIN_ASSUME_ALIGNED: + return INTRIN_ASSUME_ALIGNED; + case CFREE_CG_INTRIN_FMA: + case CFREE_CG_INTRIN_SYSCALL: + case CFREE_CG_INTRIN_IRQ_SAVE: + case CFREE_CG_INTRIN_IRQ_RESTORE: + case CFREE_CG_INTRIN_IRQ_DISABLE: + case CFREE_CG_INTRIN_IRQ_ENABLE: + case CFREE_CG_INTRIN_DMB: + case CFREE_CG_INTRIN_DSB: + case CFREE_CG_INTRIN_ISB: + case CFREE_CG_INTRIN_DCACHE_CLEAN: + case CFREE_CG_INTRIN_DCACHE_INVALIDATE: + case CFREE_CG_INTRIN_DCACHE_CLEAN_INVALIDATE: + case CFREE_CG_INTRIN_ICACHE_INVALIDATE: + case CFREE_CG_INTRIN_CPU_NOP: + case CFREE_CG_INTRIN_CPU_YIELD: + case CFREE_CG_INTRIN_WFI: + case CFREE_CG_INTRIN_WFE: + case CFREE_CG_INTRIN_SEV: + case CFREE_CG_INTRIN_CORO_SWITCH: + return INTRIN_NONE; } return INTRIN_NONE; } @@ -2560,18 +2852,19 @@ static int api_intrinsic_is_overflow(CfreeCgIntrinsic intrin) { intrin == CFREE_CG_INTRIN_UMUL_OVERFLOW; } -void cfree_cg_intrinsic(CfreeCg* g, CfreeCgIntrinsic intrin, uint32_t nargs, +void cfree_cg_intrinsic(CfreeCg *g, CfreeCgIntrinsic intrin, uint32_t nargs, CfreeCgTypeId result_type) { - CGTarget* T; + CGTarget *T; CfreeCgTypeId rty; CfreeCgTypeId int_ty; IntrinKind kind; - ApiSValue* svs; - Operand* args; + ApiSValue *svs; + Operand *args; Operand dsts[2]; u32 ndst = 0; - Heap* h; - if (!g) return; + Heap *h; + if (!g) + return; T = g->target; h = g->c->env->heap; rty = resolve_type(g->c, result_type); @@ -2585,8 +2878,8 @@ void cfree_cg_intrinsic(CfreeCg* g, CfreeCgIntrinsic intrin, uint32_t nargs, svs = NULL; args = NULL; if (nargs) { - svs = (ApiSValue*)h->alloc(h, sizeof(*svs) * nargs, _Alignof(ApiSValue)); - args = (Operand*)h->alloc(h, sizeof(*args) * nargs, _Alignof(Operand)); + svs = (ApiSValue *)h->alloc(h, sizeof(*svs) * nargs, _Alignof(ApiSValue)); + args = (Operand *)h->alloc(h, sizeof(*args) * nargs, _Alignof(Operand)); memset(args, 0, sizeof(*args) * nargs); for (u32 i = 0; i < nargs; ++i) { u32 idx = nargs - 1u - i; @@ -2619,9 +2912,12 @@ void cfree_cg_intrinsic(CfreeCg* g, CfreeCgIntrinsic intrin, uint32_t nargs, T->intrinsic(T, kind, ndst ? dsts : NULL, ndst, args, nargs); - for (u32 i = 0; i < nargs; ++i) api_release(g, &svs[i]); - if (svs) h->free(h, svs, sizeof(*svs) * nargs); - if (args) h->free(h, args, sizeof(*args) * nargs); + for (u32 i = 0; i < nargs; ++i) + api_release(g, &svs[i]); + if (svs) + h->free(h, svs, sizeof(*svs) * nargs); + if (args) + h->free(h, args, sizeof(*args) * nargs); if (api_intrinsic_is_overflow(intrin)) { api_push(g, api_make_sv(dsts[0], dsts[0].type)); @@ -2635,8 +2931,8 @@ void cfree_cg_intrinsic(CfreeCg* g, CfreeCgIntrinsic intrin, uint32_t nargs, * Atomics (stub) * ============================================================ */ -static CfreeCgTypeId api_atomic_pointee(CfreeCg* g, CfreeCgTypeId pty, - const char* who) { +static CfreeCgTypeId api_atomic_pointee(CfreeCg *g, CfreeCgTypeId pty, + const char *who) { CfreeCgTypeId pointee = cg_type_pointee(g->c, pty); if (!pointee) { compiler_panic(g->c, g->cur_loc, "%s: operand is not a pointer", who); @@ -2645,7 +2941,7 @@ static CfreeCgTypeId api_atomic_pointee(CfreeCg* g, CfreeCgTypeId pty, return pointee; } -static MemAccess api_mem_for_atomic(CfreeCg* g, CfreeCgTypeId val_ty) { +static MemAccess api_mem_for_atomic(CfreeCg *g, CfreeCgTypeId val_ty) { MemAccess ma; memset(&ma, 0, sizeof ma); ma.type = val_ty; @@ -2656,31 +2952,35 @@ static MemAccess api_mem_for_atomic(CfreeCg* g, CfreeCgTypeId val_ty) { return ma; } -int cfree_cg_atomic_is_legal(CfreeCompiler* c, CfreeCgMemAccess access, +int cfree_cg_atomic_is_legal(CfreeCompiler *c, CfreeCgMemAccess access, CfreeCgMemOrder order) { CfreeCgTypeId ty = resolve_type(c, access.type); (void)order; - if (!ty) return 0; + if (!ty) + return 0; return abi_cg_sizeof(c->abi, access.type) <= 8; } -int cfree_cg_atomic_is_lock_free(CfreeCompiler* c, CfreeCgMemAccess access) { +int cfree_cg_atomic_is_lock_free(CfreeCompiler *c, CfreeCgMemAccess access) { CfreeCgTypeId ty = resolve_type(c, access.type); - if (!ty) return 0; + if (!ty) + return 0; return abi_cg_sizeof(c->abi, access.type) <= (u32)c->target.ptr_size; } -void cfree_cg_atomic_load(CfreeCg* g, CfreeCgMemAccess access, +void cfree_cg_atomic_load(CfreeCg *g, CfreeCgMemAccess access, CfreeCgMemOrder order) { ApiSValue ptr; CfreeCgTypeId pty, val_ty; Operand addr, dst; Reg rr; - if (!g) return; + if (!g) + return; ptr = api_pop(g); pty = api_sv_type(&ptr); val_ty = resolve_type(g->c, access.type); - if (!val_ty) val_ty = api_atomic_pointee(g, pty, "CfreeCg: atomic_load"); + if (!val_ty) + val_ty = api_atomic_pointee(g, pty, "CfreeCg: atomic_load"); addr = api_force_reg(g, &ptr, pty); rr = api_alloc_reg_or_spill(g, api_type_class(val_ty), val_ty); dst = api_op_reg(rr, val_ty); @@ -2690,17 +2990,19 @@ void cfree_cg_atomic_load(CfreeCg* g, CfreeCgMemAccess access, api_push(g, api_make_sv(dst, val_ty)); } -void cfree_cg_atomic_store(CfreeCg* g, CfreeCgMemAccess access, +void cfree_cg_atomic_store(CfreeCg *g, CfreeCgMemAccess access, CfreeCgMemOrder order) { ApiSValue val, ptr; CfreeCgTypeId pty, val_ty; Operand addr, src; - if (!g) return; + if (!g) + return; val = api_pop(g); ptr = api_pop(g); pty = api_sv_type(&ptr); val_ty = resolve_type(g->c, access.type); - if (!val_ty) val_ty = api_atomic_pointee(g, pty, "CfreeCg: atomic_store"); + if (!val_ty) + val_ty = api_atomic_pointee(g, pty, "CfreeCg: atomic_store"); addr = api_force_reg(g, &ptr, pty); src = (val.op.kind == OPK_IMM || val.op.kind == OPK_REG) ? val.op @@ -2711,18 +3013,20 @@ void cfree_cg_atomic_store(CfreeCg* g, CfreeCgMemAccess access, api_release(g, &ptr); } -void cfree_cg_atomic_rmw(CfreeCg* g, CfreeCgMemAccess access, +void cfree_cg_atomic_rmw(CfreeCg *g, CfreeCgMemAccess access, CfreeCgAtomicOp op, CfreeCgMemOrder order) { ApiSValue val, ptr; CfreeCgTypeId pty, val_ty; Operand addr, vop, dst; Reg rr; - if (!g) return; + if (!g) + return; val = api_pop(g); ptr = api_pop(g); pty = api_sv_type(&ptr); val_ty = resolve_type(g->c, access.type); - if (!val_ty) val_ty = api_atomic_pointee(g, pty, "CfreeCg: atomic_rmw"); + if (!val_ty) + val_ty = api_atomic_pointee(g, pty, "CfreeCg: atomic_rmw"); addr = api_force_reg(g, &ptr, pty); vop = (val.op.kind == OPK_IMM || val.op.kind == OPK_REG) ? val.op @@ -2737,21 +3041,23 @@ void cfree_cg_atomic_rmw(CfreeCg* g, CfreeCgMemAccess access, api_push(g, api_make_sv(dst, val_ty)); } -void cfree_cg_atomic_cmpxchg(CfreeCg* g, CfreeCgMemAccess access, +void cfree_cg_atomic_cmpxchg(CfreeCg *g, CfreeCgMemAccess access, CfreeCgMemOrder success, CfreeCgMemOrder failure, int weak) { ApiSValue desired, expected, ptr; CfreeCgTypeId pty, val_ty, int_ty; Operand addr, exp_op, des_op, prior, ok; Reg pr, kr; - if (!g) return; + if (!g) + return; (void)weak; desired = api_pop(g); expected = api_pop(g); ptr = api_pop(g); pty = api_sv_type(&ptr); val_ty = resolve_type(g->c, access.type); - if (!val_ty) val_ty = api_atomic_pointee(g, pty, "CfreeCg: atomic_cmpxchg"); + if (!val_ty) + val_ty = api_atomic_pointee(g, pty, "CfreeCg: atomic_cmpxchg"); int_ty = builtin_id(CFREE_CG_BUILTIN_I32); addr = api_force_reg(g, &ptr, pty); exp_op = (expected.op.kind == OPK_IMM || expected.op.kind == OPK_REG) @@ -2774,8 +3080,9 @@ void cfree_cg_atomic_cmpxchg(CfreeCg* g, CfreeCgMemAccess access, api_push(g, api_make_sv(ok, int_ty)); } -void cfree_cg_atomic_fence(CfreeCg* g, CfreeCgMemOrder order) { - if (!g) return; +void cfree_cg_atomic_fence(CfreeCg *g, CfreeCgMemOrder order) { + if (!g) + return; g->target->fence(g->target, api_map_mem_order(order)); } @@ -2783,38 +3090,44 @@ void cfree_cg_atomic_fence(CfreeCg* g, CfreeCgMemOrder order) { * Inline asm (stub) * ============================================================ */ -static const char* api_sym_cstr(CfreeCg* g, CfreeSym sym) { +static const char *api_sym_cstr(CfreeCg *g, CfreeSym sym) { size_t len; - const char* s; - if (!sym) return ""; + const char *s; + if (!sym) + return ""; s = pool_str(g->c->global, (Sym)sym, &len); (void)len; return s ? s : ""; } -static int api_asm_parse_match_index(const char* s) { +static int api_asm_parse_match_index(const char *s) { int n; - if (!s || s[0] < '0' || s[0] > '9') return -1; + if (!s || s[0] < '0' || s[0] > '9') + return -1; n = 0; - for (const char* p = s; *p >= '0' && *p <= '9'; ++p) { + for (const char *p = s; *p >= '0' && *p <= '9'; ++p) { n = n * 10 + (*p - '0'); } return n; } -static const char* api_asm_constraint_body(const char* s) { - if (!s) return ""; - if (s[0] == '=' && s[1] == '&') return s + 2; - if (s[0] == '=' || s[0] == '+' || s[0] == '&') return s + 1; +static const char *api_asm_constraint_body(const char *s) { + if (!s) + return ""; + if (s[0] == '=' && s[1] == '&') + return s + 2; + if (s[0] == '=' || s[0] == '+' || s[0] == '&') + return s + 1; return s; } -static int api_asm_is_early_clobber(const char* s) { - if (!s) return 0; +static int api_asm_is_early_clobber(const char *s) { + if (!s) + return 0; return (s[0] == '=' && s[1] == '&') || s[0] == '&'; } -static void api_asm_spill_sv(CfreeCg* g, ApiSValue* sv, Reg phys, +static void api_asm_spill_sv(CfreeCg *g, ApiSValue *sv, Reg phys, RegClass cls) { FrameSlot slot = api_take_spill_slot(g, cls); Operand victim_reg = api_op_reg(phys, api_owned_reg_type(g, sv)); @@ -2825,34 +3138,35 @@ static void api_asm_spill_sv(CfreeCg* g, ApiSValue* sv, Reg phys, api_set_owned_reg(sv, (Reg)REG_NONE); } -void cfree_cg_inline_asm(CfreeCg* g, CfreeCgInlineAsm asm_block) { - static const char* const match_strs[10] = {"0", "1", "2", "3", "4", +void cfree_cg_inline_asm(CfreeCg *g, CfreeCgInlineAsm asm_block) { + static const char *const match_strs[10] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}; - CGTarget* T; - Heap* h; + CGTarget *T; + Heap *h; CfreeCgTypeId fallback_ty; - AsmConstraint* outs; - AsmConstraint* ins; - Sym* clobs; - ApiSValue* in_svs; - Operand* in_ops; - Operand* out_ops; - u8* out_reg_owned; - const char* tmpl_str; + AsmConstraint *outs; + AsmConstraint *ins; + Sym *clobs; + ApiSValue *in_svs; + Operand *in_ops; + Operand *out_ops; + u8 *out_reg_owned; + const char *tmpl_str; Sym sym_memory; int has_memory_clobber; uint32_t ninout; uint32_t total_inputs; CfreeSym tmpl = asm_block.tmpl; - const CfreeCgAsmOperand* outputs = asm_block.outputs; + const CfreeCgAsmOperand *outputs = asm_block.outputs; uint32_t noutputs = asm_block.noutputs; - const CfreeCgAsmOperand* inputs = asm_block.inputs; + const CfreeCgAsmOperand *inputs = asm_block.inputs; uint32_t ninputs = asm_block.ninputs; - const CfreeSym* clobbers = asm_block.clobbers; + const CfreeSym *clobbers = asm_block.clobbers; uint32_t nclobbers = asm_block.nclobbers; (void)asm_block.flags; (void)asm_block.clobber_abi_sets; - if (!g) return; + if (!g) + return; T = g->target; h = g->c->env->heap; fallback_ty = builtin_id(CFREE_CG_BUILTIN_I64); @@ -2868,15 +3182,16 @@ void cfree_cg_inline_asm(CfreeCg* g, CfreeCgInlineAsm asm_block) { out_reg_owned = NULL; if (noutputs) { - outs = (AsmConstraint*)h->alloc(h, sizeof(*outs) * noutputs, - _Alignof(AsmConstraint)); + outs = (AsmConstraint *)h->alloc(h, sizeof(*outs) * noutputs, + _Alignof(AsmConstraint)); memset(outs, 0, sizeof(*outs) * noutputs); for (u32 i = 0; i < noutputs; ++i) { outs[i].str = api_sym_cstr(g, outputs[i].constraint); outs[i].name = (Sym)outputs[i].name; outs[i].type = resolve_type(g->c, outputs[i].type); outs[i].dir = (u8)api_map_asm_dir(outputs[i].dir); - if (!outs[i].type) outs[i].type = fallback_ty; + if (!outs[i].type) + outs[i].type = fallback_ty; if (outs[i].dir == ASM_INOUT) { if (i >= 10) { compiler_panic(g->c, g->cur_loc, @@ -2887,33 +3202,35 @@ void cfree_cg_inline_asm(CfreeCg* g, CfreeCgInlineAsm asm_block) { } } out_ops = - (Operand*)h->alloc(h, sizeof(*out_ops) * noutputs, _Alignof(Operand)); + (Operand *)h->alloc(h, sizeof(*out_ops) * noutputs, _Alignof(Operand)); memset(out_ops, 0, sizeof(*out_ops) * noutputs); - out_reg_owned = (u8*)h->alloc(h, noutputs, 1); + out_reg_owned = (u8 *)h->alloc(h, noutputs, 1); memset(out_reg_owned, 0, noutputs); } total_inputs = ninputs + ninout; if (total_inputs) { uint32_t inout_index; - ins = (AsmConstraint*)h->alloc(h, sizeof(*ins) * total_inputs, - _Alignof(AsmConstraint)); + ins = (AsmConstraint *)h->alloc(h, sizeof(*ins) * total_inputs, + _Alignof(AsmConstraint)); memset(ins, 0, sizeof(*ins) * total_inputs); - in_svs = (ApiSValue*)h->alloc(h, sizeof(*in_svs) * total_inputs, - _Alignof(ApiSValue)); - in_ops = (Operand*)h->alloc(h, sizeof(*in_ops) * total_inputs, - _Alignof(Operand)); + in_svs = (ApiSValue *)h->alloc(h, sizeof(*in_svs) * total_inputs, + _Alignof(ApiSValue)); + in_ops = (Operand *)h->alloc(h, sizeof(*in_ops) * total_inputs, + _Alignof(Operand)); memset(in_ops, 0, sizeof(*in_ops) * total_inputs); for (u32 i = 0; i < ninputs; ++i) { ins[i].str = api_sym_cstr(g, inputs[i].constraint); ins[i].name = (Sym)inputs[i].name; ins[i].type = resolve_type(g->c, inputs[i].type); ins[i].dir = (u8)api_map_asm_dir(inputs[i].dir); - if (!ins[i].type) ins[i].type = fallback_ty; + if (!ins[i].type) + ins[i].type = fallback_ty; } inout_index = ninputs; for (u32 i = 0; i < noutputs; ++i) { - if (outs[i].dir != ASM_INOUT) continue; + if (outs[i].dir != ASM_INOUT) + continue; ins[inout_index].str = match_strs[i]; ins[inout_index].type = outs[i].type ? outs[i].type : fallback_ty; ins[inout_index].dir = ASM_IN; @@ -2927,13 +3244,15 @@ void cfree_cg_inline_asm(CfreeCg* g, CfreeCgInlineAsm asm_block) { } if (nclobbers) { - clobs = (Sym*)h->alloc(h, sizeof(*clobs) * nclobbers, _Alignof(Sym)); - for (u32 i = 0; i < nclobbers; ++i) clobs[i] = (Sym)clobbers[i]; + clobs = (Sym *)h->alloc(h, sizeof(*clobs) * nclobbers, _Alignof(Sym)); + for (u32 i = 0; i < nclobbers; ++i) + clobs[i] = (Sym)clobbers[i]; } for (u32 i = 0; i < noutputs; ++i) { - const char* body = api_asm_constraint_body(outs[i].str); - if (api_asm_is_early_clobber(outs[i].str)) continue; + const char *body = api_asm_constraint_body(outs[i].str); + if (api_asm_is_early_clobber(outs[i].str)) + continue; if (body[0] == 'r') { CfreeCgTypeId oty = outs[i].type ? outs[i].type : fallback_ty; Reg r = api_alloc_reg_or_spill(g, api_type_class(oty), oty); @@ -2946,7 +3265,7 @@ void cfree_cg_inline_asm(CfreeCg* g, CfreeCgInlineAsm asm_block) { } for (u32 i = 0; i < total_inputs; ++i) { - const char* s = ins[i].str ? ins[i].str : ""; + const char *s = ins[i].str ? ins[i].str : ""; int matched = api_asm_parse_match_index(s); CfreeCgTypeId ity = api_sv_type(&in_svs[i]); if (matched >= 0) { @@ -3001,10 +3320,11 @@ void cfree_cg_inline_asm(CfreeCg* g, CfreeCgInlineAsm asm_block) { } for (u32 i = 0; i < noutputs; ++i) { - const char* body; + const char *body; CfreeCgTypeId oty; Reg r; - if (!api_asm_is_early_clobber(outs[i].str)) continue; + if (!api_asm_is_early_clobber(outs[i].str)) + continue; body = api_asm_constraint_body(outs[i].str); if (body[0] != 'r') { compiler_panic(g->c, g->cur_loc, @@ -3027,14 +3347,16 @@ void cfree_cg_inline_asm(CfreeCg* g, CfreeCgInlineAsm asm_block) { sym_memory = pool_intern_cstr(g->c->global, "memory"); has_memory_clobber = 0; for (u32 i = 0; i < nclobbers; ++i) { - if (clobs[i] == sym_memory) has_memory_clobber = 1; + if (clobs[i] == sym_memory) + has_memory_clobber = 1; } if (has_memory_clobber) { for (u32 i = 0; i < g->sp; ++i) { - ApiSValue* sv = &g->stack[i]; + ApiSValue *sv = &g->stack[i]; Reg phys; RegClass cls; - if (sv->res != RES_REG) continue; + if (sv->res != RES_REG) + continue; phys = api_reg_of_sv(sv); cls = (RegClass)api_class_of_sv(sv); api_asm_spill_sv(g, sv, phys, cls); @@ -3043,7 +3365,8 @@ void cfree_cg_inline_asm(CfreeCg* g, CfreeCgInlineAsm asm_block) { for (u32 i = 0; i < nclobbers; ++i) { Reg phys; RegClass cls; - if (T->resolve_reg_name(T, clobs[i], &phys, &cls) != 0) continue; + if (T->resolve_reg_name(T, clobs[i], &phys, &cls) != 0) + continue; for (u32 k = 0; k < noutputs; ++k) { if (out_ops[k].kind == OPK_REG && out_ops[k].cls == cls && (Reg)out_ops[k].v.reg == phys) { @@ -3059,10 +3382,13 @@ void cfree_cg_inline_asm(CfreeCg* g, CfreeCgInlineAsm asm_block) { } } for (u32 k = 0; k < g->sp; ++k) { - ApiSValue* sv = &g->stack[k]; - if (sv->res != RES_REG) continue; - if (api_class_of_sv(sv) != (u8)cls) continue; - if ((Reg)api_reg_of_sv(sv) != phys) continue; + ApiSValue *sv = &g->stack[k]; + if (sv->res != RES_REG) + continue; + if (api_class_of_sv(sv) != (u8)cls) + continue; + if ((Reg)api_reg_of_sv(sv) != phys) + continue; api_asm_spill_sv(g, sv, phys, cls); } } @@ -3071,52 +3397,66 @@ void cfree_cg_inline_asm(CfreeCg* g, CfreeCgInlineAsm asm_block) { T->asm_block(T, tmpl_str, outs, noutputs, out_ops, ins, total_inputs, in_ops, clobs, nclobbers); - for (u32 i = 0; i < total_inputs; ++i) api_release(g, &in_svs[i]); + for (u32 i = 0; i < total_inputs; ++i) + api_release(g, &in_svs[i]); for (u32 i = 0; i < noutputs; ++i) { CfreeCgTypeId oty = outs[i].type ? outs[i].type : fallback_ty; ApiSValue sv = api_make_sv(out_ops[i], oty); - if (!out_reg_owned[i] && sv.res == RES_REG) sv.res = RES_INHERENT; + if (!out_reg_owned[i] && sv.res == RES_REG) + sv.res = RES_INHERENT; api_push(g, sv); } - if (outs) h->free(h, outs, sizeof(*outs) * noutputs); - if (ins) h->free(h, ins, sizeof(*ins) * total_inputs); - if (clobs) h->free(h, clobs, sizeof(*clobs) * nclobbers); - if (in_svs) h->free(h, in_svs, sizeof(*in_svs) * total_inputs); - if (in_ops) h->free(h, in_ops, sizeof(*in_ops) * total_inputs); - if (out_ops) h->free(h, out_ops, sizeof(*out_ops) * noutputs); - if (out_reg_owned) h->free(h, out_reg_owned, noutputs); + if (outs) + h->free(h, outs, sizeof(*outs) * noutputs); + if (ins) + h->free(h, ins, sizeof(*ins) * total_inputs); + if (clobs) + h->free(h, clobs, sizeof(*clobs) * nclobbers); + if (in_svs) + h->free(h, in_svs, sizeof(*in_svs) * total_inputs); + if (in_ops) + h->free(h, in_ops, sizeof(*in_ops) * total_inputs); + if (out_ops) + h->free(h, out_ops, sizeof(*out_ops) * noutputs); + if (out_reg_owned) + h->free(h, out_reg_owned, noutputs); } /* ============================================================ * Labels / branches * ============================================================ */ -CfreeCgLabel cfree_cg_label_new(CfreeCg* g) { - if (!g) return CFREE_CG_LABEL_NONE; +CfreeCgLabel cfree_cg_label_new(CfreeCg *g) { + if (!g) + return CFREE_CG_LABEL_NONE; return (CfreeCgLabel)g->target->label_new(g->target); } -void cfree_cg_label_place(CfreeCg* g, CfreeCgLabel label) { - if (!g) return; +void cfree_cg_label_place(CfreeCg *g, CfreeCgLabel label) { + if (!g) + return; g->target->label_place(g->target, (Label)label); } -void cfree_cg_jump(CfreeCg* g, CfreeCgLabel label) { - if (!g) return; +void cfree_cg_jump(CfreeCg *g, CfreeCgLabel label) { + if (!g) + return; g->target->jump(g->target, (Label)label); } -void cfree_cg_branch_true(CfreeCg* g, CfreeCgLabel label) { +void cfree_cg_branch_true(CfreeCg *g, CfreeCgLabel label) { ApiSValue v; - CGTarget* T; + CGTarget *T; CfreeCgTypeId ty; - if (!g) return; + if (!g) + return; T = g->target; v = api_pop(g); ty = v.type ? v.type : builtin_id(CFREE_CG_BUILTIN_I32); if (v.op.kind == OPK_IMM) { - if (v.op.v.imm != 0) T->jump(T, (Label)label); + if (v.op.v.imm != 0) + T->jump(T, (Label)label); api_release(g, &v); return; } @@ -3128,16 +3468,18 @@ void cfree_cg_branch_true(CfreeCg* g, CfreeCgLabel label) { } } -void cfree_cg_branch_false(CfreeCg* g, CfreeCgLabel label) { +void cfree_cg_branch_false(CfreeCg *g, CfreeCgLabel label) { ApiSValue v; - CGTarget* T; + CGTarget *T; CfreeCgTypeId ty; - if (!g) return; + if (!g) + return; T = g->target; v = api_pop(g); ty = v.type ? v.type : builtin_id(CFREE_CG_BUILTIN_I32); if (v.op.kind == OPK_IMM) { - if (v.op.v.imm == 0) T->jump(T, (Label)label); + if (v.op.v.imm == 0) + T->jump(T, (Label)label); api_release(g, &v); return; } @@ -3149,15 +3491,18 @@ void cfree_cg_branch_false(CfreeCg* g, CfreeCgLabel label) { } } -void cfree_cg_switch(CfreeCg* g, CfreeCgSwitch sw) { +void cfree_cg_switch(CfreeCg *g, CfreeCgSwitch sw) { ApiSValue selector; CfreeCgTypeId ty; Operand sel; - if (!g) return; - if (g->sp == 0) return; + if (!g) + return; + if (g->sp == 0) + return; selector = api_pop(g); ty = resolve_type(g->c, sw.selector_type); - if (!ty) ty = api_sv_type(&selector); + if (!ty) + ty = api_sv_type(&selector); sel = api_force_reg_unless_imm(g, &selector, ty); for (u32 i = 0; i < sw.ncases; ++i) { Operand imm = api_op_imm((i64)sw.cases[i].value, ty); @@ -3170,29 +3515,32 @@ void cfree_cg_switch(CfreeCg* g, CfreeCgSwitch sw) { api_release(g, &selector); } -void cfree_cg_push_label_addr(CfreeCg* g, CfreeCgLabel label, +void cfree_cg_push_label_addr(CfreeCg *g, CfreeCgLabel label, CfreeCgTypeId ptr_type) { (void)label; - if (!g) return; + if (!g) + return; compiler_panic(g->c, g->cur_loc, "CfreeCg: label addresses are unsupported by CGTarget"); cfree_cg_push_null(g, ptr_type); } -void cfree_cg_computed_goto(CfreeCg* g, const CfreeCgLabel* valid_targets, +void cfree_cg_computed_goto(CfreeCg *g, const CfreeCgLabel *valid_targets, uint32_t ntargets) { ApiSValue target; (void)valid_targets; (void)ntargets; - if (!g) return; + if (!g) + return; target = api_pop(g); api_release(g, &target); compiler_panic(g->c, g->cur_loc, "CfreeCg: computed goto is unsupported by CGTarget"); } -void cfree_cg_unreachable(CfreeCg* g) { - if (!g) return; +void cfree_cg_unreachable(CfreeCg *g) { + if (!g) + return; g->target->intrinsic(g->target, INTRIN_UNREACHABLE, NULL, 0, NULL, 0); } @@ -3204,12 +3552,13 @@ static CfreeCgScope api_scope_handle(u32 idx, u32 generation) { return (CfreeCgScope)((generation << 8) | ((idx + 1u) & 0xffu)); } -static ApiCgScope* api_scope_from_handle(CfreeCg* g, CfreeCgScope scope, - int require_top, const char* who) { +static ApiCgScope *api_scope_from_handle(CfreeCg *g, CfreeCgScope scope, + int require_top, const char *who) { u32 slot; u32 generation; - ApiCgScope* s; - if (!g || scope == 0) return NULL; + ApiCgScope *s; + if (!g || scope == 0) + return NULL; slot = ((u32)scope & 0xffu); generation = ((u32)scope >> 8); if (slot == 0 || slot > API_CG_MAX_SCOPES) { @@ -3233,15 +3582,16 @@ static ApiCgScope* api_scope_from_handle(CfreeCg* g, CfreeCgScope scope, return s; } -static int api_scope_has_result(const ApiCgScope* s) { +static int api_scope_has_result(const ApiCgScope *s) { return s->result_type != CFREE_CG_TYPE_NONE; } -static void api_scope_store_result(CfreeCg* g, ApiCgScope* s, - ApiSValue* result) { +static void api_scope_store_result(CfreeCg *g, ApiCgScope *s, + ApiSValue *result) { Operand dst; Operand src; - if (!api_scope_has_result(s)) return; + if (!api_scope_has_result(s)) + return; dst = api_op_local(s->result_slot, s->result_type); src = (result->op.kind == OPK_IMM || result->op.kind == OPK_REG) ? result->op @@ -3251,11 +3601,12 @@ static void api_scope_store_result(CfreeCg* g, ApiCgScope* s, api_release(g, result); } -static void api_scope_push_result(CfreeCg* g, ApiCgScope* s) { +static void api_scope_push_result(CfreeCg *g, ApiCgScope *s) { Operand dst; Operand src; Reg r; - if (!api_scope_has_result(s)) return; + if (!api_scope_has_result(s)) + return; r = api_alloc_reg_or_spill(g, api_type_class(s->result_type), s->result_type); dst = api_op_reg(r, s->result_type); src = api_op_local(s->result_slot, s->result_type); @@ -3264,13 +3615,14 @@ static void api_scope_push_result(CfreeCg* g, ApiCgScope* s) { api_push(g, api_make_sv(dst, s->result_type)); } -CfreeCgScope cfree_cg_scope_begin(CfreeCg* g, CfreeCgTypeId result_type) { +CfreeCgScope cfree_cg_scope_begin(CfreeCg *g, CfreeCgTypeId result_type) { Label break_lbl, cont_lbl; CGScopeDesc d; - ApiCgScope* s; + ApiCgScope *s; CGScope target_scope; u32 idx; - if (!g) return 0; + if (!g) + return 0; break_lbl = g->target->label_new(g->target); cont_lbl = g->target->label_new(g->target); g->target->label_place(g->target, cont_lbl); @@ -3285,7 +3637,8 @@ CfreeCgScope cfree_cg_scope_begin(CfreeCg* g, CfreeCgTypeId result_type) { s->continue_lbl = cont_lbl; s->result_type = resolve_type(g->c, result_type); s->generation = ++g->scope_generation; - if (s->generation == 0) s->generation = ++g->scope_generation; + if (s->generation == 0) + s->generation = ++g->scope_generation; s->active = 1; g->nscopes++; @@ -3310,9 +3663,10 @@ CfreeCgScope cfree_cg_scope_begin(CfreeCg* g, CfreeCgTypeId result_type) { return api_scope_handle(idx, s->generation); } -void cfree_cg_scope_end(CfreeCg* g, CfreeCgScope scope) { - ApiCgScope* s = api_scope_from_handle(g, scope, 1, "CfreeCg: scope_end"); - if (!s) return; +void cfree_cg_scope_end(CfreeCg *g, CfreeCgScope scope) { + ApiCgScope *s = api_scope_from_handle(g, scope, 1, "CfreeCg: scope_end"); + if (!s) + return; if (api_scope_has_result(s)) { ApiSValue result = api_pop(g); api_scope_store_result(g, s, &result); @@ -3324,9 +3678,10 @@ void cfree_cg_scope_end(CfreeCg* g, CfreeCgScope scope) { g->nscopes--; } -void cfree_cg_break(CfreeCg* g, CfreeCgScope scope) { - ApiCgScope* s = api_scope_from_handle(g, scope, 0, "CfreeCg: break"); - if (!s) return; +void cfree_cg_break(CfreeCg *g, CfreeCgScope scope) { + ApiCgScope *s = api_scope_from_handle(g, scope, 0, "CfreeCg: break"); + if (!s) + return; if (api_scope_has_result(s)) { ApiSValue result = api_pop(g); api_scope_store_result(g, s, &result); @@ -3334,14 +3689,16 @@ void cfree_cg_break(CfreeCg* g, CfreeCgScope scope) { g->target->jump(g->target, s->break_lbl); } -void cfree_cg_break_true(CfreeCg* g, CfreeCgScope scope) { - ApiCgScope* s; +void cfree_cg_break_true(CfreeCg *g, CfreeCgScope scope) { + ApiCgScope *s; ApiSValue cond; - CGTarget* T; + CGTarget *T; CfreeCgTypeId ty; - if (!g || scope == 0) return; + if (!g || scope == 0) + return; s = api_scope_from_handle(g, scope, 0, "CfreeCg: break_true"); - if (!s) return; + if (!s) + return; T = g->target; cond = api_pop(g); ty = cond.type ? cond.type : builtin_id(CFREE_CG_BUILTIN_I32); @@ -3368,7 +3725,8 @@ void cfree_cg_break_true(CfreeCg* g, CfreeCgScope scope) { } } else { if (cond.op.kind == OPK_IMM) { - if (cond.op.v.imm != 0) T->jump(T, s->break_lbl); + if (cond.op.v.imm != 0) + T->jump(T, s->break_lbl); api_release(g, &cond); } else { Operand a = api_force_reg(g, &cond, ty); @@ -3379,14 +3737,16 @@ void cfree_cg_break_true(CfreeCg* g, CfreeCgScope scope) { } } -void cfree_cg_break_false(CfreeCg* g, CfreeCgScope scope) { - ApiCgScope* s; +void cfree_cg_break_false(CfreeCg *g, CfreeCgScope scope) { + ApiCgScope *s; ApiSValue cond; - CGTarget* T; + CGTarget *T; CfreeCgTypeId ty; - if (!g || scope == 0) return; + if (!g || scope == 0) + return; s = api_scope_from_handle(g, scope, 0, "CfreeCg: break_false"); - if (!s) return; + if (!s) + return; T = g->target; cond = api_pop(g); ty = cond.type ? cond.type : builtin_id(CFREE_CG_BUILTIN_I32); @@ -3413,7 +3773,8 @@ void cfree_cg_break_false(CfreeCg* g, CfreeCgScope scope) { } } else { if (cond.op.kind == OPK_IMM) { - if (cond.op.v.imm == 0) T->jump(T, s->break_lbl); + if (cond.op.v.imm == 0) + T->jump(T, s->break_lbl); api_release(g, &cond); } else { Operand a = api_force_reg(g, &cond, ty); @@ -3424,25 +3785,29 @@ void cfree_cg_break_false(CfreeCg* g, CfreeCgScope scope) { } } -void cfree_cg_continue(CfreeCg* g, CfreeCgScope scope) { - ApiCgScope* s = api_scope_from_handle(g, scope, 0, "CfreeCg: continue"); - if (!s) return; +void cfree_cg_continue(CfreeCg *g, CfreeCgScope scope) { + ApiCgScope *s = api_scope_from_handle(g, scope, 0, "CfreeCg: continue"); + if (!s) + return; g->target->jump(g->target, s->continue_lbl); } -void cfree_cg_continue_true(CfreeCg* g, CfreeCgScope scope) { - ApiCgScope* s; +void cfree_cg_continue_true(CfreeCg *g, CfreeCgScope scope) { + ApiCgScope *s; ApiSValue v; - CGTarget* T; + CGTarget *T; CfreeCgTypeId ty; - if (!g || scope == 0) return; + if (!g || scope == 0) + return; s = api_scope_from_handle(g, scope, 0, "CfreeCg: continue_true"); - if (!s) return; + if (!s) + return; T = g->target; v = api_pop(g); ty = v.type ? v.type : builtin_id(CFREE_CG_BUILTIN_I32); if (v.op.kind == OPK_IMM) { - if (v.op.v.imm != 0) T->jump(T, s->continue_lbl); + if (v.op.v.imm != 0) + T->jump(T, s->continue_lbl); api_release(g, &v); } else { Operand a = api_force_reg(g, &v, ty); @@ -3452,19 +3817,22 @@ void cfree_cg_continue_true(CfreeCg* g, CfreeCgScope scope) { } } -void cfree_cg_continue_false(CfreeCg* g, CfreeCgScope scope) { - ApiCgScope* s; +void cfree_cg_continue_false(CfreeCg *g, CfreeCgScope scope) { + ApiCgScope *s; ApiSValue v; - CGTarget* T; + CGTarget *T; CfreeCgTypeId ty; - if (!g || scope == 0) return; + if (!g || scope == 0) + return; s = api_scope_from_handle(g, scope, 0, "CfreeCg: continue_false"); - if (!s) return; + if (!s) + return; T = g->target; v = api_pop(g); ty = v.type ? v.type : builtin_id(CFREE_CG_BUILTIN_I32); if (v.op.kind == OPK_IMM) { - if (v.op.v.imm == 0) T->jump(T, s->continue_lbl); + if (v.op.v.imm == 0) + T->jump(T, s->continue_lbl); api_release(g, &v); } else { Operand a = api_force_reg(g, &v, ty); @@ -3478,19 +3846,21 @@ void cfree_cg_continue_false(CfreeCg* g, CfreeCgScope scope) { * Dynamic stack allocation / variadics (stubs) * ============================================================ */ -void cfree_cg_alloca(CfreeCg* g, uint32_t align, +void cfree_cg_alloca(CfreeCg *g, uint32_t align, CfreeCgTypeId result_ptr_type) { ApiSValue sz; - CGTarget* T; + CGTarget *T; CfreeCgTypeId pty; Operand sz_op; Reg rr; Operand dst; - if (!g) return; + if (!g) + return; T = g->target; sz = api_pop(g); pty = resolve_type(g->c, result_ptr_type); - if (!pty) pty = cg_type_ptr_to(g->c, builtin_id(CFREE_CG_BUILTIN_VOID)); + if (!pty) + pty = cg_type_ptr_to(g->c, builtin_id(CFREE_CG_BUILTIN_VOID)); sz_op = (sz.op.kind == OPK_IMM) ? sz.op : api_force_reg(g, &sz, api_sv_type(&sz)); rr = api_alloc_reg_or_spill(g, RC_INT, pty); @@ -3500,11 +3870,12 @@ void cfree_cg_alloca(CfreeCg* g, uint32_t align, api_push(g, api_make_sv(dst, pty)); } -void cfree_cg_vararg_start(CfreeCg* g) { +void cfree_cg_vararg_start(CfreeCg *g) { ApiSValue ap; - CGTarget* T; + CGTarget *T; Operand ap_op; - if (!g) return; + if (!g) + return; T = g->target; ap = api_pop(g); ap_op = api_force_reg(g, &ap, api_sv_type(&ap)); @@ -3512,17 +3883,19 @@ void cfree_cg_vararg_start(CfreeCg* g) { api_release(g, &ap); } -void cfree_cg_vararg_next(CfreeCg* g, CfreeCgTypeId type) { +void cfree_cg_vararg_next(CfreeCg *g, CfreeCgTypeId type) { ApiSValue ap; - CGTarget* T; + CGTarget *T; CfreeCgTypeId ty; Operand ap_op; Reg rr; Operand dst; - if (!g) return; + if (!g) + return; T = g->target; ty = resolve_type(g->c, type); - if (!ty) return; + if (!ty) + return; ap = api_pop(g); ap_op = api_force_reg(g, &ap, api_sv_type(&ap)); rr = api_alloc_reg_or_spill(g, api_type_class(ty), ty); @@ -3532,11 +3905,12 @@ void cfree_cg_vararg_next(CfreeCg* g, CfreeCgTypeId type) { api_push(g, api_make_sv(dst, ty)); } -void cfree_cg_vararg_end(CfreeCg* g) { +void cfree_cg_vararg_end(CfreeCg *g) { ApiSValue ap; - CGTarget* T; + CGTarget *T; Operand ap_op; - if (!g) return; + if (!g) + return; T = g->target; ap = api_pop(g); ap_op = api_force_reg(g, &ap, api_sv_type(&ap)); @@ -3544,11 +3918,12 @@ void cfree_cg_vararg_end(CfreeCg* g) { api_release(g, &ap); } -void cfree_cg_vararg_copy(CfreeCg* g) { +void cfree_cg_vararg_copy(CfreeCg *g) { ApiSValue src, dst; - CGTarget* T; + CGTarget *T; Operand src_op, dst_op; - if (!g) return; + if (!g) + return; T = g->target; src = api_pop(g); dst = api_pop(g); @@ -3563,13 +3938,14 @@ void cfree_cg_vararg_copy(CfreeCg* g) { * Memory operations (stubs) * ============================================================ */ -void cfree_cg_memcpy(CfreeCg* g, uint64_t size, CfreeCgMemAccess dst_access, +void cfree_cg_memcpy(CfreeCg *g, uint64_t size, CfreeCgMemAccess dst_access, CfreeCgMemAccess src_access) { ApiSValue src, dst; - CGTarget* T; + CGTarget *T; AggregateAccess agg; Operand dst_op, src_op; - if (!g) return; + if (!g) + return; (void)src_access; if (size > UINT32_MAX) { compiler_panic(g->c, g->cur_loc, "CfreeCg: memcpy size exceeds CGTarget"); @@ -3588,11 +3964,12 @@ void cfree_cg_memcpy(CfreeCg* g, uint64_t size, CfreeCgMemAccess dst_access, api_release(g, &src); } -void cfree_cg_memmove(CfreeCg* g, uint64_t size, CfreeCgMemAccess dst_access, +void cfree_cg_memmove(CfreeCg *g, uint64_t size, CfreeCgMemAccess dst_access, CfreeCgMemAccess src_access) { ApiSValue src, dst; Operand args[3]; - if (!g) return; + if (!g) + return; (void)dst_access; (void)src_access; if (size > INT64_MAX) { @@ -3609,13 +3986,14 @@ void cfree_cg_memmove(CfreeCg* g, uint64_t size, CfreeCgMemAccess dst_access, api_release(g, &src); } -void cfree_cg_memset(CfreeCg* g, uint8_t val, uint64_t size, +void cfree_cg_memset(CfreeCg *g, uint8_t val, uint64_t size, CfreeCgMemAccess dst_access) { ApiSValue dst; - CGTarget* T; + CGTarget *T; AggregateAccess agg; Operand dst_op, byte_val; - if (!g) return; + if (!g) + return; if (size > UINT32_MAX) { compiler_panic(g->c, g->cur_loc, "CfreeCg: memset size exceeds CGTarget"); return; @@ -3631,16 +4009,17 @@ void cfree_cg_memset(CfreeCg* g, uint8_t val, uint64_t size, api_release(g, &dst); } -void cfree_cg_index(CfreeCg* g, uint64_t offset) { +void cfree_cg_index(CfreeCg *g, uint64_t offset) { ApiSValue idx, base; - CGTarget* T; + CGTarget *T; CfreeCgTypeId base_ty, base_ptr_ty, elem_ty, idx_ty; - const CgType* base_info; + const CgType *base_info; u32 elemsz; int free_base_op = 0; Operand base_op, idx_op, result; Reg rr; - if (!g) return; + if (!g) + return; if (offset > INT64_MAX) { compiler_panic(g->c, g->cur_loc, "CfreeCg: index offset too large"); return; @@ -3665,7 +4044,8 @@ void cfree_cg_index(CfreeCg* g, uint64_t offset) { } elemsz = (u32)abi_cg_sizeof(g->c->abi, elem_ty); idx_ty = idx.type ? idx.type : idx.op.type; - if (!idx_ty) idx_ty = builtin_id(CFREE_CG_BUILTIN_I32); + if (!idx_ty) + idx_ty = builtin_id(CFREE_CG_BUILTIN_I32); if (base_info && base_info->kind == CFREE_CG_TYPE_ARRAY) { rr = api_alloc_reg_or_spill(g, RC_INT, base_ptr_ty); base_op = api_op_reg(rr, base_ptr_ty); @@ -3692,24 +4072,27 @@ void cfree_cg_index(CfreeCg* g, uint64_t offset) { T->binop(T, BO_IADD, result, base_op, scaled); api_free_reg(g, sr, RC_INT); } - if (free_base_op) api_free_reg(g, base_op.v.reg, RC_INT); - if (!base_info || base_info->kind != CFREE_CG_TYPE_ARRAY) api_release(g, &base); + if (free_base_op) + api_free_reg(g, base_op.v.reg, RC_INT); + if (!base_info || base_info->kind != CFREE_CG_TYPE_ARRAY) + api_release(g, &base); api_release(g, &idx); api_push(g, api_make_lv(api_op_indirect(result.v.reg, 0, elem_ty), elem_ty)); } -void cfree_cg_field(CfreeCg* g, uint32_t field_index) { +void cfree_cg_field(CfreeCg *g, uint32_t field_index) { ApiSValue base; - CGTarget* T; + CGTarget *T; CfreeCgTypeId rec_ty; CfreeCgTypeId field_ty; CfreeCgTypeId rec_ptr_ty; - const CgType* rec_info; - const ABIRecordLayout* layout; + const CgType *rec_info; + const ABIRecordLayout *layout; u32 field_offset; Operand result; Reg rr; - if (!g) return; + if (!g) + return; T = g->target; base = api_pop(g); api_ensure_reg(g, &base); @@ -3766,23 +4149,25 @@ void cfree_cg_field(CfreeCg* g, uint32_t field_index) { * Calls / return * ============================================================ */ -void cfree_cg_call(CfreeCg* g, uint32_t nargs, CfreeCgTypeId fn_type, +void cfree_cg_call(CfreeCg *g, uint32_t nargs, CfreeCgTypeId fn_type, CfreeCgCallAttrs attrs) { - CGTarget* T; + CGTarget *T; CfreeCgTypeId fty; - const ABIFuncInfo* abi; + const ABIFuncInfo *abi; CfreeCgTypeId ret_ty; int has_result; - CGABIValue* avs; + CGABIValue *avs; CGCallDesc desc; ApiSValue callee; int tail; - if (!g) return; + if (!g) + return; tail = attrs.tail == CFREE_CG_TAIL_ALLOWED || attrs.tail == CFREE_CG_TAIL_MUST; T = g->target; fty = resolve_type(g->c, fn_type); - if (!fty) return; + if (!fty) + return; abi = abi_cg_func_info(g->c->abi, fty); ret_ty = cg_type_func_ret_id(g->c, fty); has_result = !tail && !cg_type_is_void(g->c, ret_ty); @@ -3811,7 +4196,8 @@ void cfree_cg_call(CfreeCg* g, uint32_t nargs, CfreeCgTypeId fn_type, aty = arg.type ? arg.type : api_sv_type(&arg); } else { aty = cg_type_func_param_id(g->c, fty, idx); - if (!aty) aty = arg.type; + if (!aty) + aty = arg.type; } avs[idx].type = aty; avs[idx].abi = is_vararg ? NULL : &abi->params[idx]; @@ -3884,20 +4270,22 @@ void cfree_cg_call(CfreeCg* g, uint32_t nargs, CfreeCgTypeId fn_type, } } -static void api_cg_tail_call(CfreeCg* g, uint32_t nargs, CfreeCgTypeId fn_type) +static void api_cg_tail_call(CfreeCg *g, uint32_t nargs, CfreeCgTypeId fn_type) __attribute__((unused)); -static void api_cg_tail_call(CfreeCg* g, uint32_t nargs, +static void api_cg_tail_call(CfreeCg *g, uint32_t nargs, CfreeCgTypeId fn_type) { - CGTarget* T; + CGTarget *T; CfreeCgTypeId fty; - const ABIFuncInfo* abi; - CGABIValue* avs; + const ABIFuncInfo *abi; + CGABIValue *avs; CGCallDesc desc; ApiSValue callee; - if (!g) return; + if (!g) + return; T = g->target; fty = resolve_type(g->c, fn_type); - if (!fty) return; + if (!fty) + return; abi = abi_cg_func_info(g->c->abi, fty); avs = NULL; if (nargs) { @@ -3909,7 +4297,8 @@ static void api_cg_tail_call(CfreeCg* g, uint32_t nargs, ApiSValue arg = api_pop(g); api_ensure_reg(g, &arg); CfreeCgTypeId aty = cg_type_func_param_id(g->c, fty, idx); - if (!aty) aty = arg.type; + if (!aty) + aty = arg.type; avs[idx].type = aty; avs[idx].abi = idx < abi->nparams ? &abi->params[idx] : NULL; avs[idx].storage = @@ -3939,22 +4328,24 @@ static void api_cg_tail_call(CfreeCg* g, uint32_t nargs, } } -static void api_call_symbol_common(CfreeCg* g, CfreeCgSym sym, uint32_t nargs, +static void api_call_symbol_common(CfreeCg *g, CfreeCgSym sym, uint32_t nargs, CfreeCgCallAttrs attrs) { - CGTarget* T; + CGTarget *T; CfreeCgTypeId fty; - const ABIFuncInfo* abi; + const ABIFuncInfo *abi; CfreeCgTypeId ret_ty; int has_result; - CGABIValue* avs; + CGABIValue *avs; CGCallDesc desc; Operand callee_op; - if (!g) return; + if (!g) + return; int tail = attrs.tail == CFREE_CG_TAIL_ALLOWED || attrs.tail == CFREE_CG_TAIL_MUST; T = g->target; fty = api_sym_type(g, sym); - if (!fty) return; + if (!fty) + return; abi = abi_cg_func_info(g->c->abi, fty); ret_ty = cg_type_func_ret_id(g->c, fty); has_result = !tail && !cg_type_is_void(g->c, ret_ty); @@ -3977,7 +4368,8 @@ static void api_call_symbol_common(CfreeCg* g, CfreeCgSym sym, uint32_t nargs, api_ensure_reg(g, &arg); aty = is_vararg ? (arg.type ? arg.type : api_sv_type(&arg)) : cg_type_func_param_id(g->c, fty, idx); - if (!aty) aty = arg.type; + if (!aty) + aty = arg.type; avs[idx].type = aty; avs[idx].abi = is_vararg ? NULL : &abi->params[idx]; if (cg_type_is_aggregate(g->c, aty)) { @@ -4036,18 +4428,19 @@ static void api_call_symbol_common(CfreeCg* g, CfreeCgSym sym, uint32_t nargs, } } -void cfree_cg_call_symbol(CfreeCg* g, CfreeCgSym sym, uint32_t nargs, +void cfree_cg_call_symbol(CfreeCg *g, CfreeCgSym sym, uint32_t nargs, CfreeCgCallAttrs attrs) { api_call_symbol_common(g, sym, nargs, attrs); } -void cfree_cg_ret(CfreeCg* g) { +void cfree_cg_ret(CfreeCg *g) { ApiSValue v; - CGTarget* T; + CGTarget *T; CfreeCgTypeId rty; CGABIValue av; Operand ret_op; - if (!g) return; + if (!g) + return; T = g->target; rty = g->fn_ret_type; if (cg_type_is_void(g->c, rty)) { @@ -4072,8 +4465,9 @@ void cfree_cg_ret(CfreeCg* g) { api_release(g, &v); } -void cfree_cg_ret_void(CfreeCg* g) { - if (!g) return; +void cfree_cg_ret_void(CfreeCg *g) { + if (!g) + return; g->target->ret(g->target, NULL); } @@ -4081,10 +4475,10 @@ void cfree_cg_ret_void(CfreeCg* g) { * Data definitions (stubs) * ============================================================ */ -void cfree_cg_data_begin(CfreeCg* g, CfreeCgSym cg_sym, +void cfree_cg_data_begin(CfreeCg *g, CfreeCgSym cg_sym, CfreeCgDataDefAttrs attrs) { - Compiler* c; - ObjBuilder* ob; + Compiler *c; + ObjBuilder *ob; ObjSymId sym; CfreeCgTypeId ty; u32 align; @@ -4093,14 +4487,17 @@ void cfree_cg_data_begin(CfreeCg* g, CfreeCgSym cg_sym, Sym sec_name_sym; ObjSecId sec; CfreeCgDecl decl_attrs; - if (!g) return; + if (!g) + return; c = g->c; ob = g->obj; sym = (ObjSymId)cg_sym; ty = api_sym_type(g, cg_sym); - if (!ty) return; + if (!ty) + return; decl_attrs = api_sym_attrs(g, cg_sym); - align = attrs.align ? attrs.align : (u32)abi_cg_alignof(c->abi, decl_attrs.type); + align = + attrs.align ? attrs.align : (u32)abi_cg_alignof(c->abi, decl_attrs.type); if (!attrs.section && decl_attrs.as.object.section) { attrs.section = decl_attrs.as.object.section; } @@ -4132,9 +4529,12 @@ void cfree_cg_data_begin(CfreeCg* g, CfreeCgSym cg_sym, sec_flags = SF_ALLOC | SF_WRITE; sec_name_sym = pool_intern_cstr(c->global, ".data"); } - if (attrs.flags & CFREE_CG_DATADEF_RETAIN) sec_flags |= SF_RETAIN; - if (attrs.flags & CFREE_CG_DATADEF_MERGE) sec_flags |= SF_MERGE; - if (attrs.flags & CFREE_CG_DATADEF_STRINGS) sec_flags |= SF_STRINGS; + if (attrs.flags & CFREE_CG_DATADEF_RETAIN) + sec_flags |= SF_RETAIN; + if (attrs.flags & CFREE_CG_DATADEF_MERGE) + sec_flags |= SF_MERGE; + if (attrs.flags & CFREE_CG_DATADEF_STRINGS) + sec_flags |= SF_STRINGS; if (attrs.flags & CFREE_CG_DATADEF_ZERO_FILL) { sec = obj_section_ex(ob, sec_name_sym, sec_kind, SSEM_NOBITS, sec_flags, align, 0, OBJ_SEC_NONE, 0); @@ -4151,15 +4551,17 @@ void cfree_cg_data_begin(CfreeCg* g, CfreeCgSym cg_sym, } } -void cfree_cg_data_common(CfreeCg* g, CfreeCgSym cg_sym, uint64_t size, +void cfree_cg_data_common(CfreeCg *g, CfreeCgSym cg_sym, uint64_t size, uint32_t align) { - ObjSym* osym; + ObjSym *osym; ObjSymId sym; CfreeCgDecl decl_attrs; - if (!g || cg_sym == CFREE_CG_SYM_NONE) return; + if (!g || cg_sym == CFREE_CG_SYM_NONE) + return; sym = (ObjSymId)cg_sym; - osym = (ObjSym*)obj_symbol_get(g->obj, sym); - if (!osym) return; + osym = (ObjSym *)obj_symbol_get(g->obj, sym); + if (!osym) + return; decl_attrs = api_sym_attrs(g, cg_sym); osym->bind = api_map_bind(decl_attrs.sym.bind); osym->vis = api_map_vis(decl_attrs.sym.visibility); @@ -4170,14 +4572,16 @@ void cfree_cg_data_common(CfreeCg* g, CfreeCgSym cg_sym, uint64_t size, osym->common_align = align; } -void cfree_cg_data_align(CfreeCg* g, uint32_t align) { - if (!g || g->data_sec == OBJ_SEC_NONE || !align) return; +void cfree_cg_data_align(CfreeCg *g, uint32_t align) { + if (!g || g->data_sec == OBJ_SEC_NONE || !align) + return; g->data_size = obj_align_to(g->obj, g->data_sec, align) - g->data_base; } -void cfree_cg_data_pad(CfreeCg* g, uint64_t size, uint8_t value) { +void cfree_cg_data_pad(CfreeCg *g, uint64_t size, uint8_t value) { u8 pad[64]; - if (!g || !size) return; + if (!g || !size) + return; memset(pad, value, sizeof(pad)); while (size >= sizeof(pad)) { obj_write(g->obj, g->data_sec, pad, sizeof(pad)); @@ -4190,15 +4594,18 @@ void cfree_cg_data_pad(CfreeCg* g, uint64_t size, uint8_t value) { } } -void cfree_cg_data_int(CfreeCg* g, uint64_t value, CfreeCgTypeId type) { +void cfree_cg_data_int(CfreeCg *g, uint64_t value, CfreeCgTypeId type) { CfreeCgTypeId ty; u32 size; u8 bytes[8]; - if (!g) return; + if (!g) + return; ty = resolve_type(g->c, type); - if (!ty) return; + if (!ty) + return; size = (u32)abi_cg_sizeof(g->c->abi, type); - if (size > sizeof(bytes)) return; + if (size > sizeof(bytes)) + return; for (u32 i = 0; i < size; ++i) { u32 shift = g->c->target.big_endian ? (size - 1u - i) * 8u : i * 8u; bytes[i] = (u8)(value >> shift); @@ -4206,16 +4613,18 @@ void cfree_cg_data_int(CfreeCg* g, uint64_t value, CfreeCgTypeId type) { cfree_cg_data_bytes(g, bytes, size); } -void cfree_cg_data_float(CfreeCg* g, double value, CfreeCgTypeId type) { +void cfree_cg_data_float(CfreeCg *g, double value, CfreeCgTypeId type) { CfreeCgTypeId ty; union { float f; double d; u8 b[8]; } u; - if (!g) return; + if (!g) + return; ty = resolve_type(g->c, type); - if (!ty) return; + if (!ty) + return; if (ty == builtin_id(CFREE_CG_BUILTIN_F32)) { u.f = (float)value; if (g->c->target.big_endian) { @@ -4240,19 +4649,21 @@ void cfree_cg_data_float(CfreeCg* g, double value, CfreeCgTypeId type) { } } -void cfree_cg_data_bytes(CfreeCg* g, const uint8_t* data, size_t len) { - if (!g || !len) return; +void cfree_cg_data_bytes(CfreeCg *g, const uint8_t *data, size_t len) { + if (!g || !len) + return; obj_write(g->obj, g->data_sec, data, len); g->data_size += len; } -void cfree_cg_data_zero(CfreeCg* g, uint64_t size) { - const Section* sec; - if (!g || !size) return; +void cfree_cg_data_zero(CfreeCg *g, uint64_t size) { + const Section *sec; + if (!g || !size) + return; sec = obj_section_get(g->obj, g->data_sec); if (sec && (sec->kind == SEC_BSS || sec->sem == SSEM_NOBITS)) { - obj_reserve_bss(g->obj, g->data_sec, g->data_base + (u32)(g->data_size + size), - 0); + obj_reserve_bss(g->obj, g->data_sec, + g->data_base + (u32)(g->data_size + size), 0); g->data_size += size; return; } @@ -4264,20 +4675,23 @@ void cfree_cg_data_zero(CfreeCg* g, uint64_t size) { obj_write(g->obj, g->data_sec, pad, sizeof pad); remaining -= sizeof pad; } - if (remaining) obj_write(g->obj, g->data_sec, pad, (size_t)remaining); + if (remaining) + obj_write(g->obj, g->data_sec, pad, (size_t)remaining); } g->data_size += size; } -static void api_cg_data_reloc(CfreeCg* g, CfreeCgSym target, int64_t addend, +static void api_cg_data_reloc(CfreeCg *g, CfreeCgSym target, int64_t addend, uint32_t width, int pcrel) { - ObjBuilder* ob; + ObjBuilder *ob; RelocKind rk; u8 pad[8]; - if (!g || !width || width > sizeof(pad)) return; + if (!g || !width || width > sizeof(pad)) + return; ob = g->obj; rk = api_data_reloc_kind(pcrel, width); - if (rk == R_NONE) return; + if (rk == R_NONE) + return; memset(pad, 0, sizeof pad); obj_write(ob, g->data_sec, pad, width); obj_reloc(ob, g->data_sec, g->data_base + (u32)g->data_size, rk, @@ -4285,19 +4699,20 @@ static void api_cg_data_reloc(CfreeCg* g, CfreeCgSym target, int64_t addend, g->data_size += width; } -void cfree_cg_data_addr(CfreeCg* g, CfreeCgSym target, int64_t addend, +void cfree_cg_data_addr(CfreeCg *g, CfreeCgSym target, int64_t addend, uint32_t width, uint32_t address_space) { (void)address_space; api_cg_data_reloc(g, target, addend, width, 0); } -void cfree_cg_data_label_addr(CfreeCg* g, CfreeCgLabel target, int64_t addend, +void cfree_cg_data_label_addr(CfreeCg *g, CfreeCgLabel target, int64_t addend, uint32_t width, uint32_t address_space) { u8 pad[8]; (void)target; (void)addend; (void)address_space; - if (!g || !width || width > sizeof(pad)) return; + if (!g || !width || width > sizeof(pad)) + return; compiler_panic(g->c, g->cur_loc, "CfreeCg: data label addresses are unsupported by ObjBuilder"); memset(pad, 0, sizeof(pad)); @@ -4305,36 +4720,37 @@ void cfree_cg_data_label_addr(CfreeCg* g, CfreeCgLabel target, int64_t addend, g->data_size += width; } -void cfree_cg_data_pcrel(CfreeCg* g, CfreeCgSym target, int64_t addend, +void cfree_cg_data_pcrel(CfreeCg *g, CfreeCgSym target, int64_t addend, uint32_t width) { api_cg_data_reloc(g, target, addend, width, 1); } -void cfree_cg_data_symdiff(CfreeCg* g, CfreeCgSym lhs, CfreeCgSym rhs, +void cfree_cg_data_symdiff(CfreeCg *g, CfreeCgSym lhs, CfreeCgSym rhs, int64_t addend, uint32_t width) { u8 pad[8]; RelocKind add_kind; RelocKind sub_kind; - if (!g || width > sizeof(pad)) return; + if (!g || width > sizeof(pad)) + return; switch (width) { - case 1: - add_kind = R_RV_ADD8; - sub_kind = R_RV_SUB8; - break; - case 2: - add_kind = R_RV_ADD16; - sub_kind = R_RV_SUB16; - break; - case 4: - add_kind = R_RV_ADD32; - sub_kind = R_RV_SUB32; - break; - case 8: - add_kind = R_RV_ADD64; - sub_kind = R_RV_SUB64; - break; - default: - return; + case 1: + add_kind = R_RV_ADD8; + sub_kind = R_RV_SUB8; + break; + case 2: + add_kind = R_RV_ADD16; + sub_kind = R_RV_SUB16; + break; + case 4: + add_kind = R_RV_ADD32; + sub_kind = R_RV_SUB32; + break; + case 8: + add_kind = R_RV_ADD64; + sub_kind = R_RV_SUB64; + break; + default: + return; } memset(pad, 0, sizeof(pad)); obj_write(g->obj, g->data_sec, pad, width); @@ -4345,8 +4761,9 @@ void cfree_cg_data_symdiff(CfreeCg* g, CfreeCgSym lhs, CfreeCgSym rhs, g->data_size += width; } -void cfree_cg_data_end(CfreeCg* g) { - if (!g) return; +void cfree_cg_data_end(CfreeCg *g) { + if (!g) + return; if (g->data_sym != OBJ_SYM_NONE) { obj_symbol_define(g->obj, g->data_sym, g->data_sec, g->data_base, g->data_size); diff --git a/src/arch/aa64/emit.c b/src/arch/aa64/emit.c @@ -3,7 +3,9 @@ #include "arch/aa64/internal.h" -extern void debug_emit_row(Debug*, ObjSecId text_section, u32 offset, SrcLoc); +extern void debug_emit_row(Debug *, ObjSecId text_section, u32 offset, SrcLoc); +extern void debug_func_pc_range(Debug *, ObjSecId text_section, u32 begin_ofs, + u32 end_ofs); /* ============================================================ * Shared type / operand helpers @@ -28,7 +30,8 @@ u32 type_byte_size(CfreeCgTypeId t) { if (t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_I8) || t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_BOOL)) return 1; - if (t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_I16)) return 2; + if (t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_I16)) + return 2; if (t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_I32) || t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_F32)) return 4; @@ -37,25 +40,26 @@ u32 type_byte_size(CfreeCgTypeId t) { u32 size_idx_for_bytes(u32 nbytes) { switch (nbytes) { - case 1: - return 0; - case 2: - return 1; - case 4: - return 2; - case 8: - return 3; - default: - return 3; + case 1: + return 0; + case 2: + return 1; + case 4: + return 2; + case 8: + return 3; + default: + return 3; } } u32 reg_num(Operand op) { return op.v.reg & 0x1fu; } -static u32 collect_mask_regs(u32 mask, u32 first, u32 last, u32* out) { +static u32 collect_mask_regs(u32 mask, u32 first, u32 last, u32 *out) { u32 n = 0; for (u32 r = first; r <= last; ++r) { - if (mask & (1u << r)) out[n++] = r; + if (mask & (1u << r)) + out[n++] = r; } return n; } @@ -64,7 +68,7 @@ static u32 collect_mask_regs(u32 mask, u32 first, u32 last, u32* out) { * Low-level emission * ============================================================ */ -void aa64_emit32(MCEmitter* mc, u32 word) { +void aa64_emit32(MCEmitter *mc, u32 word) { u32 ofs = obj_pos(mc->obj, mc->section_id); u8 b[4]; b[0] = (u8)(word & 0xff); @@ -77,7 +81,7 @@ void aa64_emit32(MCEmitter* mc, u32 word) { } } -void aa64_patch32(ObjBuilder* obj, u32 sec_id, u32 ofs, u32 word) { +void aa64_patch32(ObjBuilder *obj, u32 sec_id, u32 ofs, u32 word) { u8 b[4]; b[0] = (u8)(word & 0xff); b[1] = (u8)((word >> 8) & 0xff); @@ -90,7 +94,7 @@ void aa64_patch32(ObjBuilder* obj, u32 sec_id, u32 ofs, u32 word) { * Immediate encoding helpers * ============================================================ */ -void aa64_emit_load_imm(MCEmitter* mc, u32 sf, u32 Rd, i64 imm) { +void aa64_emit_load_imm(MCEmitter *mc, u32 sf, u32 Rd, i64 imm) { const u32 nslots = sf ? 4u : 2u; u64 v = sf ? (u64)imm : ((u64)imm & 0xffffffffu); @@ -119,17 +123,19 @@ void aa64_emit_load_imm(MCEmitter* mc, u32 sf, u32 Rd, i64 imm) { for (u32 i = 0; i < nslots; ++i) { u32 slot = (u32)((v >> (i * 16)) & 0xffffu); if (!placed) { - if (slot == 0) continue; + if (slot == 0) + continue; aa64_emit32(mc, aa64_movz(sf, Rd, slot, i)); placed = 1; } else if (slot != 0) { aa64_emit32(mc, aa64_movk(sf, Rd, slot, i)); } } - if (!placed) aa64_emit32(mc, aa64_movz(sf, Rd, 0, 0)); + if (!placed) + aa64_emit32(mc, aa64_movz(sf, Rd, 0, 0)); } -void emit_sp_add(MCEmitter* mc, u32 imm) { +void emit_sp_add(MCEmitter *mc, u32 imm) { if (imm <= 0xfff) { aa64_emit32(mc, aa64_add_imm(1, 31, 31, imm, 0)); } else if ((imm & 0xfff) == 0 && (imm >> 12) <= 0xfff) { @@ -144,9 +150,9 @@ void emit_sp_add(MCEmitter* mc, u32 imm) { * Function lifecycle * ============================================================ */ -void aa_func_begin(CGTarget* t, const CGFuncDesc* fd) { - AAImpl* a = impl_of(t); - MCEmitter* mc = t->mc; +void aa_func_begin(CGTarget *t, const CGFuncDesc *fd) { + AAImpl *a = impl_of(t); + MCEmitter *mc = t->mc; mc->set_section(mc, fd->text_section_id); mc->emit_align(mc, 4, 0); @@ -174,7 +180,8 @@ void aa_func_begin(CGTarget* t, const CGFuncDesc* fd) { mc->cfi_startproc(mc); a->prologue_pos = mc->pos(mc); - for (u32 i = 0; i < AA_PROLOGUE_WORDS; ++i) aa64_emit32(mc, AA64_NOP); + for (u32 i = 0; i < AA_PROLOGUE_WORDS; ++i) + aa64_emit32(mc, AA64_NOP); if (a->has_sret) { FrameSlotDesc fsd = { @@ -210,8 +217,8 @@ void aa_func_begin(CGTarget* t, const CGFuncDesc* fd) { .flags = 0, }; a->fp_save_slot = aa_frame_slot(t, &fpd); - AASlot* gs = aa64_slot_get(a, a->gp_save_slot); - AASlot* fs = aa64_slot_get(a, a->fp_save_slot); + AASlot *gs = aa64_slot_get(a, a->gp_save_slot); + AASlot *fs = aa64_slot_get(a, a->fp_save_slot); for (u32 i = 0; i < 8; ++i) { aa64_emit32(mc, aa64_stur(3, i, 29, -(i32)gs->off + (i32)i * 8)); } @@ -221,9 +228,9 @@ void aa_func_begin(CGTarget* t, const CGFuncDesc* fd) { } } -void aa_func_end(CGTarget* t) { - AAImpl* a = impl_of(t); - MCEmitter* mc = t->mc; +void aa_func_end(CGTarget *t) { + AAImpl *a = impl_of(t); + MCEmitter *mc = t->mc; u32 int_regs[10]; u32 fp_regs[8]; @@ -255,24 +262,23 @@ void aa_func_end(CGTarget* t) { for (i32 i = (i32)n_fp_saves - 1; i >= 0; --i) { u32 r0 = fp_regs[i]; - aa64_emit32(mc, aa64_ldr_fp_uimm(3, r0, 31, - fp_save_off + (u32)i * 8u)); + aa64_emit32(mc, aa64_ldr_fp_uimm(3, r0, 31, fp_save_off + (u32)i * 8u)); } for (i32 i = (i32)n_int_saves - 1; i >= 0; --i) { u32 r0 = int_regs[i]; - aa64_emit32(mc, aa64_ldr_uimm(3, r0, 31, - int_save_off + (u32)i * 8u)); + aa64_emit32(mc, aa64_ldr_uimm(3, r0, 31, int_save_off + (u32)i * 8u)); } aa64_emit32(mc, aa64_ldp_x(29, 30, 31, (i32)fp_lr_off)); emit_sp_add(mc, frame_size); aa64_emit32(mc, aa64_ret(AA64_LR)); u32 pos = a->prologue_pos; - ObjBuilder* obj = t->obj; + ObjBuilder *obj = t->obj; u32 sec = a->fd->text_section_id; u32 words[AA_PROLOGUE_WORDS]; - for (u32 i = 0; i < AA_PROLOGUE_WORDS; ++i) words[i] = AA64_NOP; + for (u32 i = 0; i < AA_PROLOGUE_WORDS; ++i) + words[i] = AA64_NOP; u32 wi = 0; if (frame_size <= 0xfff) { @@ -291,20 +297,23 @@ void aa_func_end(CGTarget* t) { words[wi++] = aa64_stp_x(29, 30, 31, (i32)fp_lr_off); words[wi++] = aa64_add_imm(1, 29, 31, fp_lr_off, 0); if (a->has_sret && a->sret_ptr_slot != FRAME_SLOT_NONE) { - AASlot* s = aa64_slot_get(a, a->sret_ptr_slot); + AASlot *s = aa64_slot_get(a, a->sret_ptr_slot); if (s) { - if (wi >= AA_PROLOGUE_WORDS) goto overflow; + if (wi >= AA_PROLOGUE_WORDS) + goto overflow; words[wi++] = aa64_stur(3, 8, 29, -(i32)s->off); } } for (u32 i = 0; i < n_int_saves; ++i) { u32 r0 = int_regs[i]; - if (wi >= AA_PROLOGUE_WORDS) goto overflow; + if (wi >= AA_PROLOGUE_WORDS) + goto overflow; words[wi++] = aa64_str_uimm(3, r0, 31, int_save_off + i * 8u); } for (u32 i = 0; i < n_fp_saves; ++i) { u32 r0 = fp_regs[i]; - if (wi >= AA_PROLOGUE_WORDS) goto overflow; + if (wi >= AA_PROLOGUE_WORDS) + goto overflow; words[wi++] = aa64_str_fp_uimm(3, r0, 31, fp_save_off + i * 8u); } if (0) { @@ -334,6 +343,8 @@ void aa_func_end(CGTarget* t) { u32 end = mc->pos(mc); obj_symbol_define(obj, a->fd->sym, sec, (u64)a->func_start, (u64)(end - a->func_start)); + if (t->debug) + debug_func_pc_range(t->debug, sec, a->func_start, end); mc->cfi_endproc(mc); a->fd = NULL; @@ -343,12 +354,13 @@ void aa_func_end(CGTarget* t) { * Frame slots * ============================================================ */ -FrameSlot aa_frame_slot(CGTarget* t, const FrameSlotDesc* d) { - AAImpl* a = impl_of(t); +FrameSlot aa_frame_slot(CGTarget *t, const FrameSlotDesc *d) { + AAImpl *a = impl_of(t); if (a->nslots == a->slots_cap) { u32 ncap = a->slots_cap ? a->slots_cap * 2 : 8; - AASlot* nbuf = arena_array(t->c->tu, AASlot, ncap); - if (a->slots) memcpy(nbuf, a->slots, sizeof(AASlot) * a->nslots); + AASlot *nbuf = arena_array(t->c->tu, AASlot, ncap); + if (a->slots) + memcpy(nbuf, a->slots, sizeof(AASlot) * a->nslots); a->slots = nbuf; a->slots_cap = ncap; } @@ -358,7 +370,7 @@ FrameSlot aa_frame_slot(CGTarget* t, const FrameSlotDesc* d) { u32 mask = align - 1; next = (next + mask) & ~mask; - AASlot* s = &a->slots[a->nslots]; + AASlot *s = &a->slots[a->nslots]; s->off = next; s->size = size; s->align = align; @@ -373,15 +385,16 @@ FrameSlot aa_frame_slot(CGTarget* t, const FrameSlotDesc* d) { * Parameters * ============================================================ */ -void aa_param(CGTarget* t, const CGParamDesc* p) { - AAImpl* a = impl_of(t); - AASlot* s = aa64_slot_get(a, p->slot); +void aa_param(CGTarget *t, const CGParamDesc *p) { + AAImpl *a = impl_of(t); + AASlot *s = aa64_slot_get(a, p->slot); if (!s) { compiler_panic(t->c, a->loc, "aarch64 param: bad slot"); } - const ABIArgInfo* ai = p->abi; + const ABIArgInfo *ai = p->abi; - if (ai->kind == ABI_ARG_IGNORE) return; + if (ai->kind == ABI_ARG_IGNORE) + return; if (ai->kind == ABI_ARG_INDIRECT) { u32 ptr_reg; if (a->next_param_int < 8) { @@ -417,7 +430,7 @@ void aa_param(CGTarget* t, const CGParamDesc* p) { return; } for (u16 i = 0; i < ai->nparts; ++i) { - const ABIArgPart* pt = &ai->parts[i]; + const ABIArgPart *pt = &ai->parts[i]; u32 part_off = pt->src_offset; u32 sz = pt->size; u32 sidx = size_idx_for_bytes(sz); @@ -425,29 +438,28 @@ void aa_param(CGTarget* t, const CGParamDesc* p) { if (pt->cls == ABI_CLASS_INT) { if (a->next_param_int < 8) { u32 reg = a->next_param_int++; - aa64_emit32(t->mc, aa64_stur(sidx, reg, 29, -(i32)s->off + (i32)part_off)); + aa64_emit32(t->mc, + aa64_stur(sidx, reg, 29, -(i32)s->off + (i32)part_off)); } else { u32 caller_off = a->next_param_stack; a->next_param_stack += 8; - aa64_emit32(t->mc, aa64_ldur(sidx, AA_TMP0, 29, (i32)(16 + caller_off))); aa64_emit32(t->mc, - aa64_stur(sidx, AA_TMP0, 29, - -(i32)s->off + (i32)part_off)); + aa64_ldur(sidx, AA_TMP0, 29, (i32)(16 + caller_off))); + aa64_emit32(t->mc, + aa64_stur(sidx, AA_TMP0, 29, -(i32)s->off + (i32)part_off)); } } else if (pt->cls == ABI_CLASS_FP) { if (a->next_param_fp < 8) { u32 reg = a->next_param_fp++; aa64_emit32(t->mc, - aa64_stur_fp(sidx, reg, 29, -(i32)s->off + (i32)part_off)); + aa64_stur_fp(sidx, reg, 29, -(i32)s->off + (i32)part_off)); } else { u32 caller_off = a->next_param_stack; a->next_param_stack += 8; aa64_emit32(t->mc, - aa64_ldur_fp(sidx, AA_FP_TMP0, 29, - (i32)(16 + caller_off))); - aa64_emit32(t->mc, - aa64_stur_fp(sidx, AA_FP_TMP0, 29, - -(i32)s->off + (i32)part_off)); + aa64_ldur_fp(sidx, AA_FP_TMP0, 29, (i32)(16 + caller_off))); + aa64_emit32(t->mc, aa64_stur_fp(sidx, AA_FP_TMP0, 29, + -(i32)s->off + (i32)part_off)); } } else { compiler_panic(t->c, a->loc, "aarch64 param: ABI class %d unimpl", @@ -460,12 +472,12 @@ void aa_param(CGTarget* t, const CGParamDesc* p) { * Address materialization helpers * ============================================================ */ -static int use_got_for_sym(CGTarget* t, ObjSymId sym) { +static int use_got_for_sym(CGTarget *t, ObjSymId sym) { return obj_symbol_extern_via_got(t->c, t->obj, sym); } -void aa64_emit_got_load_addr(CGTarget* t, u32 dst_reg, ObjSymId sym) { - MCEmitter* mc = t->mc; +void aa64_emit_got_load_addr(CGTarget *t, u32 dst_reg, ObjSymId sym) { + MCEmitter *mc = t->mc; u32 sec = mc->section_id; u32 adrp_pos = mc->pos(mc); aa64_emit32(mc, aa64_adrp_base(dst_reg)); @@ -475,11 +487,12 @@ void aa64_emit_got_load_addr(CGTarget* t, u32 dst_reg, ObjSymId sym) { mc->emit_reloc_at(mc, sec, ldr_pos, R_AARCH64_LD64_GOT_LO12_NC, sym, 0, 0, 0); } -void emit_global_addr(CGTarget* t, u32 dst_reg, ObjSymId sym, i64 addend) { - MCEmitter* mc = t->mc; +void emit_global_addr(CGTarget *t, u32 dst_reg, ObjSymId sym, i64 addend) { + MCEmitter *mc = t->mc; if (use_got_for_sym(t, sym)) { aa64_emit_got_load_addr(t, dst_reg, sym); - if (addend) aa64_emit_addr_adjust(mc, dst_reg, dst_reg, (i32)addend); + if (addend) + aa64_emit_addr_adjust(mc, dst_reg, dst_reg, (i32)addend); return; } u32 sec = mc->section_id; @@ -493,7 +506,7 @@ void emit_global_addr(CGTarget* t, u32 dst_reg, ObjSymId sym, i64 addend) { 0); } -void aa64_emit_addr_adjust(MCEmitter* mc, u32 Rd, u32 base, i32 off) { +void aa64_emit_addr_adjust(MCEmitter *mc, u32 Rd, u32 base, i32 off) { if (off == 0) { aa64_emit32(mc, aa64_mov_reg(1, Rd, base)); return; @@ -510,11 +523,15 @@ void aa64_emit_addr_adjust(MCEmitter* mc, u32 Rd, u32 base, i32 off) { u32 hi = (abs_off >> 12) & 0xfff; u32 lo = abs_off & 0xfff; if (off < 0) { - if (hi) aa64_emit32(mc, aa64_sub_imm(1, Rd, base, hi, 1)); - if (lo) aa64_emit32(mc, aa64_sub_imm(1, Rd, hi ? Rd : base, lo, 0)); + if (hi) + aa64_emit32(mc, aa64_sub_imm(1, Rd, base, hi, 1)); + if (lo) + aa64_emit32(mc, aa64_sub_imm(1, Rd, hi ? Rd : base, lo, 0)); } else { - if (hi) aa64_emit32(mc, aa64_add_imm(1, Rd, base, hi, 1)); - if (lo) aa64_emit32(mc, aa64_add_imm(1, Rd, hi ? Rd : base, lo, 0)); + if (hi) + aa64_emit32(mc, aa64_add_imm(1, Rd, base, hi, 1)); + if (lo) + aa64_emit32(mc, aa64_add_imm(1, Rd, hi ? Rd : base, lo, 0)); } return; } diff --git a/src/arch/rv64/emit.c b/src/arch/rv64/emit.c @@ -1,16 +1,18 @@ -/* src/arch/rv64/emit.c — immediate encoding, function lifecycle, frame setup. */ +/* src/arch/rv64/emit.c — immediate encoding, function lifecycle, frame setup. + */ #include "arch/rv64/internal.h" -static u32 collect_mask_regs(u32 mask, u32 first, u32 last, u32* out) { +static u32 collect_mask_regs(u32 mask, u32 first, u32 last, u32 *out) { u32 n = 0; for (u32 r = first; r <= last; ++r) { - if (mask & (1u << r)) out[n++] = r; + if (mask & (1u << r)) + out[n++] = r; } return n; } -void rv64_emit32(MCEmitter* mc, u32 word) { +void rv64_emit32(MCEmitter *mc, u32 word) { u32 ofs = obj_pos(mc->obj, mc->section_id); u8 b[4]; b[0] = (u8)(word & 0xff); @@ -18,10 +20,11 @@ void rv64_emit32(MCEmitter* mc, u32 word) { b[2] = (u8)((word >> 16) & 0xff); b[3] = (u8)((word >> 24) & 0xff); mc->emit_bytes(mc, b, 4); - if (mc->debug) debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); + if (mc->debug) + debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); } -void rv64_patch32(ObjBuilder* obj, u32 sec_id, u32 ofs, u32 word) { +void rv64_patch32(ObjBuilder *obj, u32 sec_id, u32 ofs, u32 word) { u8 b[4]; b[0] = (u8)(word & 0xff); b[1] = (u8)((word >> 8) & 0xff); @@ -30,14 +33,16 @@ void rv64_patch32(ObjBuilder* obj, u32 sec_id, u32 ofs, u32 word) { obj_patch(obj, sec_id, ofs, b, 4); } -_Noreturn void rv_panic(CGTarget* t, const char* what) { +_Noreturn void rv_panic(CGTarget *t, const char *what) { SrcLoc loc = impl_of(t)->loc; compiler_panic(t->c, loc, "rv64: %s not implemented", what); } -int fits_signed32(i64 v) { return v >= (i64)(i32)0x80000000 && v <= (i64)(i32)0x7fffffff; } +int fits_signed32(i64 v) { + return v >= (i64)(i32)0x80000000 && v <= (i64)(i32)0x7fffffff; +} -void emit_li_32(MCEmitter* mc, u32 rd, i32 imm) { +void emit_li_32(MCEmitter *mc, u32 rd, i32 imm) { if (imm >= -2048 && imm <= 2047) { rv64_emit32(mc, rv_addi(rd, RV_ZERO, imm)); return; @@ -46,10 +51,11 @@ void emit_li_32(MCEmitter* mc, u32 rd, i32 imm) { i32 hi = (i32)((u32)(imm + 0x800) >> 12); i32 lo = (i32)((i32)imm - (i32)(hi << 12)); rv64_emit32(mc, rv_lui(rd, (u32)hi & 0xfffffu)); - if (lo) rv64_emit32(mc, rv_addiw(rd, rd, lo)); + if (lo) + rv64_emit32(mc, rv_addiw(rd, rd, lo)); } -void rv64_emit_load_imm(MCEmitter* mc, u32 sf, u32 rd, i64 imm) { +void rv64_emit_load_imm(MCEmitter *mc, u32 sf, u32 rd, i64 imm) { if (!sf) { /* 32-bit destination: low 32 bits, sign-extended. */ emit_li_32(mc, rd, (i32)imm); @@ -62,10 +68,9 @@ void rv64_emit_load_imm(MCEmitter* mc, u32 sf, u32 rd, i64 imm) { /* General 64-bit load: split into high and low 32 bits, place high * into rd << 32, then OR in low via a temp register (t0=x5). The cg * corpus has no IMM operands that collide with t0, so this is safe. */ - i64 lo32 = (i64)(i32)(imm & 0xffffffffu); /* sign-ext low half */ - i64 hi64 = (imm - lo32) >> 32; /* what remains in hi */ - if (hi64 < (i64)(i32)0x80000000 || - hi64 > (i64)(i32)0x7fffffff) { + i64 lo32 = (i64)(i32)(imm & 0xffffffffu); /* sign-ext low half */ + i64 hi64 = (imm - lo32) >> 32; /* what remains in hi */ + if (hi64 < (i64)(i32)0x80000000 || hi64 > (i64)(i32)0x7fffffff) { /* Out of i32 range — fallback: use a smaller chunked approach. * For the cg corpus this isn't hit; emit a conservative sequence: * li rd, hi32; slli 32; li t0, lo32; or rd, rd, t0. */ @@ -92,7 +97,7 @@ void rv64_emit_load_imm(MCEmitter* mc, u32 sf, u32 rd, i64 imm) { /* sp += imm. imm can be any signed value the caller passes — we pick * the shortest sequence. */ -void emit_sp_addi(MCEmitter* mc, i64 imm) { +void emit_sp_addi(MCEmitter *mc, i64 imm) { if (imm >= -2048 && imm <= 2047) { rv64_emit32(mc, rv_addi(RV_SP, RV_SP, (i32)imm)); return; @@ -103,9 +108,9 @@ void emit_sp_addi(MCEmitter* mc, i64 imm) { /* ---- function lifecycle ---- */ -void rv_func_begin(CGTarget* t, const CGFuncDesc* fd) { - RImpl* a = impl_of(t); - MCEmitter* mc = t->mc; +void rv_func_begin(CGTarget *t, const CGFuncDesc *fd) { + RImpl *a = impl_of(t); + MCEmitter *mc = t->mc; mc->set_section(mc, fd->text_section_id); mc->emit_align(mc, 4, 0); @@ -134,7 +139,8 @@ void rv_func_begin(CGTarget* t, const CGFuncDesc* fd) { /* Reserve a NOP-filled prologue placeholder; func_end patches it. */ a->prologue_pos = mc->pos(mc); - for (u32 i = 0; i < RV_PROLOGUE_WORDS; ++i) rv64_emit32(mc, RV_NOP); + for (u32 i = 0; i < RV_PROLOGUE_WORDS; ++i) + rv64_emit32(mc, RV_NOP); /* For an sret return, the caller passed the destination pointer in * a0; reserve a hidden slot to spill it into so the body can use a0 @@ -163,10 +169,10 @@ void rv_func_begin(CGTarget* t, const CGFuncDesc* fd) { * is_variadic is set. */ } -void rv_func_end(CGTarget* t) { - RImpl* a = impl_of(t); - MCEmitter* mc = t->mc; - ObjBuilder* obj = t->obj; +void rv_func_end(CGTarget *t) { + RImpl *a = impl_of(t); + MCEmitter *mc = t->mc; + ObjBuilder *obj = t->obj; u32 sec = a->fd->text_section_id; u32 int_regs[10]; @@ -247,7 +253,8 @@ void rv_func_end(CGTarget* t) { /* Now patch the prologue placeholder. */ u32 pos = a->prologue_pos; u32 words[RV_PROLOGUE_WORDS]; - for (u32 i = 0; i < RV_PROLOGUE_WORDS; ++i) words[i] = RV_NOP; + for (u32 i = 0; i < RV_PROLOGUE_WORDS; ++i) + words[i] = RV_NOP; u32 wi = 0; /* addi sp, sp, -frame_size (or 2-insn if too large) */ @@ -262,13 +269,15 @@ void rv_func_end(CGTarget* t) { i32 hi = (i32)((u32)((i32)neg + 0x800) >> 12); i32 lo = (i32)neg - (hi << 12); words[wi++] = rv_lui(RV_T0, (u32)hi & 0xfffffu); - if (lo) words[wi++] = rv_addiw(RV_T0, RV_T0, lo); + if (lo) + words[wi++] = rv_addiw(RV_T0, RV_T0, lo); words[wi++] = rv_add(RV_SP, RV_SP, RV_T0); } else { compiler_panic(t->c, a->loc, "rv64: frame_size too large to patch"); } } - /* sd s0, fp_pair_off(sp); sd ra, fp_pair_off+8(sp); addi s0, sp, fp_pair_off */ + /* sd s0, fp_pair_off(sp); sd ra, fp_pair_off+8(sp); addi s0, sp, fp_pair_off + */ if ((i32)fp_pair_off > 2047 || (i32)(fp_pair_off + 8) > 2047) { compiler_panic(t->c, a->loc, "rv64: fp_pair_off out of imm12 range"); } @@ -278,9 +287,10 @@ void rv_func_end(CGTarget* t) { /* If sret, spill incoming a0 into the hidden slot. */ if (a->has_sret && a->sret_ptr_slot != FRAME_SLOT_NONE) { - RvSlot* s = rv64_slot_get(a, a->sret_ptr_slot); + RvSlot *s = rv64_slot_get(a, a->sret_ptr_slot); if (s) { - if (wi >= RV_PROLOGUE_WORDS) goto overflow; + if (wi >= RV_PROLOGUE_WORDS) + goto overflow; words[wi++] = rv_sd(RV_A0, RV_S0, -(i32)s->off); } } @@ -290,7 +300,8 @@ void rv_func_end(CGTarget* t) { * == caller's first stack arg. */ if (a->is_variadic) { for (u32 i = a->next_param_int; i < 8; ++i) { - if (wi >= RV_PROLOGUE_WORDS) goto overflow; + if (wi >= RV_PROLOGUE_WORDS) + goto overflow; words[wi++] = rv_sd(RV_A0 + i, RV_S0, 16 + (i32)i * 8); } } @@ -298,14 +309,16 @@ void rv_func_end(CGTarget* t) { for (u32 i = 0; i < n_int_saves; ++i) { u32 r = int_regs[i]; i32 off = int_save_base - 8 * (i32)i; - if (wi >= RV_PROLOGUE_WORDS) goto overflow; + if (wi >= RV_PROLOGUE_WORDS) + goto overflow; words[wi++] = rv_sd(r, RV_S0, off); } /* fp saves */ for (u32 i = 0; i < n_fp_saves; ++i) { u32 r = fp_regs[i]; i32 off = fp_save_base - 8 * (i32)i; - if (wi >= RV_PROLOGUE_WORDS) goto overflow; + if (wi >= RV_PROLOGUE_WORDS) + goto overflow; words[wi++] = rv_fsd(r, RV_S0, off); } if (0) { @@ -335,6 +348,8 @@ void rv_func_end(CGTarget* t) { u32 end = mc->pos(mc); obj_symbol_define(obj, a->fd->sym, sec, (u64)a->func_start, (u64)(end - a->func_start)); + if (t->debug) + debug_func_pc_range(t->debug, sec, a->func_start, end); mc->cfi_endproc(mc); a->fd = NULL; diff --git a/src/arch/rv64/internal.h b/src/arch/rv64/internal.h @@ -5,8 +5,8 @@ #include <string.h> #include "arch/arch.h" -#include "arch/rv64/rv64.h" #include "arch/rv64/isa.h" +#include "arch/rv64/rv64.h" #include "core/arena.h" #include "core/pool.h" #include "obj/obj.h" @@ -36,13 +36,13 @@ typedef struct RvScope { typedef struct RImpl { CGTarget base; SrcLoc loc; - const CGFuncDesc* fd; + const CGFuncDesc *fd; u32 func_start; u32 prologue_pos; MCLabel epilogue_label; - RvSlot* slots; + RvSlot *slots; u32 nslots; u32 slots_cap; u32 cum_off; @@ -58,7 +58,7 @@ typedef struct RImpl { u32 used_cs_int_mask; /* bit reg set for s2-s11 */ u32 used_cs_fp_mask; /* bit reg set for fs2-fs11 */ - RvScope* scopes; + RvScope *scopes; u32 nscopes; u32 scopes_cap; @@ -66,7 +66,7 @@ typedef struct RImpl { struct RvAllocaPatch { u32 pos; u32 dst_reg; - }* add_patches; + } *add_patches; u32 nadd_patches; u32 add_patches_cap; @@ -75,7 +75,7 @@ typedef struct RImpl { } RImpl; /* ---- impl_of ---- */ -static inline RImpl* impl_of(CGTarget* t) { return (RImpl*)t; } +static inline RImpl *impl_of(CGTarget *t) { return (RImpl *)t; } /* ---- type helpers ---- */ #define CG_BUILTIN_ID(k) ((CfreeCgTypeId)((1u << 6) | (u32)(k))) @@ -91,7 +91,8 @@ static inline u32 type_byte_size(CfreeCgTypeId t) { if (t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_I8) || t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_BOOL)) return 1; - if (t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_I16)) return 2; + if (t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_I16)) + return 2; if (t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_I32) || t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_F32)) return 4; @@ -105,50 +106,52 @@ static inline int type_is_signed(CfreeCgTypeId t) { static inline u32 reg_num(Operand op) { return op.v.reg & 0x1fu; } /* ---- emit.c: function lifecycle (referenced by ops.c vtable) ---- */ -void rv_func_begin(CGTarget* t, const CGFuncDesc* fd); -void rv_func_end(CGTarget* t); +void rv_func_begin(CGTarget *t, const CGFuncDesc *fd); +void rv_func_end(CGTarget *t); -void rv_coord_vtable_init(CGTarget* t); +void rv_coord_vtable_init(CGTarget *t); /* ---- emit helpers (defined in emit.c, used cross-file) ---- */ -extern void debug_emit_row(Debug*, ObjSecId text_section, u32 offset, SrcLoc); - -void rv64_emit32(MCEmitter* mc, u32 word); -void rv64_patch32(ObjBuilder* obj, u32 sec_id, u32 ofs, u32 word); -int fits_signed32(i64 v); -void emit_li_32(MCEmitter* mc, u32 rd, i32 imm); -void rv64_emit_load_imm(MCEmitter* mc, u32 sf, u32 rd, i64 imm); -void emit_sp_addi(MCEmitter* mc, i64 imm); -_Noreturn void rv_panic(CGTarget* t, const char* what); +extern void debug_emit_row(Debug *, ObjSecId text_section, u32 offset, SrcLoc); +extern void debug_func_pc_range(Debug *, ObjSecId text_section, u32 begin_ofs, + u32 end_ofs); + +void rv64_emit32(MCEmitter *mc, u32 word); +void rv64_patch32(ObjBuilder *obj, u32 sec_id, u32 ofs, u32 word); +int fits_signed32(i64 v); +void emit_li_32(MCEmitter *mc, u32 rd, i32 imm); +void rv64_emit_load_imm(MCEmitter *mc, u32 sf, u32 rd, i64 imm); +void emit_sp_addi(MCEmitter *mc, i64 imm); +_Noreturn void rv_panic(CGTarget *t, const char *what); /* ---- alloc.c: all functions (non-static; referenced by ops.c vtable) ---- */ -FrameSlot rv_frame_slot(CGTarget* t, const FrameSlotDesc* d); -RvSlot* rv64_slot_get(RImpl* a, FrameSlot fs); -void rv_param(CGTarget* t, const CGParamDesc* p); -void rv_spill_reg(CGTarget* t, Operand src, FrameSlot slot, MemAccess ma); -void rv_reload_reg(CGTarget* t, Operand dst, FrameSlot slot, MemAccess ma); -Label rv_label_new(CGTarget* t); -void rv_label_place(CGTarget* t, Label l); -void rv_jump(CGTarget* t, Label l); -u32 rv64_force_reg_int(CGTarget* t, Operand op, u32 scratch); -void rv_cmp_branch(CGTarget* t, CmpOp op, Operand a_op, Operand b_op, Label l); -void rv_cmp(CGTarget* t, CmpOp op, Operand dst, Operand a_op, Operand b_op); -CGScope rv_scope_begin(CGTarget* t, const CGScopeDesc* d); -void rv_scope_else(CGTarget* t, CGScope s); -void rv_scope_end(CGTarget* t, CGScope s); -void rv_break_to(CGTarget* t, CGScope s); -void rv_continue_to(CGTarget* t, CGScope s); +FrameSlot rv_frame_slot(CGTarget *t, const FrameSlotDesc *d); +RvSlot *rv64_slot_get(RImpl *a, FrameSlot fs); +void rv_param(CGTarget *t, const CGParamDesc *p); +void rv_spill_reg(CGTarget *t, Operand src, FrameSlot slot, MemAccess ma); +void rv_reload_reg(CGTarget *t, Operand dst, FrameSlot slot, MemAccess ma); +Label rv_label_new(CGTarget *t); +void rv_label_place(CGTarget *t, Label l); +void rv_jump(CGTarget *t, Label l); +u32 rv64_force_reg_int(CGTarget *t, Operand op, u32 scratch); +void rv_cmp_branch(CGTarget *t, CmpOp op, Operand a_op, Operand b_op, Label l); +void rv_cmp(CGTarget *t, CmpOp op, Operand dst, Operand a_op, Operand b_op); +CGScope rv_scope_begin(CGTarget *t, const CGScopeDesc *d); +void rv_scope_else(CGTarget *t, CGScope s); +void rv_scope_end(CGTarget *t, CGScope s); +void rv_break_to(CGTarget *t, CGScope s); +void rv_continue_to(CGTarget *t, CGScope s); /* ---- ops.c: functions used cross-file ---- */ -void rv_load(CGTarget* t, Operand dst, Operand addr, MemAccess ma); -void rv_store(CGTarget* t, Operand addr, Operand src, MemAccess ma); -u32 enc_int_store(u32 nbytes, u32 src, u32 base, i32 off); -u32 enc_int_load(u32 nbytes, int sign_ext, u32 rd, u32 base, i32 off); -u32 addr_base(CGTarget* t, Operand addr, i32* out_off, u32 tmp_reg); -void rv64_emit_addr_adjust(MCEmitter* mc, u32 rd, u32 base, i32 off); -ObjSymId emit_pcrel_anchor(CGTarget* t, u32 sec, u32 auipc_pos); -void rv64_emit_got_load_addr(CGTarget* t, u32 dst_reg, ObjSymId sym); -u32 agg_addr_reg(CGTarget* t, Operand op, u32 scratch); -int rv64_use_got_for_sym(CGTarget* t, ObjSymId sym); -int mem_order_is_acquire(MemOrder o); -int mem_order_is_release(MemOrder o); +void rv_load(CGTarget *t, Operand dst, Operand addr, MemAccess ma); +void rv_store(CGTarget *t, Operand addr, Operand src, MemAccess ma); +u32 enc_int_store(u32 nbytes, u32 src, u32 base, i32 off); +u32 enc_int_load(u32 nbytes, int sign_ext, u32 rd, u32 base, i32 off); +u32 addr_base(CGTarget *t, Operand addr, i32 *out_off, u32 tmp_reg); +void rv64_emit_addr_adjust(MCEmitter *mc, u32 rd, u32 base, i32 off); +ObjSymId emit_pcrel_anchor(CGTarget *t, u32 sec, u32 auipc_pos); +void rv64_emit_got_load_addr(CGTarget *t, u32 dst_reg, ObjSymId sym); +u32 agg_addr_reg(CGTarget *t, Operand op, u32 scratch); +int rv64_use_got_for_sym(CGTarget *t, ObjSymId sym); +int mem_order_is_acquire(MemOrder o); +int mem_order_is_release(MemOrder o); diff --git a/src/arch/x64/emit.c b/src/arch/x64/emit.c @@ -7,8 +7,8 @@ #include <string.h> #include "arch/arch.h" -#include "arch/x64/x64.h" #include "arch/x64/isa.h" +#include "arch/x64/x64.h" #include "core/arena.h" #include "core/pool.h" #include "obj/obj.h" @@ -19,19 +19,19 @@ * Shared constant tables. */ const Reg g_int_order[6] = { - X64_RBX, X64_R12, X64_R13, X64_R14, X64_R15, /* callee-saved (n_cs=5) */ - X64_R10, /* caller-saved tail */ + X64_RBX, X64_R12, X64_R13, X64_R14, X64_R15, /* callee-saved (n_cs=5) */ + X64_R10, /* caller-saved tail */ }; const Reg g_fp_order[10] = { /* All xmm regs are caller-saved on SysV; preference order is xmm6 * upward to keep the low arg/return regs (xmm0..5) clear for calls. */ - X64_XMM6, X64_XMM7, X64_XMM8, X64_XMM0 + 9, X64_XMM0 + 10, + X64_XMM6, X64_XMM7, X64_XMM8, X64_XMM0 + 9, X64_XMM0 + 10, X64_XMM0 + 11, X64_XMM0 + 12, X64_XMM0 + 13, X64_XMM0 + 14, X64_XMM15, }; const u32 g_int_arg_regs[6] = {X64_RDI, X64_RSI, X64_RDX, - X64_RCX, X64_R8, X64_R9}; + X64_RCX, X64_R8, X64_R9}; /* ============================================================ * Byte-level emit helpers. @@ -41,12 +41,13 @@ const u32 g_int_arg_regs[6] = {X64_RDI, X64_RSI, X64_RDX, * displacement, optional immediate. Helpers below build sequences * into the active MCEmitter section, recording one Debug row per * instruction-start. */ -static void emit1(MCEmitter* mc, u8 b) { +static void emit1(MCEmitter *mc, u8 b) { u32 ofs = obj_pos(mc->obj, mc->section_id); mc->emit_bytes(mc, &b, 1); - if (mc->debug) debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); + if (mc->debug) + debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); } -void emit_u32le(MCEmitter* mc, u32 v) { +void emit_u32le(MCEmitter *mc, u32 v) { u8 b[4]; b[0] = (u8)v; b[1] = (u8)(v >> 8); @@ -54,27 +55,33 @@ void emit_u32le(MCEmitter* mc, u32 v) { b[3] = (u8)(v >> 24); mc->emit_bytes(mc, b, 4); } -static void emit_u64le(MCEmitter* mc, u64 v) { +static void emit_u64le(MCEmitter *mc, u64 v) { u8 b[8]; - for (int i = 0; i < 8; ++i) b[i] = (u8)(v >> (i * 8)); + for (int i = 0; i < 8; ++i) + b[i] = (u8)(v >> (i * 8)); mc->emit_bytes(mc, b, 8); } static u8 make_rex(int w, u32 reg, u32 index, u32 rm) { u8 r = 0; - if (w) r |= X64_REX_W; - if (reg & 8) r |= X64_REX_R; - if (index & 8) r |= X64_REX_X; - if (rm & 8) r |= X64_REX_B; + if (w) + r |= X64_REX_W; + if (reg & 8) + r |= X64_REX_R; + if (index & 8) + r |= X64_REX_X; + if (rm & 8) + r |= X64_REX_B; return r ? (u8)(X64_REX_BASE | r) : 0; } -void emit_rex(MCEmitter* mc, int w, u32 reg, u32 index, u32 rm) { +void emit_rex(MCEmitter *mc, int w, u32 reg, u32 index, u32 rm) { u8 r = make_rex(w, reg, index, rm); - if (r) mc->emit_bytes(mc, &r, 1); + if (r) + mc->emit_bytes(mc, &r, 1); } /* Force REX (even REX=0x40) — required for byte-reg encodings that * promote SIL/DIL/etc. */ -void emit_rex_force(MCEmitter* mc, int w, u32 reg, u32 index, u32 rm) { +void emit_rex_force(MCEmitter *mc, int w, u32 reg, u32 index, u32 rm) { u8 r = (u8)(X64_REX_BASE | (w ? X64_REX_W : 0) | ((reg & 8) ? X64_REX_R : 0) | ((index & 8) ? X64_REX_X : 0) | ((rm & 8) ? X64_REX_B : 0)); mc->emit_bytes(mc, &r, 1); @@ -88,12 +95,14 @@ u8 sib(u32 scale, u32 index, u32 base) { } static u32 disp_mod(u32 base, i32 disp) { - if (disp == 0 && (base & 7u) != 5u) return 0u; /* [base] */ - if (disp >= -128 && disp <= 127) return 1u; /* [base + disp8] */ - return 2u; /* [base + disp32] */ + if (disp == 0 && (base & 7u) != 5u) + return 0u; /* [base] */ + if (disp >= -128 && disp <= 127) + return 1u; /* [base + disp8] */ + return 2u; /* [base + disp32] */ } -void emit_mem_operand(MCEmitter* mc, u32 reg, u32 base, i32 disp) { +void emit_mem_operand(MCEmitter *mc, u32 reg, u32 base, i32 disp) { u32 m = disp_mod(base, disp); if ((base & 7u) == 4u) { /* SIB byte required: index=4 (none), base=base. */ @@ -112,7 +121,7 @@ void emit_mem_operand(MCEmitter* mc, u32 reg, u32 base, i32 disp) { emit_u32le(mc, (u32)disp); } } -void emit_rm_reg(MCEmitter* mc, u32 reg, u32 rm) { +void emit_rm_reg(MCEmitter *mc, u32 reg, u32 rm) { u8 mr = modrm(3u, reg, rm); mc->emit_bytes(mc, &mr, 1); } @@ -120,18 +129,19 @@ void emit_rm_reg(MCEmitter* mc, u32 reg, u32 rm) { /* ---- specific instruction emitters ---- */ /* mov rd, rs (64-bit if w, else 32-bit). */ -void emit_mov_rr(MCEmitter* mc, int w, u32 dst, u32 src) { +void emit_mov_rr(MCEmitter *mc, int w, u32 dst, u32 src) { u32 ofs = obj_pos(mc->obj, mc->section_id); emit_rex(mc, w, src, 0, dst); - u8 op = 0x89; /* MOV r/m, r */ + u8 op = 0x89; /* MOV r/m, r */ mc->emit_bytes(mc, &op, 1); emit_rm_reg(mc, src, dst); - if (mc->debug) debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); + if (mc->debug) + debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); } /* mov reg, [base + disp]; size 1/2/4/8. */ -void emit_mov_load(MCEmitter* mc, u32 size, int signed_ext, u32 dst, - u32 base, i32 disp) { +void emit_mov_load(MCEmitter *mc, u32 size, int signed_ext, u32 dst, u32 base, + i32 disp) { u32 ofs = obj_pos(mc->obj, mc->section_id); if (size == 8) { emit_rex(mc, 1, dst, 0, base); @@ -154,11 +164,12 @@ void emit_mov_load(MCEmitter* mc, u32 size, int signed_ext, u32 dst, mc->emit_bytes(mc, op, 2); emit_mem_operand(mc, dst, base, disp); } - if (mc->debug) debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); + if (mc->debug) + debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); } /* mov [base + disp], src; size 1/2/4/8. */ -void emit_mov_store(MCEmitter* mc, u32 size, u32 src, u32 base, i32 disp) { +void emit_mov_store(MCEmitter *mc, u32 size, u32 src, u32 base, i32 disp) { u32 ofs = obj_pos(mc->obj, mc->section_id); if (size == 8) { emit_rex(mc, 1, src, 0, base); @@ -184,21 +195,23 @@ void emit_mov_store(MCEmitter* mc, u32 size, u32 src, u32 base, i32 disp) { mc->emit_bytes(mc, &op, 1); emit_mem_operand(mc, src, base, disp); } - if (mc->debug) debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); + if (mc->debug) + debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); } -void emit_lea(MCEmitter* mc, u32 dst, u32 base, i32 disp) { +void emit_lea(MCEmitter *mc, u32 dst, u32 base, i32 disp) { u32 ofs = obj_pos(mc->obj, mc->section_id); emit_rex(mc, 1, dst, 0, base); u8 op = 0x8D; mc->emit_bytes(mc, &op, 1); emit_mem_operand(mc, dst, base, disp); - if (mc->debug) debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); + if (mc->debug) + debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); } /* movabs reg, imm64 (REX.W + B8+r imm64) for is64; mov r32, imm32 (B8+r * imm32) for !is64. Both 10/5 bytes. */ -void x64_emit_load_imm(MCEmitter* mc, int is64, u32 dst, i64 imm) { +void x64_emit_load_imm(MCEmitter *mc, int is64, u32 dst, i64 imm) { u32 ofs = obj_pos(mc->obj, mc->section_id); if (is64) { emit_rex(mc, 1, 0, 0, dst); @@ -211,48 +224,53 @@ void x64_emit_load_imm(MCEmitter* mc, int is64, u32 dst, i64 imm) { mc->emit_bytes(mc, &op, 1); emit_u32le(mc, (u32)imm); } - if (mc->debug) debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); + if (mc->debug) + debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); } /* Two-operand ALU r/m, r. op picks ADD(01)/SUB(29)/AND(21)/OR(09)/XOR(31)/ * CMP(39)/MOV(89)/TEST(85). */ -void emit_alu_rr(MCEmitter* mc, int w, u8 op, u32 dst, u32 src) { +void emit_alu_rr(MCEmitter *mc, int w, u8 op, u32 dst, u32 src) { u32 ofs = obj_pos(mc->obj, mc->section_id); emit_rex(mc, w, src, 0, dst); mc->emit_bytes(mc, &op, 1); emit_rm_reg(mc, src, dst); - if (mc->debug) debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); + if (mc->debug) + debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); } -void emit_imul_rr(MCEmitter* mc, int w, u32 dst, u32 src) { +void emit_imul_rr(MCEmitter *mc, int w, u32 dst, u32 src) { u32 ofs = obj_pos(mc->obj, mc->section_id); emit_rex(mc, w, dst, 0, src); u8 op[2] = {0x0F, 0xAF}; mc->emit_bytes(mc, op, 2); emit_rm_reg(mc, dst, src); - if (mc->debug) debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); + if (mc->debug) + debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); } -void emit_f7_rm(MCEmitter* mc, int w, u32 sub, u32 reg) { +void emit_f7_rm(MCEmitter *mc, int w, u32 sub, u32 reg) { u32 ofs = obj_pos(mc->obj, mc->section_id); emit_rex(mc, w, 0, 0, reg); u8 op = 0xF7; mc->emit_bytes(mc, &op, 1); emit_rm_reg(mc, sub, reg); - if (mc->debug) debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); + if (mc->debug) + debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); } -void emit_shift_cl(MCEmitter* mc, int w, u32 sub, u32 reg) { +void emit_shift_cl(MCEmitter *mc, int w, u32 sub, u32 reg) { u32 ofs = obj_pos(mc->obj, mc->section_id); emit_rex(mc, w, 0, 0, reg); u8 op = 0xD3; mc->emit_bytes(mc, &op, 1); emit_rm_reg(mc, sub, reg); - if (mc->debug) debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); + if (mc->debug) + debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); } /* Shift r/m by imm8: opcode C1 /sub ib. sub: SHL=4, SHR=5, SAR=7. */ -void emit_shift_imm(MCEmitter* mc, int w, u32 sub, u32 reg, u8 imm) { +void emit_shift_imm(MCEmitter *mc, int w, u32 sub, u32 reg, u8 imm) { u32 ofs = obj_pos(mc->obj, mc->section_id); emit_rex(mc, w, 0, 0, reg); u8 buf[3]; @@ -260,10 +278,11 @@ void emit_shift_imm(MCEmitter* mc, int w, u32 sub, u32 reg, u8 imm) { buf[1] = modrm(3u, sub, reg); buf[2] = imm; mc->emit_bytes(mc, buf, 3); - if (mc->debug) debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); + if (mc->debug) + debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); } -void emit_cqo_or_cdq(MCEmitter* mc, int w) { +void emit_cqo_or_cdq(MCEmitter *mc, int w) { if (w) { u8 buf[2] = {X64_REX_BASE | X64_REX_W, 0x99}; mc->emit_bytes(mc, buf, 2); @@ -273,12 +292,12 @@ void emit_cqo_or_cdq(MCEmitter* mc, int w) { } } -void emit_xor_self(MCEmitter* mc, int w, u32 r) { +void emit_xor_self(MCEmitter *mc, int w, u32 r) { emit_alu_rr(mc, w, 0x31, r, r); } /* cmp r/m, imm8 (0x83 /7). */ -void emit_cmp_imm8(MCEmitter* mc, int w, u32 reg, i8 imm) { +void emit_cmp_imm8(MCEmitter *mc, int w, u32 reg, i8 imm) { u32 ofs = obj_pos(mc->obj, mc->section_id); emit_rex(mc, w, 0, 0, reg); u8 buf[3]; @@ -286,12 +305,13 @@ void emit_cmp_imm8(MCEmitter* mc, int w, u32 reg, i8 imm) { buf[1] = modrm(3u, 7u, reg); buf[2] = (u8)imm; mc->emit_bytes(mc, buf, 3); - if (mc->debug) debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); + if (mc->debug) + debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); } /* ALU r/m, imm8: opcode 0x83 /sub ib (sign-extended). sub: ADD=0, * OR=1, ADC=2, SBB=3, AND=4, SUB=5, XOR=6, CMP=7. */ -void emit_alu_imm8(MCEmitter* mc, int w, u32 sub, u32 reg, i8 imm) { +void emit_alu_imm8(MCEmitter *mc, int w, u32 sub, u32 reg, i8 imm) { u32 ofs = obj_pos(mc->obj, mc->section_id); emit_rex(mc, w, 0, 0, reg); u8 buf[3]; @@ -299,11 +319,12 @@ void emit_alu_imm8(MCEmitter* mc, int w, u32 sub, u32 reg, i8 imm) { buf[1] = modrm(3u, sub, reg); buf[2] = (u8)imm; mc->emit_bytes(mc, buf, 3); - if (mc->debug) debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); + if (mc->debug) + debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); } /* ALU r/m, imm32: opcode 0x81 /sub id (sign-extended for w=1). */ -void emit_alu_imm32(MCEmitter* mc, int w, u32 sub, u32 reg, i32 imm) { +void emit_alu_imm32(MCEmitter *mc, int w, u32 sub, u32 reg, i32 imm) { u32 ofs = obj_pos(mc->obj, mc->section_id); emit_rex(mc, w, 0, 0, reg); u8 buf[6]; @@ -314,14 +335,15 @@ void emit_alu_imm32(MCEmitter* mc, int w, u32 sub, u32 reg, i32 imm) { buf[4] = (u8)((imm >> 16) & 0xFF); buf[5] = (u8)((imm >> 24) & 0xFF); mc->emit_bytes(mc, buf, 6); - if (mc->debug) debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); + if (mc->debug) + debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); } /* IMUL r, r/m, imm: 0x6B /r ib (imm8 sext) or 0x69 /r id (imm32 sext). * Both forms write the result back to the same `dst` register so the * caller doesn't need an explicit copy beforehand — unlike the ALU * forms which read-modify-write a single operand. */ -void emit_imul_imm8(MCEmitter* mc, int w, u32 dst, u32 src, i8 imm) { +void emit_imul_imm8(MCEmitter *mc, int w, u32 dst, u32 src, i8 imm) { u32 ofs = obj_pos(mc->obj, mc->section_id); emit_rex(mc, w, dst, 0, src); u8 buf[3]; @@ -329,9 +351,10 @@ void emit_imul_imm8(MCEmitter* mc, int w, u32 dst, u32 src, i8 imm) { buf[1] = modrm(3u, dst, src); buf[2] = (u8)imm; mc->emit_bytes(mc, buf, 3); - if (mc->debug) debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); + if (mc->debug) + debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); } -void emit_imul_imm32(MCEmitter* mc, int w, u32 dst, u32 src, i32 imm) { +void emit_imul_imm32(MCEmitter *mc, int w, u32 dst, u32 src, i32 imm) { u32 ofs = obj_pos(mc->obj, mc->section_id); emit_rex(mc, w, dst, 0, src); u8 buf[6]; @@ -342,7 +365,8 @@ void emit_imul_imm32(MCEmitter* mc, int w, u32 dst, u32 src, i32 imm) { buf[4] = (u8)((imm >> 16) & 0xFF); buf[5] = (u8)((imm >> 24) & 0xFF); mc->emit_bytes(mc, buf, 6); - if (mc->debug) debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); + if (mc->debug) + debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); } /* Width predicate: does `imm` fit in an i8 (used by the 0x83/0x6B @@ -356,31 +380,33 @@ int imm_fits_i32(i64 imm) { return imm >= -2147483648LL && imm <= 2147483647LL; } -void emit_test_self(MCEmitter* mc, int w, u32 reg) { +void emit_test_self(MCEmitter *mc, int w, u32 reg) { emit_alu_rr(mc, w, 0x85, reg, reg); } -void emit_setcc(MCEmitter* mc, u32 cc, u32 reg) { +void emit_setcc(MCEmitter *mc, u32 cc, u32 reg) { u32 ofs = obj_pos(mc->obj, mc->section_id); emit_rex_force(mc, 0, 0, 0, reg); u8 op[2] = {0x0F, (u8)(0x90 | (cc & 0xF))}; mc->emit_bytes(mc, op, 2); emit_rm_reg(mc, 0u, reg); - if (mc->debug) debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); + if (mc->debug) + debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); } -void emit_movzx_r32_r8(MCEmitter* mc, u32 dst, u32 src) { +void emit_movzx_r32_r8(MCEmitter *mc, u32 dst, u32 src) { u32 ofs = obj_pos(mc->obj, mc->section_id); emit_rex_force(mc, 0, dst, 0, src); u8 op[2] = {0x0F, 0xB6}; mc->emit_bytes(mc, op, 2); emit_rm_reg(mc, dst, src); - if (mc->debug) debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); + if (mc->debug) + debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); } /* movzx/movsx r→r. src_size is source byte width. */ -void emit_extend_rr(MCEmitter* mc, int w, int signed_ext, u32 src_size, - u32 dst, u32 src) { +void emit_extend_rr(MCEmitter *mc, int w, int signed_ext, u32 src_size, u32 dst, + u32 src) { u32 ofs = obj_pos(mc->obj, mc->section_id); if (src_size == 4 && signed_ext) { /* movsxd r64, r32: REX.W 0x63 ModRM */ @@ -405,65 +431,74 @@ void emit_extend_rr(MCEmitter* mc, int w, int signed_ext, u32 src_size, mc->emit_bytes(mc, op, 2); emit_rm_reg(mc, dst, src); } - if (mc->debug) debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); + if (mc->debug) + debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); } -static void emit_ret(MCEmitter* mc) { +static void emit_ret(MCEmitter *mc) { u8 op = 0xC3; mc->emit_bytes(mc, &op, 1); } -static void emit_leave(MCEmitter* mc) { +static void emit_leave(MCEmitter *mc) { u8 op = 0xC9; mc->emit_bytes(mc, &op, 1); } /* ---- SSE scalar FP encoders ---- */ -void emit_sse_rr(MCEmitter* mc, u8 prefix, u8 opcode, u32 dst, u32 src) { +void emit_sse_rr(MCEmitter *mc, u8 prefix, u8 opcode, u32 dst, u32 src) { u32 ofs = obj_pos(mc->obj, mc->section_id); - if (prefix) mc->emit_bytes(mc, &prefix, 1); + if (prefix) + mc->emit_bytes(mc, &prefix, 1); emit_rex(mc, 0, dst, 0, src); u8 op[2] = {0x0F, opcode}; mc->emit_bytes(mc, op, 2); emit_rm_reg(mc, dst, src); - if (mc->debug) debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); + if (mc->debug) + debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); } -void emit_sse_load(MCEmitter* mc, u8 prefix, u8 opcode, u32 dst, - u32 base, i32 disp) { +void emit_sse_load(MCEmitter *mc, u8 prefix, u8 opcode, u32 dst, u32 base, + i32 disp) { u32 ofs = obj_pos(mc->obj, mc->section_id); - if (prefix) mc->emit_bytes(mc, &prefix, 1); + if (prefix) + mc->emit_bytes(mc, &prefix, 1); emit_rex(mc, 0, dst, 0, base); u8 op[2] = {0x0F, opcode}; mc->emit_bytes(mc, op, 2); emit_mem_operand(mc, dst, base, disp); - if (mc->debug) debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); + if (mc->debug) + debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); } -void emit_sse_store(MCEmitter* mc, u8 prefix, u8 opcode, u32 src, - u32 base, i32 disp) { +void emit_sse_store(MCEmitter *mc, u8 prefix, u8 opcode, u32 src, u32 base, + i32 disp) { u32 ofs = obj_pos(mc->obj, mc->section_id); - if (prefix) mc->emit_bytes(mc, &prefix, 1); + if (prefix) + mc->emit_bytes(mc, &prefix, 1); emit_rex(mc, 0, src, 0, base); u8 op[2] = {0x0F, opcode}; mc->emit_bytes(mc, op, 2); emit_mem_operand(mc, src, base, disp); - if (mc->debug) debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); + if (mc->debug) + debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); } -void emit_sse_rr_w(MCEmitter* mc, u8 prefix, u8 opcode, int w, u32 dst, +void emit_sse_rr_w(MCEmitter *mc, u8 prefix, u8 opcode, int w, u32 dst, u32 src) { u32 ofs = obj_pos(mc->obj, mc->section_id); - if (prefix) mc->emit_bytes(mc, &prefix, 1); + if (prefix) + mc->emit_bytes(mc, &prefix, 1); emit_rex(mc, w, dst, 0, src); u8 op[2] = {0x0F, opcode}; mc->emit_bytes(mc, op, 2); emit_rm_reg(mc, dst, src); - if (mc->debug) debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); + if (mc->debug) + debug_emit_row(mc->debug, mc->section_id, ofs, mc->loc); } /* ============================================================ * Function lifecycle */ -void x_func_begin(CGTarget* t, const CGFuncDesc* fd) { - XImpl* a = impl_of(t); - MCEmitter* mc = t->mc; +void x_func_begin(CGTarget *t, const CGFuncDesc *fd) { + XImpl *a = impl_of(t); + MCEmitter *mc = t->mc; mc->set_section(mc, fd->text_section_id); mc->emit_align(mc, 16, 0x90); @@ -491,14 +526,20 @@ void x_func_begin(CGTarget* t, const CGFuncDesc* fd) { /* Reserve a fixed-size prologue placeholder filled with NOPs. */ a->prologue_pos = mc->pos(mc); - for (u32 i = 0; i < X64_PROLOGUE_BYTES; ++i) emit1(mc, 0x90); + for (u32 i = 0; i < X64_PROLOGUE_BYTES; ++i) + emit1(mc, 0x90); /* sret: rdi at entry holds the destination pointer. Spill it to a * hidden slot so the body can use rdi freely. */ if (a->has_sret) { FrameSlotDesc fsd = { - .type = CFREE_CG_TYPE_NONE, .name = 0, .loc = {0, 0, 0}, - .size = 8, .align = 8, .kind = FS_SPILL, .flags = 0, + .type = CFREE_CG_TYPE_NONE, + .name = 0, + .loc = {0, 0, 0}, + .size = 8, + .align = 8, + .kind = FS_SPILL, + .flags = 0, }; a->sret_ptr_slot = x_frame_slot(t, &fsd); /* Subsequent int args start at rsi (next_param_int = 1). */ @@ -511,16 +552,20 @@ void x_func_begin(CGTarget* t, const CGFuncDesc* fd) { * args are preserved before x_param() spills the named ones. */ if (a->is_variadic) { FrameSlotDesc rsd = { - .type = CFREE_CG_TYPE_NONE, .name = 0, .loc = {0, 0, 0}, - .size = 176, .align = 8, .kind = FS_SPILL, .flags = 0, + .type = CFREE_CG_TYPE_NONE, + .name = 0, + .loc = {0, 0, 0}, + .size = 176, + .align = 8, + .kind = FS_SPILL, + .flags = 0, }; a->reg_save_slot = x_frame_slot(t, &rsd); - XSlot* rs = x64_slot_get(a, a->reg_save_slot); + XSlot *rs = x64_slot_get(a, a->reg_save_slot); static const u32 gprs[6] = {X64_RDI, X64_RSI, X64_RDX, X64_RCX, X64_R8, X64_R9}; for (u32 i = 0; i < 6; ++i) { - emit_mov_store(mc, 8, gprs[i], X64_RBP, - -(i32)rs->off + (i32)(i * 8u)); + emit_mov_store(mc, 8, gprs[i], X64_RBP, -(i32)rs->off + (i32)(i * 8u)); } /* movsd writes the low 8 bytes of each xmm; va_arg reads 8 bytes per * FP slot, so the upper half of the 16-byte stride stays unused. */ @@ -533,15 +578,16 @@ void x_func_begin(CGTarget* t, const CGFuncDesc* fd) { static u32 align_up_u32(u32 v, u32 a) { return (v + (a - 1u)) & ~(a - 1u); } -void x_func_end(CGTarget* t) { - XImpl* a = impl_of(t); - MCEmitter* mc = t->mc; +void x_func_end(CGTarget *t) { + XImpl *a = impl_of(t); + MCEmitter *mc = t->mc; Reg cs_regs[5]; u32 cs_used = 0; for (u32 i = 0; i < 5u; ++i) { Reg r = g_int_order[i]; - if (a->used_cs_int_mask & (1u << r)) cs_regs[cs_used++] = r; + if (a->used_cs_int_mask & (1u << r)) + cs_regs[cs_used++] = r; } u32 cs_size = cs_used * 8u; @@ -552,7 +598,8 @@ void x_func_end(CGTarget* t) { * mod 16, so frame_size must be a multiple of 16. */ u32 raw = a->max_outgoing + cs_size + a->cum_off; u32 frame_size = align_up_u32(raw, 16u); - if (frame_size == 0) frame_size = 16; + if (frame_size == 0) + frame_size = 16; mc->label_place(mc, a->epilogue_label); @@ -569,7 +616,8 @@ void x_func_end(CGTarget* t) { /* Patch prologue placeholder. */ u8 buf[X64_PROLOGUE_BYTES]; - for (u32 i = 0; i < X64_PROLOGUE_BYTES; ++i) buf[i] = 0x90; + for (u32 i = 0; i < X64_PROLOGUE_BYTES; ++i) + buf[i] = 0x90; u32 wi = 0; /* push rbp (1 byte). */ @@ -589,10 +637,11 @@ void x_func_end(CGTarget* t) { /* sret: mov [rbp + disp32], rdi. */ if (a->has_sret && a->sret_ptr_slot != FRAME_SLOT_NONE) { - XSlot* s = x64_slot_get(a, a->sret_ptr_slot); + XSlot *s = x64_slot_get(a, a->sret_ptr_slot); if (s) { i32 off = -(i32)s->off; - if (wi + 7 > X64_PROLOGUE_BYTES) goto overflow; + if (wi + 7 > X64_PROLOGUE_BYTES) + goto overflow; buf[wi++] = X64_REX_BASE | X64_REX_W; buf[wi++] = 0x89; buf[wi++] = modrm(2u, X64_RDI, X64_RBP); @@ -607,7 +656,8 @@ void x_func_end(CGTarget* t) { for (u32 i = 0; i < cs_used; ++i) { u32 reg = cs_regs[i]; i32 off = -(i32)a->cum_off - (i32)(i + 1) * 8; - if (wi + 7 > X64_PROLOGUE_BYTES) goto overflow; + if (wi + 7 > X64_PROLOGUE_BYTES) + goto overflow; buf[wi++] = (u8)(X64_REX_BASE | X64_REX_W | ((reg & 8) ? X64_REX_R : 0)); buf[wi++] = 0x89; buf[wi++] = modrm(2u, (reg & 7u), X64_RBP); @@ -636,14 +686,16 @@ void x_func_end(CGTarget* t) { dbuf[1] = (u8)(m >> 8); dbuf[2] = (u8)(m >> 16); dbuf[3] = (u8)(m >> 24); - obj_patch(t->obj, a->fd->text_section_id, - a->alloca_patches[i].disp_pos, dbuf, 4); + obj_patch(t->obj, a->fd->text_section_id, a->alloca_patches[i].disp_pos, + dbuf, 4); } /* Define the function symbol. */ u32 end = mc->pos(mc); obj_symbol_define(t->obj, a->fd->sym, a->fd->text_section_id, (u64)a->func_start, (u64)(end - a->func_start)); + if (t->debug) + debug_func_pc_range(t->debug, a->fd->text_section_id, a->func_start, end); mc->cfi_endproc(mc); a->fd = NULL; diff --git a/src/arch/x64/internal.h b/src/arch/x64/internal.h @@ -13,8 +13,8 @@ #include <string.h> #include "arch/arch.h" -#include "arch/x64/x64.h" #include "arch/x64/isa.h" +#include "arch/x64/x64.h" #include "core/arena.h" #include "core/pool.h" #include "obj/obj.h" @@ -25,7 +25,7 @@ * XImpl and friends. */ typedef struct XSlot { - u32 off; /* bytes below rbp (positive); address = rbp - off */ + u32 off; /* bytes below rbp (positive); address = rbp - off */ u32 size; u32 align; u8 kind; @@ -52,13 +52,13 @@ typedef struct XAllocaPatch { typedef struct XImpl { CGTarget base; SrcLoc loc; - const CGFuncDesc* fd; + const CGFuncDesc *fd; u32 func_start; u32 prologue_pos; MCLabel epilogue_label; - XSlot* slots; + XSlot *slots; u32 nslots; u32 slots_cap; u32 cum_off; @@ -77,18 +77,20 @@ typedef struct XImpl { u32 used_cs_int_mask; /* SysV callee-saved GPRs used by this function */ u32 used_cs_fp_mask; /* reserved for ABIs with callee-saved FP regs */ - XScope* scopes; + XScope *scopes; u32 nscopes; u32 scopes_cap; - XAllocaPatch* alloca_patches; + XAllocaPatch *alloca_patches; u32 nalloca_patches; u32 alloca_patches_cap; } XImpl; -static inline XImpl* impl_of(CGTarget* t) { return (XImpl*)t; } +static inline XImpl *impl_of(CGTarget *t) { return (XImpl *)t; } -extern void debug_emit_row(Debug*, ObjSecId text_section, u32 offset, SrcLoc); +extern void debug_emit_row(Debug *, ObjSecId text_section, u32 offset, SrcLoc); +extern void debug_func_pc_range(Debug *, ObjSecId text_section, u32 begin_ofs, + u32 end_ofs); /* ============================================================ * Type helpers (static inline — used in all three translation units). */ @@ -106,7 +108,8 @@ static inline u32 type_byte_size(CfreeCgTypeId t) { if (t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_I8) || t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_BOOL)) return 1; - if (t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_I16)) return 2; + if (t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_I16)) + return 2; if (t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_I32) || t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_F32)) return 4; @@ -117,7 +120,7 @@ static inline int type_is_signed(CfreeCgTypeId t) { return 0; } -static inline _Noreturn void x_panic(CGTarget* t, const char* what) { +static inline _Noreturn void x_panic(CGTarget *t, const char *what) { SrcLoc loc = impl_of(t)->loc; compiler_panic(t->c, loc, "x64: %s not implemented", what); } @@ -137,72 +140,72 @@ extern const u32 g_int_arg_regs[6]; /* --- emit.c exports (lifecycle used by ops.c vtable constructor, * encoding helpers used by alloc.c and ops.c) --- */ -void x_func_begin(CGTarget* t, const CGFuncDesc* fd); -void x_func_end(CGTarget* t); +void x_func_begin(CGTarget *t, const CGFuncDesc *fd); +void x_func_end(CGTarget *t); -void x_coord_vtable_init(CGTarget* t); +void x_coord_vtable_init(CGTarget *t); /* encoding helpers */ -void emit_u32le(MCEmitter* mc, u32 v); -void emit_rex(MCEmitter* mc, int w, u32 reg, u32 index, u32 rm); -void emit_rex_force(MCEmitter* mc, int w, u32 reg, u32 index, u32 rm); +void emit_u32le(MCEmitter *mc, u32 v); +void emit_rex(MCEmitter *mc, int w, u32 reg, u32 index, u32 rm); +void emit_rex_force(MCEmitter *mc, int w, u32 reg, u32 index, u32 rm); u8 modrm(u32 mod, u32 reg, u32 rm); u8 sib(u32 scale, u32 index, u32 base); -void emit_mem_operand(MCEmitter* mc, u32 reg, u32 base, i32 disp); -void emit_rm_reg(MCEmitter* mc, u32 reg, u32 rm); -void emit_mov_rr(MCEmitter* mc, int w, u32 dst, u32 src); -void emit_mov_load(MCEmitter* mc, u32 size, int signed_ext, u32 dst, u32 base, +void emit_mem_operand(MCEmitter *mc, u32 reg, u32 base, i32 disp); +void emit_rm_reg(MCEmitter *mc, u32 reg, u32 rm); +void emit_mov_rr(MCEmitter *mc, int w, u32 dst, u32 src); +void emit_mov_load(MCEmitter *mc, u32 size, int signed_ext, u32 dst, u32 base, i32 disp); -void emit_mov_store(MCEmitter* mc, u32 size, u32 src, u32 base, i32 disp); -void emit_lea(MCEmitter* mc, u32 dst, u32 base, i32 disp); -void x64_emit_load_imm(MCEmitter* mc, int is64, u32 dst, i64 imm); -void emit_alu_rr(MCEmitter* mc, int w, u8 op, u32 dst, u32 src); -void emit_imul_rr(MCEmitter* mc, int w, u32 dst, u32 src); -void emit_f7_rm(MCEmitter* mc, int w, u32 sub, u32 reg); -void emit_shift_cl(MCEmitter* mc, int w, u32 sub, u32 reg); -void emit_shift_imm(MCEmitter* mc, int w, u32 sub, u32 reg, u8 imm); -void emit_cqo_or_cdq(MCEmitter* mc, int w); -void emit_xor_self(MCEmitter* mc, int w, u32 r); -void emit_cmp_imm8(MCEmitter* mc, int w, u32 reg, i8 imm); -void emit_alu_imm8(MCEmitter* mc, int w, u32 sub, u32 reg, i8 imm); -void emit_alu_imm32(MCEmitter* mc, int w, u32 sub, u32 reg, i32 imm); -void emit_imul_imm8(MCEmitter* mc, int w, u32 dst, u32 src, i8 imm); -void emit_imul_imm32(MCEmitter* mc, int w, u32 dst, u32 src, i32 imm); +void emit_mov_store(MCEmitter *mc, u32 size, u32 src, u32 base, i32 disp); +void emit_lea(MCEmitter *mc, u32 dst, u32 base, i32 disp); +void x64_emit_load_imm(MCEmitter *mc, int is64, u32 dst, i64 imm); +void emit_alu_rr(MCEmitter *mc, int w, u8 op, u32 dst, u32 src); +void emit_imul_rr(MCEmitter *mc, int w, u32 dst, u32 src); +void emit_f7_rm(MCEmitter *mc, int w, u32 sub, u32 reg); +void emit_shift_cl(MCEmitter *mc, int w, u32 sub, u32 reg); +void emit_shift_imm(MCEmitter *mc, int w, u32 sub, u32 reg, u8 imm); +void emit_cqo_or_cdq(MCEmitter *mc, int w); +void emit_xor_self(MCEmitter *mc, int w, u32 r); +void emit_cmp_imm8(MCEmitter *mc, int w, u32 reg, i8 imm); +void emit_alu_imm8(MCEmitter *mc, int w, u32 sub, u32 reg, i8 imm); +void emit_alu_imm32(MCEmitter *mc, int w, u32 sub, u32 reg, i32 imm); +void emit_imul_imm8(MCEmitter *mc, int w, u32 dst, u32 src, i8 imm); +void emit_imul_imm32(MCEmitter *mc, int w, u32 dst, u32 src, i32 imm); int imm_fits_i8(i64 imm); int imm_fits_i32(i64 imm); -void emit_test_self(MCEmitter* mc, int w, u32 reg); -void emit_setcc(MCEmitter* mc, u32 cc, u32 reg); -void emit_movzx_r32_r8(MCEmitter* mc, u32 dst, u32 src); -void emit_extend_rr(MCEmitter* mc, int w, int signed_ext, u32 src_size, - u32 dst, u32 src); -void emit_sse_rr(MCEmitter* mc, u8 prefix, u8 opcode, u32 dst, u32 src); -void emit_sse_load(MCEmitter* mc, u8 prefix, u8 opcode, u32 dst, u32 base, +void emit_test_self(MCEmitter *mc, int w, u32 reg); +void emit_setcc(MCEmitter *mc, u32 cc, u32 reg); +void emit_movzx_r32_r8(MCEmitter *mc, u32 dst, u32 src); +void emit_extend_rr(MCEmitter *mc, int w, int signed_ext, u32 src_size, u32 dst, + u32 src); +void emit_sse_rr(MCEmitter *mc, u8 prefix, u8 opcode, u32 dst, u32 src); +void emit_sse_load(MCEmitter *mc, u8 prefix, u8 opcode, u32 dst, u32 base, i32 disp); -void emit_sse_store(MCEmitter* mc, u8 prefix, u8 opcode, u32 src, u32 base, +void emit_sse_store(MCEmitter *mc, u8 prefix, u8 opcode, u32 src, u32 base, i32 disp); -void emit_sse_rr_w(MCEmitter* mc, u8 prefix, u8 opcode, int w, u32 dst, +void emit_sse_rr_w(MCEmitter *mc, u8 prefix, u8 opcode, int w, u32 dst, u32 src); /* --- alloc.c exports (used by emit.c and/or ops.c) --- */ -XSlot* x64_slot_get(XImpl* a, FrameSlot fs); -FrameSlot x_frame_slot(CGTarget* t, const FrameSlotDesc* d); -void x_param(CGTarget* t, const CGParamDesc* p); -void x_spill_reg(CGTarget* t, Operand src, FrameSlot slot, MemAccess ma); -void x_reload_reg(CGTarget* t, Operand dst, FrameSlot slot, MemAccess ma); -Label x_label_new(CGTarget* t); -void x_label_place(CGTarget* t, Label l); -void emit_jmp_label(MCEmitter* mc, MCLabel l); -void emit_jcc_label(MCEmitter* mc, u32 cc, MCLabel l); -void x_jump(CGTarget* t, Label l); -void x_cmp_branch(CGTarget* t, CmpOp op, Operand a, Operand b, Label l); -void x_cmp(CGTarget* t, CmpOp op, Operand dst, Operand a, Operand b); -CGScope x_scope_begin(CGTarget* t, const CGScopeDesc* d); -void x_scope_else(CGTarget* t, CGScope s); -void x_scope_end(CGTarget* t, CGScope s); -void x_break_to(CGTarget* t, CGScope s); -void x_continue_to(CGTarget* t, CGScope s); -u32 x64_force_reg_int(CGTarget* t, Operand op, int w, u32 scratch); +XSlot *x64_slot_get(XImpl *a, FrameSlot fs); +FrameSlot x_frame_slot(CGTarget *t, const FrameSlotDesc *d); +void x_param(CGTarget *t, const CGParamDesc *p); +void x_spill_reg(CGTarget *t, Operand src, FrameSlot slot, MemAccess ma); +void x_reload_reg(CGTarget *t, Operand dst, FrameSlot slot, MemAccess ma); +Label x_label_new(CGTarget *t); +void x_label_place(CGTarget *t, Label l); +void emit_jmp_label(MCEmitter *mc, MCLabel l); +void emit_jcc_label(MCEmitter *mc, u32 cc, MCLabel l); +void x_jump(CGTarget *t, Label l); +void x_cmp_branch(CGTarget *t, CmpOp op, Operand a, Operand b, Label l); +void x_cmp(CGTarget *t, CmpOp op, Operand dst, Operand a, Operand b); +CGScope x_scope_begin(CGTarget *t, const CGScopeDesc *d); +void x_scope_else(CGTarget *t, CGScope s); +void x_scope_end(CGTarget *t, CGScope s); +void x_break_to(CGTarget *t, CGScope s); +void x_continue_to(CGTarget *t, CGScope s); +u32 x64_force_reg_int(CGTarget *t, Operand op, int w, u32 scratch); /* --- ops.c exports (used by alloc.c) --- */ -void x_load(CGTarget* t, Operand dst, Operand addr, MemAccess ma); -void x_store(CGTarget* t, Operand addr, Operand src, MemAccess ma); +void x_load(CGTarget *t, Operand dst, Operand addr, MemAccess ma); +void x_store(CGTarget *t, Operand addr, Operand src, MemAccess ma); diff --git a/src/debug/debug_emit.c b/src/debug/debug_emit.c @@ -23,7 +23,7 @@ #include "core/vec.h" #include "debug/debug_internal.h" -void abbrev_fini_heap(DebugAbbrevPool* p, Heap* h); +void abbrev_fini_heap(DebugAbbrevPool *p, Heap *h); /* ---------------------------------------------------------------- */ /* String tables. */ @@ -32,12 +32,12 @@ typedef struct StrTab { Buf buf; SymToU32 by_sym; /* Sym → byte offset within buf */ /* Insertion order — used to populate .debug_str_offsets. */ - Sym* syms; + Sym *syms; u32 nsyms; u32 syms_cap; } StrTab; -static void str_init(StrTab* s, Heap* h) { +static void str_init(StrTab *s, Heap *h) { buf_init(&s->buf, h); SymToU32_init(&s->by_sym, h); s->syms = NULL; @@ -45,40 +45,46 @@ static void str_init(StrTab* s, Heap* h) { s->syms_cap = 0; } -static void str_fini(StrTab* s, Heap* h) { +static void str_fini(StrTab *s, Heap *h) { buf_fini(&s->buf); SymToU32_fini(&s->by_sym); - if (s->syms) h->free(h, s->syms, sizeof(Sym) * s->syms_cap); + if (s->syms) + h->free(h, s->syms, sizeof(Sym) * s->syms_cap); s->syms = NULL; s->nsyms = 0; s->syms_cap = 0; } -static u32 str_intern(StrTab* s, Heap* h, Pool* pool, Sym sym) { - u32* found; +static u32 str_intern(StrTab *s, Heap *h, Pool *pool, Sym sym) { + u32 *found; u32 ofs; size_t len; - const char* str; - if (sym == 0) sym = pool_intern_cstr(pool, ""); + const char *str; + if (sym == 0) + sym = pool_intern_cstr(pool, ""); found = SymToU32_get(&s->by_sym, sym); - if (found) return *found; + if (found) + return *found; ofs = buf_pos(&s->buf); str = pool_str(pool, sym, &len); - if (str && len) buf_write(&s->buf, str, len); + if (str && len) + buf_write(&s->buf, str, len); { u8 nul = 0; buf_write(&s->buf, &nul, 1); } SymToU32_set(&s->by_sym, sym, ofs); - if (VEC_GROW(h, s->syms, s->syms_cap, s->nsyms + 1)) return ofs; + if (VEC_GROW(h, s->syms, s->syms_cap, s->nsyms + 1)) + return ofs; s->syms[s->nsyms++] = sym; return ofs; } -static u32 str_index_of(StrTab* s, Sym sym) { +static u32 str_index_of(StrTab *s, Sym sym) { u32 i; for (i = 0; i < s->nsyms; ++i) { - if (s->syms[i] == sym) return i; + if (s->syms[i] == sym) + return i; } return 0; } @@ -98,10 +104,10 @@ typedef struct AddrReloc { } AddrReloc; typedef struct EmitCtx { - Debug* d; - Heap* heap; - Pool* pool; - ObjBuilder* ob; + Debug *d; + Heap *heap; + Pool *pool; + ObjBuilder *ob; StrTab str; /* .debug_str */ StrTab line_str; /* .debug_line_str */ @@ -135,27 +141,27 @@ typedef struct EmitCtx { Buf info_body; /* Forward type-ref fixups (info_body-relative). */ - DieFixup* fixups; + DieFixup *fixups; u32 nfixups; u32 fixups_cap; /* low_pc relocs in .debug_info (info_body-relative offset). */ - AddrReloc* info_relocs; + AddrReloc *info_relocs; u32 ninfo_relocs; u32 info_relocs_cap; /* line-program address relocs (.debug_line offset within program region). */ - AddrReloc* line_relocs; + AddrReloc *line_relocs; u32 nline_relocs; u32 line_relocs_cap; /* aranges relocs (section-relative once we know offsets). */ - AddrReloc* aranges_relocs; + AddrReloc *aranges_relocs; u32 naranges_relocs; u32 aranges_relocs_cap; /* rnglists relocs. */ - AddrReloc* rng_relocs; + AddrReloc *rng_relocs; u32 nrng_relocs; u32 nrng_relocs_cap; @@ -199,16 +205,17 @@ typedef struct EmitCtx { /* ---------------------------------------------------------------- */ -static void add_fixup(EmitCtx* e, u32 buf_offset, DebugTypeId target) { - DieFixup* fx; - if (VEC_GROW(e->heap, e->fixups, e->fixups_cap, e->nfixups + 1)) return; +static void add_fixup(EmitCtx *e, u32 buf_offset, DebugTypeId target) { + DieFixup *fx; + if (VEC_GROW(e->heap, e->fixups, e->fixups_cap, e->nfixups + 1)) + return; fx = &e->fixups[e->nfixups++]; fx->buf_offset = buf_offset; fx->target = target; } -static void add_info_reloc(EmitCtx* e, u32 buf_offset, ObjSymId sym) { - AddrReloc* r; +static void add_info_reloc(EmitCtx *e, u32 buf_offset, ObjSymId sym) { + AddrReloc *r; if (VEC_GROW(e->heap, e->info_relocs, e->info_relocs_cap, e->ninfo_relocs + 1)) return; @@ -218,8 +225,8 @@ static void add_info_reloc(EmitCtx* e, u32 buf_offset, ObjSymId sym) { r->section = OBJ_SEC_NONE; } -static void add_line_reloc(EmitCtx* e, u32 buf_offset, ObjSymId sym) { - AddrReloc* r; +static void add_line_reloc(EmitCtx *e, u32 buf_offset, ObjSymId sym) { + AddrReloc *r; if (VEC_GROW(e->heap, e->line_relocs, e->line_relocs_cap, e->nline_relocs + 1)) return; @@ -229,8 +236,8 @@ static void add_line_reloc(EmitCtx* e, u32 buf_offset, ObjSymId sym) { r->section = OBJ_SEC_NONE; } -static void add_aranges_reloc(EmitCtx* e, u32 buf_offset, ObjSymId sym) { - AddrReloc* r; +static void add_aranges_reloc(EmitCtx *e, u32 buf_offset, ObjSymId sym) { + AddrReloc *r; if (VEC_GROW(e->heap, e->aranges_relocs, e->aranges_relocs_cap, e->naranges_relocs + 1)) return; @@ -240,8 +247,8 @@ static void add_aranges_reloc(EmitCtx* e, u32 buf_offset, ObjSymId sym) { r->section = OBJ_SEC_NONE; } -static void add_rng_reloc(EmitCtx* e, u32 buf_offset, ObjSymId sym) { - AddrReloc* r; +static void add_rng_reloc(EmitCtx *e, u32 buf_offset, ObjSymId sym) { + AddrReloc *r; if (VEC_GROW(e->heap, e->rng_relocs, e->nrng_relocs_cap, e->nrng_relocs + 1)) return; r = &e->rng_relocs[e->nrng_relocs++]; @@ -253,7 +260,7 @@ static void add_rng_reloc(EmitCtx* e, u32 buf_offset, ObjSymId sym) { /* ---------------------------------------------------------------- */ /* String emit shortcuts. */ -static void emit_strx4(EmitCtx* e, Buf* b, Sym name) { +static void emit_strx4(EmitCtx *e, Buf *b, Sym name) { str_intern(&e->str, e->heap, e->pool, name); { Sym key = name ? name : pool_intern_cstr(e->pool, ""); @@ -262,19 +269,19 @@ static void emit_strx4(EmitCtx* e, Buf* b, Sym name) { } } -static u32 line_str_offset(EmitCtx* e, Sym sym) { +static u32 line_str_offset(EmitCtx *e, Sym sym) { return str_intern(&e->line_str, e->heap, e->pool, sym); } /* ---------------------------------------------------------------- */ /* Abbrev resolution. */ -static u32 abbr_intern(EmitCtx* e, u16 tag, u8 has_children, - const DebugAbbrevAttr* attrs, u32 nattrs) { +static u32 abbr_intern(EmitCtx *e, u16 tag, u8 has_children, + const DebugAbbrevAttr *attrs, u32 nattrs) { return abbrev_intern(&e->abbr, e->heap, tag, has_children, attrs, nattrs); } -static void resolve_abbrevs(EmitCtx* e) { +static void resolve_abbrevs(EmitCtx *e) { /* Order of intern == order of code assignment. */ { DebugAbbrevAttr a[] = { @@ -404,9 +411,9 @@ static void resolve_abbrevs(EmitCtx* e) { /* ---------------------------------------------------------------- */ /* Per-type DIE emission. */ -static void emit_type_die(EmitCtx* e, DebugTypeId id); +static void emit_type_die(EmitCtx *e, DebugTypeId id); -static void emit_type_ref(EmitCtx* e, DebugTypeId tid) { +static void emit_type_ref(EmitCtx *e, DebugTypeId tid) { u32 ofs = buf_pos(&e->info_body); u32 placeholder = 0; buf_write(&e->info_body, &placeholder, 4); @@ -417,192 +424,195 @@ static void emit_type_ref(EmitCtx* e, DebugTypeId tid) { static u8 base_enc(DebugBaseEncoding enc) { switch (enc) { - case DEBUG_BE_BOOL: - return DW_ATE_boolean; - case DEBUG_BE_SIGNED: - return DW_ATE_signed; - case DEBUG_BE_UNSIGNED: - return DW_ATE_unsigned; - case DEBUG_BE_SIGNED_CHAR: - return DW_ATE_signed_char; - case DEBUG_BE_UNSIGNED_CHAR: - return DW_ATE_unsigned_char; - case DEBUG_BE_FLOAT: - return DW_ATE_float; - case DEBUG_BE_UTF: - return DW_ATE_UTF; - case DEBUG_BE_ADDRESS: - return DW_ATE_address; + case DEBUG_BE_BOOL: + return DW_ATE_boolean; + case DEBUG_BE_SIGNED: + return DW_ATE_signed; + case DEBUG_BE_UNSIGNED: + return DW_ATE_unsigned; + case DEBUG_BE_SIGNED_CHAR: + return DW_ATE_signed_char; + case DEBUG_BE_UNSIGNED_CHAR: + return DW_ATE_unsigned_char; + case DEBUG_BE_FLOAT: + return DW_ATE_float; + case DEBUG_BE_UTF: + return DW_ATE_UTF; + case DEBUG_BE_ADDRESS: + return DW_ATE_address; } return DW_ATE_signed; } -static void emit_type_die(EmitCtx* e, DebugTypeId id) { - DebugType* t; - Debug* d = e->d; - if (id == DEBUG_TYPE_NONE || id > d->ntypes) return; +static void emit_type_die(EmitCtx *e, DebugTypeId id) { + DebugType *t; + Debug *d = e->d; + if (id == DEBUG_TYPE_NONE || id > d->ntypes) + return; t = &d->types[id - 1]; - if (t->die_offset != 0) return; + if (t->die_offset != 0) + return; switch ((DebugTypeKind)t->kind) { - case DTK_VOID: - /* No DIE — t->die_offset stays 0; refs will encode as 0 (consumer - * interprets as void). */ - return; - case DTK_BASE: - t->die_offset = buf_pos(&e->info_body); - form_uleb(&e->info_body, e->abbr_base); - emit_strx4(e, &e->info_body, t->name); - form_u8(&e->info_body, base_enc((DebugBaseEncoding)t->base_encoding)); - form_u8(&e->info_body, (u8)t->byte_size); - return; - case DTK_PTR: - t->die_offset = buf_pos(&e->info_body); - form_uleb(&e->info_body, e->abbr_ptr); - form_u8(&e->info_body, (u8)t->byte_size); - emit_type_ref(e, t->inner); - return; - case DTK_TYPEDEF: - t->die_offset = buf_pos(&e->info_body); - form_uleb(&e->info_body, e->abbr_typedef); - emit_strx4(e, &e->info_body, t->name); - emit_type_ref(e, t->inner); - return; - case DTK_CONST: - t->die_offset = buf_pos(&e->info_body); - form_uleb(&e->info_body, e->abbr_qual_const); - emit_type_ref(e, t->inner); - return; - case DTK_VOLATILE: - t->die_offset = buf_pos(&e->info_body); - form_uleb(&e->info_body, e->abbr_qual_volatile); - emit_type_ref(e, t->inner); - return; - case DTK_RESTRICT: - t->die_offset = buf_pos(&e->info_body); - form_uleb(&e->info_body, e->abbr_qual_restrict); - emit_type_ref(e, t->inner); - return; - case DTK_ARRAY: - t->die_offset = buf_pos(&e->info_body); - form_uleb(&e->info_body, e->abbr_array); - emit_type_ref(e, t->inner); - if (t->array_count) { - form_uleb(&e->info_body, e->abbr_array_subrange); - form_uleb(&e->info_body, t->array_count); - } else { - form_uleb(&e->info_body, e->abbr_array_subrange_unbounded); - } - form_uleb(&e->info_body, 0); - return; - case DTK_FUNC: { - u32 i; - t->die_offset = buf_pos(&e->info_body); - form_uleb(&e->info_body, e->abbr_func_type); - emit_type_ref(e, t->inner); - /* DW_AT_prototyped flag_present has no body */ - for (i = 0; i < t->nparams; ++i) { - form_uleb(&e->info_body, e->abbr_func_type_param); - emit_type_ref(e, t->params[i]); - } - form_uleb(&e->info_body, 0); - return; + case DTK_VOID: + /* No DIE — t->die_offset stays 0; refs will encode as 0 (consumer + * interprets as void). */ + return; + case DTK_BASE: + t->die_offset = buf_pos(&e->info_body); + form_uleb(&e->info_body, e->abbr_base); + emit_strx4(e, &e->info_body, t->name); + form_u8(&e->info_body, base_enc((DebugBaseEncoding)t->base_encoding)); + form_u8(&e->info_body, (u8)t->byte_size); + return; + case DTK_PTR: + t->die_offset = buf_pos(&e->info_body); + form_uleb(&e->info_body, e->abbr_ptr); + form_u8(&e->info_body, (u8)t->byte_size); + emit_type_ref(e, t->inner); + return; + case DTK_TYPEDEF: + t->die_offset = buf_pos(&e->info_body); + form_uleb(&e->info_body, e->abbr_typedef); + emit_strx4(e, &e->info_body, t->name); + emit_type_ref(e, t->inner); + return; + case DTK_CONST: + t->die_offset = buf_pos(&e->info_body); + form_uleb(&e->info_body, e->abbr_qual_const); + emit_type_ref(e, t->inner); + return; + case DTK_VOLATILE: + t->die_offset = buf_pos(&e->info_body); + form_uleb(&e->info_body, e->abbr_qual_volatile); + emit_type_ref(e, t->inner); + return; + case DTK_RESTRICT: + t->die_offset = buf_pos(&e->info_body); + form_uleb(&e->info_body, e->abbr_qual_restrict); + emit_type_ref(e, t->inner); + return; + case DTK_ARRAY: + t->die_offset = buf_pos(&e->info_body); + form_uleb(&e->info_body, e->abbr_array); + emit_type_ref(e, t->inner); + if (t->array_count) { + form_uleb(&e->info_body, e->abbr_array_subrange); + form_uleb(&e->info_body, t->array_count); + } else { + form_uleb(&e->info_body, e->abbr_array_subrange_unbounded); } - case DTK_RECORD: { - u32 i; - t->die_offset = buf_pos(&e->info_body); - form_uleb(&e->info_body, t->is_union ? e->abbr_union : e->abbr_struct); - emit_strx4(e, &e->info_body, t->name); - form_uleb(&e->info_body, t->byte_size); - for (i = 0; i < t->nfields; ++i) { - DebugRecField* f = &t->fields[i]; - form_uleb(&e->info_body, e->abbr_member); - emit_strx4(e, &e->info_body, f->name); - emit_type_ref(e, f->type); - form_uleb(&e->info_body, f->byte_offset); - } - form_uleb(&e->info_body, 0); - return; + form_uleb(&e->info_body, 0); + return; + case DTK_FUNC: { + u32 i; + t->die_offset = buf_pos(&e->info_body); + form_uleb(&e->info_body, e->abbr_func_type); + emit_type_ref(e, t->inner); + /* DW_AT_prototyped flag_present has no body */ + for (i = 0; i < t->nparams; ++i) { + form_uleb(&e->info_body, e->abbr_func_type_param); + emit_type_ref(e, t->params[i]); } - case DTK_ENUM: { - u32 i; - DebugType* base; - t->die_offset = buf_pos(&e->info_body); - form_uleb(&e->info_body, e->abbr_enum); - emit_strx4(e, &e->info_body, t->name); - emit_type_ref(e, t->inner); - base = (t->inner != DEBUG_TYPE_NONE && t->inner <= e->d->ntypes) - ? &e->d->types[t->inner - 1] - : NULL; - form_uleb(&e->info_body, base ? base->byte_size : 4); - for (i = 0; i < t->nenums; ++i) { - form_uleb(&e->info_body, e->abbr_enum_val); - emit_strx4(e, &e->info_body, t->enum_vals[i].name); - form_sleb(&e->info_body, t->enum_vals[i].value); - } - form_uleb(&e->info_body, 0); - return; + form_uleb(&e->info_body, 0); + return; + } + case DTK_RECORD: { + u32 i; + t->die_offset = buf_pos(&e->info_body); + form_uleb(&e->info_body, t->is_union ? e->abbr_union : e->abbr_struct); + emit_strx4(e, &e->info_body, t->name); + form_uleb(&e->info_body, t->byte_size); + for (i = 0; i < t->nfields; ++i) { + DebugRecField *f = &t->fields[i]; + form_uleb(&e->info_body, e->abbr_member); + emit_strx4(e, &e->info_body, f->name); + emit_type_ref(e, f->type); + form_uleb(&e->info_body, f->byte_offset); + } + form_uleb(&e->info_body, 0); + return; + } + case DTK_ENUM: { + u32 i; + DebugType *base; + t->die_offset = buf_pos(&e->info_body); + form_uleb(&e->info_body, e->abbr_enum); + emit_strx4(e, &e->info_body, t->name); + emit_type_ref(e, t->inner); + base = (t->inner != DEBUG_TYPE_NONE && t->inner <= e->d->ntypes) + ? &e->d->types[t->inner - 1] + : NULL; + form_uleb(&e->info_body, base ? base->byte_size : 4); + for (i = 0; i < t->nenums; ++i) { + form_uleb(&e->info_body, e->abbr_enum_val); + emit_strx4(e, &e->info_body, t->enum_vals[i].name); + form_sleb(&e->info_body, t->enum_vals[i].value); } + form_uleb(&e->info_body, 0); + return; + } } } /* ---------------------------------------------------------------- */ /* Variable / scope emission. */ -static void emit_var_loc_exprloc(EmitCtx* e, Buf* b, DebugVarLoc loc) { +static void emit_var_loc_exprloc(EmitCtx *e, Buf *b, DebugVarLoc loc) { u8 expr[32]; u32 n = 0; switch ((DebugVarLocKind)loc.kind) { - case DVL_REG: - if (loc.v.reg < 32) { - expr[n++] = (u8)(DW_OP_reg0 + loc.v.reg); - } else { - u64 v = loc.v.reg; - expr[n++] = DW_OP_regx; - while (v >= 0x80) { - expr[n++] = (u8)((v & 0x7f) | 0x80); - v >>= 7; - } - expr[n++] = (u8)v; - } - break; - case DVL_FRAME: { - i64 v = loc.v.frame_ofs; - int more = 1; - expr[n++] = DW_OP_fbreg; - while (more) { - u8 byte = (u8)(v & 0x7f); + case DVL_REG: + if (loc.v.reg < 32) { + expr[n++] = (u8)(DW_OP_reg0 + loc.v.reg); + } else { + u64 v = loc.v.reg; + expr[n++] = DW_OP_regx; + while (v >= 0x80) { + expr[n++] = (u8)((v & 0x7f) | 0x80); v >>= 7; - if ((v == 0 && (byte & 0x40) == 0) || (v == -1 && (byte & 0x40) != 0)) { - more = 0; - } else { - byte |= 0x80; - } - expr[n++] = byte; } - break; + expr[n++] = (u8)v; } - case DVL_GLOBAL: { - /* DW_OP_addr <ptr_size>: relocation against the symbol. We can't - * place a section reloc inside an exprloc body without computing - * its absolute info-section offset post-emit. For Phase 1 we emit - * the literal symbol value as zero and trust that DVL_GLOBAL is - * not yet exercised by any harness case. Documented in the - * agent report as a Phase-1 limitation. */ - u32 i; - expr[n++] = DW_OP_addr; - for (i = 0; i < e->d->c->target.ptr_size; ++i) expr[n++] = 0; - (void)loc.v.global; - break; + break; + case DVL_FRAME: { + i64 v = loc.v.frame_ofs; + int more = 1; + expr[n++] = DW_OP_fbreg; + while (more) { + u8 byte = (u8)(v & 0x7f); + v >>= 7; + if ((v == 0 && (byte & 0x40) == 0) || (v == -1 && (byte & 0x40) != 0)) { + more = 0; + } else { + byte |= 0x80; + } + expr[n++] = byte; } - case DVL_LOCLIST: - /* Phase 5: emit as DW_FORM_loclistx. Phase 1: empty expr. */ - break; + break; + } + case DVL_GLOBAL: { + /* DW_OP_addr <ptr_size>: relocation against the symbol. We can't + * place a section reloc inside an exprloc body without computing + * its absolute info-section offset post-emit. For Phase 1 we emit + * the literal symbol value as zero and trust that DVL_GLOBAL is + * not yet exercised by any harness case. Documented in the + * agent report as a Phase-1 limitation. */ + u32 i; + expr[n++] = DW_OP_addr; + for (i = 0; i < e->d->c->target.ptr_size; ++i) + expr[n++] = 0; + (void)loc.v.global; + break; + } + case DVL_LOCLIST: + /* Phase 5: emit as DW_FORM_loclistx. Phase 1: empty expr. */ + break; } form_uleb(b, n); buf_write(b, expr, n); } -static void emit_var_die(EmitCtx* e, DebugVarDIE* v) { +static void emit_var_die(EmitCtx *e, DebugVarDIE *v) { u32 abbrev = v->is_param ? e->abbr_param : e->abbr_var; v->die_offset = buf_pos(&e->info_body); form_uleb(&e->info_body, abbrev); @@ -613,14 +623,16 @@ static void emit_var_die(EmitCtx* e, DebugVarDIE* v) { emit_var_loc_exprloc(e, &e->info_body, v->loc); } -static void emit_scope_subtree(EmitCtx* e, DebugFunc* f, i32 scope_idx); +static void emit_scope_subtree(EmitCtx *e, DebugFunc *f, i32 scope_idx); -static void emit_vars_in_scope(EmitCtx* e, DebugFunc* f, i32 scope_idx) { +static void emit_vars_in_scope(EmitCtx *e, DebugFunc *f, i32 scope_idx) { u32 i; for (i = 0; i < f->nvars; ++i) { - DebugVarDIE* v = &f->vars[i]; - if (v->is_param) continue; - if (v->scope_idx == scope_idx) emit_var_die(e, v); + DebugVarDIE *v = &f->vars[i]; + if (v->is_param) + continue; + if (v->scope_idx == scope_idx) + emit_var_die(e, v); } { u32 s; @@ -632,22 +644,23 @@ static void emit_vars_in_scope(EmitCtx* e, DebugFunc* f, i32 scope_idx) { } } -static void emit_scope_subtree(EmitCtx* e, DebugFunc* f, i32 scope_idx) { +static void emit_scope_subtree(EmitCtx *e, DebugFunc *f, i32 scope_idx) { f->scopes[scope_idx].die_offset = buf_pos(&e->info_body); form_uleb(&e->info_body, e->abbr_lexical_block); emit_vars_in_scope(e, f, scope_idx); form_uleb(&e->info_body, 0); } -static void emit_subprogram_die(EmitCtx* e, DebugFunc* f) { - const ObjSym* osym = obj_symbol_get(e->ob, f->sym); +static void emit_subprogram_die(EmitCtx *e, DebugFunc *f) { + const ObjSym *osym = obj_symbol_get(e->ob, f->sym); Sym name = osym ? osym->name : 0; u32 reloc_off; u32 fn_size; DebugTypeId ret_type = DEBUG_TYPE_NONE; if (f->fn_type != DEBUG_TYPE_NONE && f->fn_type <= e->d->ntypes) { - DebugType* tt = &e->d->types[f->fn_type - 1]; - if (tt->kind == DTK_FUNC) ret_type = tt->inner; + DebugType *tt = &e->d->types[f->fn_type - 1]; + if (tt->kind == DTK_FUNC) + ret_type = tt->inner; } f->die_offset = buf_pos(&e->info_body); form_uleb(&e->info_body, e->abbr_subprogram); @@ -672,8 +685,22 @@ static void emit_subprogram_die(EmitCtx* e, DebugFunc* f) { /* Children: params first, then top-level locals/scopes. */ { u32 i; + u32 emitted_params = 0; for (i = 0; i < f->nvars; ++i) { - if (f->vars[i].is_param) emit_var_die(e, &f->vars[i]); + if (f->vars[i].is_param) { + emit_var_die(e, &f->vars[i]); + emitted_params++; + } + } + if (!emitted_params && f->fn_type != DEBUG_TYPE_NONE && + f->fn_type <= e->d->ntypes) { + DebugType *tt = &e->d->types[f->fn_type - 1]; + if (tt->kind == DTK_FUNC) { + for (i = 0; i < tt->nparams; ++i) { + form_uleb(&e->info_body, e->abbr_func_type_param); + emit_type_ref(e, tt->params[i]); + } + } } emit_vars_in_scope(e, f, -1); form_uleb(&e->info_body, 0); @@ -683,7 +710,7 @@ static void emit_subprogram_die(EmitCtx* e, DebugFunc* f) { /* ---------------------------------------------------------------- */ /* Section flushing. */ -static ObjSecId mk_section(EmitCtx* e, const char* name) { +static ObjSecId mk_section(EmitCtx *e, const char *name) { Sym n = pool_intern_cstr(e->pool, name); return obj_section(e->ob, n, SEC_DEBUG, 0, 1); } @@ -691,29 +718,31 @@ static ObjSecId mk_section(EmitCtx* e, const char* name) { /* Pre-create one SK_SECTION ObjSym pointing at `sec`. Section symbols are * nameless (Sym 0); identity is the section_id they reference. SB_LOCAL * because section symbols are always local in ELF/Mach-O. */ -static ObjSymId mk_section_sym(EmitCtx* e, ObjSecId sec) { +static ObjSymId mk_section_sym(EmitCtx *e, ObjSecId sec) { return obj_symbol(e->ob, 0, SB_LOCAL, SK_SECTION, sec, 0, 0); } -static void flatten_to_section(EmitCtx* e, ObjSecId sec, const Buf* src) { +static void flatten_to_section(EmitCtx *e, ObjSecId sec, const Buf *src) { u32 total = buf_pos(src); - if (total == 0) return; + if (total == 0) + return; { - u8* dst = obj_reserve(e->ob, sec, total); - if (!dst) return; + u8 *dst = obj_reserve(e->ob, sec, total); + if (!dst) + return; buf_flatten(src, dst); } } -static void emit_section_str(EmitCtx* e) { +static void emit_section_str(EmitCtx *e) { flatten_to_section(e, e->sec_str, &e->str.buf); } -static void emit_section_line_str(EmitCtx* e) { +static void emit_section_line_str(EmitCtx *e) { flatten_to_section(e, e->sec_line_str, &e->line_str.buf); } -static void emit_section_str_offsets(EmitCtx* e) { +static void emit_section_str_offsets(EmitCtx *e) { Buf b; u32 i; u32 unit_length; @@ -733,19 +762,19 @@ static void emit_section_str_offsets(EmitCtx* e) { * out) S=0 so the value is unchanged, and for the concatenated JIT * view S = view-prefix into .debug_str so the slot picks up the * right per-input offset. */ - u32* ofs = SymToU32_get(&e->str.by_sym, e->str.syms[i]); + u32 *ofs = SymToU32_get(&e->str.by_sym, e->str.syms[i]); form_u32(&b, ofs ? *ofs : 0); } flatten_to_section(e, e->sec_str_off, &b); for (i = 0; i < e->str.nsyms; ++i) { - u32* ofs = SymToU32_get(&e->str.by_sym, e->str.syms[i]); - obj_reloc(e->ob, e->sec_str_off, entries_off + i * 4u, R_ABS32, - e->ssym_str, (i64)(ofs ? *ofs : 0)); + u32 *ofs = SymToU32_get(&e->str.by_sym, e->str.syms[i]); + obj_reloc(e->ob, e->sec_str_off, entries_off + i * 4u, R_ABS32, e->ssym_str, + (i64)(ofs ? *ofs : 0)); } buf_fini(&b); } -static void emit_section_abbrev(EmitCtx* e) { +static void emit_section_abbrev(EmitCtx *e) { Buf b; buf_init(&b, e->heap); abbrev_encode(&e->abbr, &b); @@ -765,14 +794,14 @@ static void emit_section_abbrev(EmitCtx* e) { * * We emit, then track the program-start byte offset within the section so * we can place address relocations. */ -static void emit_section_line(EmitCtx* e) { +static void emit_section_line(EmitCtx *e) { Buf prog; Buf hdr_body; /* header from min_inst_length onward */ Buf out; - Pool* pool = e->pool; + Pool *pool = e->pool; u32 i, j; u32 dir_count; - Sym* dirs = NULL; + Sym *dirs = NULL; u32 ndirs = 0, dirs_cap = 0; /* Pending line_strp relocs. Each slot is a u32 in hdr_body at * `slot[k].at` with addend `slot[k].ofs` (the resolved .debug_line_str @@ -782,7 +811,7 @@ static void emit_section_line(EmitCtx* e) { struct LineStrpSlot { u32 at; u32 ofs; - }* lsp_slots = NULL; + } *lsp_slots = NULL; u32 nlsp = 0, lsp_cap = 0; /* aarch64: instructions are 4-byte aligned. DW_LNS_advance_pc takes the * advance in *operations*, which the consumer multiplies by min_inst_length @@ -796,10 +825,11 @@ static void emit_section_line(EmitCtx* e) { /* Build the program first (so we know its length). */ for (i = 0; i < e->d->nfuncs; ++i) { - DebugFunc* f = &e->d->funcs[i]; - LineRow* prev = NULL; + DebugFunc *f = &e->d->funcs[i]; + LineRow *prev = NULL; u8 addr_size; - if (!f->has_pc_range) continue; + if (!f->has_pc_range) + continue; addr_size = e->d->c->target.ptr_size; /* DW_LNE_set_address */ form_u8(&prog, 0); @@ -812,7 +842,7 @@ static void emit_section_line(EmitCtx* e) { add_line_reloc(e, buf_ofs, f->sym); } for (j = 0; j < f->nrows; ++j) { - LineRow* r = &f->rows[j]; + LineRow *r = &f->rows[j]; u32 dwfile = debug_file(e->d, r->loc.file_id); i64 prev_line = prev ? prev->loc.line : 1; u32 prev_offset = prev ? prev->offset : f->begin_ofs; @@ -854,11 +884,11 @@ static void emit_section_line(EmitCtx* e) { /* Build header body (from min_inst_length onward). */ form_u8(&hdr_body, (u8)min_inst_len); /* min_inst_length (aarch64) */ - form_u8(&hdr_body, 1); /* max_ops_per_inst */ - form_u8(&hdr_body, 1); /* default_is_stmt = 1 */ - form_u8(&hdr_body, (u8)(i8)-5); /* line_base */ - form_u8(&hdr_body, 14); /* line_range */ - form_u8(&hdr_body, 13); /* opcode_base = #standard ops + 1 */ + form_u8(&hdr_body, 1); /* max_ops_per_inst */ + form_u8(&hdr_body, 1); /* default_is_stmt = 1 */ + form_u8(&hdr_body, (u8)(i8)-5); /* line_base */ + form_u8(&hdr_body, 14); /* line_range */ + form_u8(&hdr_body, 13); /* opcode_base = #standard ops + 1 */ /* DWARF 5 standard_opcode_lengths for opcodes 1..12 */ { u8 lens[12]; @@ -899,7 +929,8 @@ static void emit_section_line(EmitCtx* e) { } } if (!found) { - if (!VEC_GROW(e->heap, dirs, dirs_cap, ndirs + 1)) dirs[ndirs++] = dir; + if (!VEC_GROW(e->heap, dirs, dirs_cap, ndirs + 1)) + dirs[ndirs++] = dir; } } dir_count = ndirs; @@ -938,7 +969,7 @@ static void emit_section_line(EmitCtx* e) { } else { form_uleb(&hdr_body, e->d->nfiles); for (i = 0; i < e->d->nfiles; ++i) { - DebugFile* df = &e->d->files[i]; + DebugFile *df = &e->d->files[i]; u32 di; u32 at = buf_pos(&hdr_body); u32 ofs = line_str_offset(e, df->base); @@ -949,13 +980,15 @@ static void emit_section_line(EmitCtx* e) { nlsp++; } for (di = 0; di < ndirs; ++di) { - if (dirs[di] == df->dir) break; + if (dirs[di] == df->dir) + break; } form_uleb(&hdr_body, di < ndirs ? di : 0); } } - if (dirs) e->heap->free(e->heap, dirs, sizeof(Sym) * dirs_cap); + if (dirs) + e->heap->free(e->heap, dirs, sizeof(Sym) * dirs_cap); /* Compose final section bytes: unit-length header + hdr_body + program. */ { @@ -971,21 +1004,23 @@ static void emit_section_line(EmitCtx* e) { form_u32(&out, hl); /* Append hdr_body bytes */ { - u8* tmp = (u8*)e->heap->alloc(e->heap, hl ? hl : 1, 1); + u8 *tmp = (u8 *)e->heap->alloc(e->heap, hl ? hl : 1, 1); if (tmp && hl) { buf_flatten(&hdr_body, tmp); buf_write(&out, tmp, hl); } - if (tmp) e->heap->free(e->heap, tmp, hl ? hl : 1); + if (tmp) + e->heap->free(e->heap, tmp, hl ? hl : 1); } /* Append program bytes */ { - u8* tmp = (u8*)e->heap->alloc(e->heap, plen ? plen : 1, 1); + u8 *tmp = (u8 *)e->heap->alloc(e->heap, plen ? plen : 1, 1); if (tmp && plen) { buf_flatten(&prog, tmp); buf_write(&out, tmp, plen); } - if (tmp) e->heap->free(e->heap, tmp, plen ? plen : 1); + if (tmp) + e->heap->free(e->heap, tmp, plen ? plen : 1); } flatten_to_section(e, e->sec_line, &out); /* program-start in section bytes = 12 (unit_length+ver+addr+seg+hl) + hl. @@ -1006,14 +1041,15 @@ static void emit_section_line(EmitCtx* e) { } } } - if (lsp_slots) e->heap->free(e->heap, lsp_slots, sizeof(*lsp_slots) * lsp_cap); + if (lsp_slots) + e->heap->free(e->heap, lsp_slots, sizeof(*lsp_slots) * lsp_cap); buf_fini(&prog); buf_fini(&hdr_body); buf_fini(&out); } /* .debug_aranges */ -static void emit_section_aranges(EmitCtx* e) { +static void emit_section_aranges(EmitCtx *e) { Buf b; u32 i; u32 unit_length; @@ -1038,8 +1074,9 @@ static void emit_section_aranges(EmitCtx* e) { } } for (i = 0; i < e->d->nfuncs; ++i) { - DebugFunc* f = &e->d->funcs[i]; - if (!f->has_pc_range) continue; + DebugFunc *f = &e->d->funcs[i]; + if (!f->has_pc_range) + continue; { u32 reloc_at = buf_pos(&b); u8 zeros[8] = {0}; @@ -1077,7 +1114,7 @@ static void emit_section_aranges(EmitCtx* e) { } /* .debug_rnglists */ -static void emit_section_rnglists(EmitCtx* e) { +static void emit_section_rnglists(EmitCtx *e) { Buf b; u32 unit_length; u32 i; @@ -1089,8 +1126,9 @@ static void emit_section_rnglists(EmitCtx* e) { form_u8(&b, 0); form_u32(&b, 0); /* offset_entry_count */ for (i = 0; i < e->d->nfuncs; ++i) { - DebugFunc* f = &e->d->funcs[i]; - if (!f->has_pc_range) continue; + DebugFunc *f = &e->d->funcs[i]; + if (!f->has_pc_range) + continue; form_u8(&b, DW_RLE_start_length); { u32 reloc_at = buf_pos(&b); @@ -1119,7 +1157,7 @@ static void emit_section_rnglists(EmitCtx* e) { } /* .debug_info: prepend CU header, append body, apply relocs and fixups. */ -static void emit_section_info(EmitCtx* e) { +static void emit_section_info(EmitCtx *e) { Buf out; u32 cu_header_size = 12; u32 body_size = buf_pos(&e->info_body); @@ -1133,12 +1171,13 @@ static void emit_section_info(EmitCtx* e) { /* Append body */ { u32 plen = body_size; - u8* tmp = (u8*)e->heap->alloc(e->heap, plen ? plen : 1, 1); + u8 *tmp = (u8 *)e->heap->alloc(e->heap, plen ? plen : 1, 1); if (tmp && plen) { buf_flatten(&e->info_body, tmp); buf_write(&out, tmp, plen); } - if (tmp) e->heap->free(e->heap, tmp, plen ? plen : 1); + if (tmp) + e->heap->free(e->heap, tmp, plen ? plen : 1); } flatten_to_section(e, e->sec_info, &out); /* CU header cross-section refs: debug_abbrev_offset at byte 8. Root @@ -1148,10 +1187,10 @@ static void emit_section_info(EmitCtx* e) { * offset (0 for abbrev/stmt_list, 12 for rnglists past its header, 8 * for str_offsets past its header). */ obj_reloc(e->ob, e->sec_info, 8u, R_ABS32, e->ssym_abbrev, 0); - obj_reloc(e->ob, e->sec_info, cu_header_size + e->root_stmt_list_at, - R_ABS32, e->ssym_line, 0); - obj_reloc(e->ob, e->sec_info, cu_header_size + e->root_ranges_at, - R_ABS32, e->ssym_rnglists, 12); + obj_reloc(e->ob, e->sec_info, cu_header_size + e->root_stmt_list_at, R_ABS32, + e->ssym_line, 0); + obj_reloc(e->ob, e->sec_info, cu_header_size + e->root_ranges_at, R_ABS32, + e->ssym_rnglists, 12); obj_reloc(e->ob, e->sec_info, cu_header_size + e->root_str_off_base_at, R_ABS32, e->ssym_str_off, 8); /* Apply forward DIE refs (DW_FORM_ref4 = CU-relative, where the CU @@ -1163,8 +1202,8 @@ static void emit_section_info(EmitCtx* e) { { u32 i; for (i = 0; i < e->nfixups; ++i) { - DieFixup* fx = &e->fixups[i]; - DebugType* tt = + DieFixup *fx = &e->fixups[i]; + DebugType *tt = (fx->target != DEBUG_TYPE_NONE && fx->target <= e->d->ntypes) ? &e->d->types[fx->target - 1] : NULL; @@ -1189,9 +1228,9 @@ static void emit_section_info(EmitCtx* e) { /* ---------------------------------------------------------------- */ -void debug_emit(Debug* d) { +void debug_emit(Debug *d) { EmitCtx ec; - Pool* pool = d->c->global; + Pool *pool = d->c->global; Sym producer_sym; Sym primary_dir = 0, primary_base = 0; u32 i; @@ -1200,9 +1239,10 @@ void debug_emit(Debug* d) { * to bzero on this size. We zero with an explicit byte-loop fallback * to match the lib_deps allowlist (which forbids _bzero). */ { - u8* p = (u8*)&ec; + u8 *p = (u8 *)&ec; size_t k; - for (k = 0; k < sizeof(ec); ++k) p[k] = 0; + for (k = 0; k < sizeof(ec); ++k) + p[k] = 0; } ec.d = d; ec.heap = d->heap; @@ -1270,8 +1310,10 @@ void debug_emit(Debug* d) { ec.root_str_off_base_at = buf_pos(&ec.info_body); form_u32(&ec.info_body, 8); - for (i = 0; i < d->ntypes; ++i) emit_type_die(&ec, (DebugTypeId)(i + 1)); - for (i = 0; i < d->nfuncs; ++i) emit_subprogram_die(&ec, &d->funcs[i]); + for (i = 0; i < d->ntypes; ++i) + emit_type_die(&ec, (DebugTypeId)(i + 1)); + for (i = 0; i < d->nfuncs; ++i) + emit_subprogram_die(&ec, &d->funcs[i]); form_uleb(&ec.info_body, 0); /* end of CU children */ /* Order: build sections that don't depend on later ones first. The str diff --git a/src/debug/dwarf_die.c b/src/debug/dwarf_die.c @@ -17,120 +17,123 @@ /* ---- subprogram + lexical_block walk --------------------------------- */ -static void pack_init(DieAttrPack* p) { memset(p, 0, sizeof(*p)); } +static void pack_init(DieAttrPack *p) { memset(p, 0, sizeof(*p)); } /* Read all attributes of a DIE into pack `p`; updates *off to past attrs. */ -static void read_pack(CfreeDebugInfo* d, const DwCu* cu, DwDie* die, - DieAttrPack* p, u32* off) { +static void read_pack(CfreeDebugInfo *d, const DwCu *cu, DwDie *die, + DieAttrPack *p, u32 *off) { u32 i; - if (!die->abbrev) return; + if (!die->abbrev) + return; for (i = 0; i < die->abbrev->nattrs; ++i) { - DwAbbrevAttr* aa = &die->abbrev->attrs[i]; + DwAbbrevAttr *aa = &die->abbrev->attrs[i]; DwAttrValue v; dw_read_form(d, cu, aa->form, aa->implicit_const, off, &v); switch (aa->attr) { - case DW_AT_name: - p->name = v.str; - break; - case DW_AT_low_pc: - p->low_pc = v.u; - p->has_low_pc = 1; - break; - case DW_AT_high_pc: - p->high_pc_value = v.u; - p->high_pc_form = aa->form; - p->has_high_pc = 1; - break; - case DW_AT_type: - /* Local CU offset: ref* forms are CU-relative; ref_addr is - * .debug_info-absolute. */ - if (aa->form == DW_FORM_ref_addr) - p->type_die_offset = (u32)v.u; - else - p->type_die_offset = cu->hdr_offset + (u32)v.u; - p->has_type = 1; - break; - case DW_AT_decl_file: - p->decl_file = (u32)v.u; - break; - case DW_AT_decl_line: - p->decl_line = (u32)v.u; - break; - case DW_AT_location: - if (aa->form == DW_FORM_loclistx) { - p->has_loclist = 1; - p->loclist_index = v.u; - } else if (aa->form == DW_FORM_exprloc || aa->form == DW_FORM_block || - aa->form == DW_FORM_block1 || aa->form == DW_FORM_block2 || - aa->form == DW_FORM_block4) { - p->loc_block = v.block; - p->loc_block_len = v.block_len; - } else if (aa->form == DW_FORM_sec_offset) { - /* Reference into .debug_loclists — not supported in Phase 5 - * baseline. */ - p->has_loclist = 1; - p->loclist_index = v.u; - } - break; - case DW_AT_frame_base: - p->fb_block = v.block; - p->fb_block_len = v.block_len; - break; - case DW_AT_const_value: - p->const_value = v.s; - p->has_const_value = 1; - break; - case DW_AT_data_member_location: - if (aa->form == DW_FORM_exprloc || aa->form == DW_FORM_block || - aa->form == DW_FORM_block1 || aa->form == DW_FORM_block2 || - aa->form == DW_FORM_block4) { - /* Best effort: evaluate a single DW_OP_plus_uconst form by - * peeking. */ - if (v.block && v.block_len > 0 && v.block[0] == DW_OP_plus_uconst) { - u32 t = 1; - p->byte_offset = (u32)dw_uleb(v.block, v.block_len, &t); - p->has_byte_offset = 1; - } - } else { - p->byte_offset = (u32)v.u; + case DW_AT_name: + p->name = v.str; + break; + case DW_AT_low_pc: + p->low_pc = v.u; + p->has_low_pc = 1; + break; + case DW_AT_high_pc: + p->high_pc_value = v.u; + p->high_pc_form = aa->form; + p->has_high_pc = 1; + break; + case DW_AT_type: + /* Local CU offset: ref* forms are CU-relative; ref_addr is + * .debug_info-absolute. */ + if (aa->form == DW_FORM_ref_addr) + p->type_die_offset = (u32)v.u; + else + p->type_die_offset = cu->hdr_offset + (u32)v.u; + p->has_type = 1; + break; + case DW_AT_decl_file: + p->decl_file = (u32)v.u; + break; + case DW_AT_decl_line: + p->decl_line = (u32)v.u; + break; + case DW_AT_location: + if (aa->form == DW_FORM_loclistx) { + p->has_loclist = 1; + p->loclist_index = v.u; + } else if (aa->form == DW_FORM_exprloc || aa->form == DW_FORM_block || + aa->form == DW_FORM_block1 || aa->form == DW_FORM_block2 || + aa->form == DW_FORM_block4) { + p->loc_block = v.block; + p->loc_block_len = v.block_len; + } else if (aa->form == DW_FORM_sec_offset) { + /* Reference into .debug_loclists — not supported in Phase 5 + * baseline. */ + p->has_loclist = 1; + p->loclist_index = v.u; + } + break; + case DW_AT_frame_base: + p->fb_block = v.block; + p->fb_block_len = v.block_len; + break; + case DW_AT_const_value: + p->const_value = v.s; + p->has_const_value = 1; + break; + case DW_AT_data_member_location: + if (aa->form == DW_FORM_exprloc || aa->form == DW_FORM_block || + aa->form == DW_FORM_block1 || aa->form == DW_FORM_block2 || + aa->form == DW_FORM_block4) { + /* Best effort: evaluate a single DW_OP_plus_uconst form by + * peeking. */ + if (v.block && v.block_len > 0 && v.block[0] == DW_OP_plus_uconst) { + u32 t = 1; + p->byte_offset = (u32)dw_uleb(v.block, v.block_len, &t); p->has_byte_offset = 1; } - break; - case DW_AT_byte_size: - p->byte_size = (u32)v.u; - p->has_byte_size = 1; - break; - case DW_AT_bit_size: - p->bit_size = (u32)v.u; - p->has_bit_size = 1; - break; - case DW_AT_bit_offset: - case DW_AT_data_bit_offset: - p->bit_offset = (u32)v.u; - p->has_bit_offset = 1; - break; - case DW_AT_encoding: - p->base_encoding = (u32)v.u; - p->has_encoding = 1; - break; - case DW_AT_count: - case DW_AT_upper_bound: - p->array_count = (u32)v.u; - if (aa->attr == DW_AT_upper_bound) p->array_count++; - p->has_array_count = 1; - break; + } else { + p->byte_offset = (u32)v.u; + p->has_byte_offset = 1; + } + break; + case DW_AT_byte_size: + p->byte_size = (u32)v.u; + p->has_byte_size = 1; + break; + case DW_AT_bit_size: + p->bit_size = (u32)v.u; + p->has_bit_size = 1; + break; + case DW_AT_bit_offset: + case DW_AT_data_bit_offset: + p->bit_offset = (u32)v.u; + p->has_bit_offset = 1; + break; + case DW_AT_encoding: + p->base_encoding = (u32)v.u; + p->has_encoding = 1; + break; + case DW_AT_count: + case DW_AT_upper_bound: + p->array_count = (u32)v.u; + if (aa->attr == DW_AT_upper_bound) + p->array_count++; + p->has_array_count = 1; + break; } } } /* Append a subprogram (or skip if its bounds aren't useful). */ -static void push_subprog(CfreeDebugInfo* d, DwSubprog* sp) { +static void push_subprog(CfreeDebugInfo *d, DwSubprog *sp) { if (d->nsubs == d->subs_cap) { u32 ncap = d->subs_cap ? d->subs_cap * 2 : 8; - DwSubprog* na = - (DwSubprog*)d->h->realloc(d->h, d->subs, d->subs_cap * sizeof(*d->subs), - ncap * sizeof(*d->subs), _Alignof(DwSubprog)); - if (!na) return; + DwSubprog *na = (DwSubprog *)d->h->realloc( + d->h, d->subs, d->subs_cap * sizeof(*d->subs), ncap * sizeof(*d->subs), + _Alignof(DwSubprog)); + if (!na) + return; d->subs = na; d->subs_cap = ncap; } @@ -138,11 +141,12 @@ static void push_subprog(CfreeDebugInfo* d, DwSubprog* sp) { } /* Walk a DIE subtree, collecting subprograms. */ -static void walk_for_subs(CfreeDebugInfo* d, u32 cu_idx, u32* off) { - DwCu* cu = &d->cus[cu_idx]; +static void walk_for_subs(CfreeDebugInfo *d, u32 cu_idx, u32 *off) { + DwCu *cu = &d->cus[cu_idx]; for (;;) { DwDie die; - if (!dw_read_die(d, cu, off, &die)) return; + if (!dw_read_die(d, cu, off, &die)) + return; if (die.abbrev->tag == DW_TAG_subprogram || die.abbrev->tag == DW_TAG_inlined_subroutine) { DieAttrPack p; @@ -163,11 +167,13 @@ static void walk_for_subs(CfreeDebugInfo* d, u32 cu_idx, u32* off) { sp.high_pc = p.low_pc; } sp.decl_line = p.decl_line; + sp.type_die_offset = p.has_type ? p.type_die_offset : 0; /* Resolve decl_file via the CU's line program. */ sp.decl_file = ""; if (p.decl_file != 0 && cu->has_stmt_list) { - DwLineProgram* lp; - if (!d->lines_built[cu_idx]) dw_build_line(d, cu_idx); + DwLineProgram *lp; + if (!d->lines_built[cu_idx]) + dw_build_line(d, cu_idx); lp = &d->lines_by_cu[cu_idx]; if (lp->nfile_norm && p.decl_file < lp->nfile_norm) sp.decl_file = lp->file_norm[p.decl_file]; @@ -190,48 +196,52 @@ static void walk_for_subs(CfreeDebugInfo* d, u32 cu_idx, u32* off) { /* Skip attrs, then descend. */ u32 i; for (i = 0; i < die.abbrev->nattrs; ++i) { - DwAbbrevAttr* aa = &die.abbrev->attrs[i]; + DwAbbrevAttr *aa = &die.abbrev->attrs[i]; dw_skip_form(d, cu, aa->form, aa->implicit_const, off); } walk_for_subs(d, cu_idx, off); } else { u32 i; for (i = 0; i < die.abbrev->nattrs; ++i) { - DwAbbrevAttr* aa = &die.abbrev->attrs[i]; + DwAbbrevAttr *aa = &die.abbrev->attrs[i]; dw_skip_form(d, cu, aa->form, aa->implicit_const, off); } } } } -void dw_build_subs(CfreeDebugInfo* d) { +void dw_build_subs(CfreeDebugInfo *d) { u32 i; - if (d->subs_built) return; + if (d->subs_built) + return; d->subs_built = 1; for (i = 0; i < d->ncus; ++i) { - DwCu* cu = &d->cus[i]; + DwCu *cu = &d->cus[i]; u32 off = cu->die_start_off; /* The root DIE is the CU itself — recurse into it. */ DwDie root; - if (!dw_read_die(d, cu, &off, &root)) continue; + if (!dw_read_die(d, cu, &off, &root)) + continue; /* Skip root attrs */ { u32 j; for (j = 0; j < root.abbrev->nattrs; ++j) { - DwAbbrevAttr* aa = &root.abbrev->attrs[j]; + DwAbbrevAttr *aa = &root.abbrev->attrs[j]; dw_skip_form(d, cu, aa->form, aa->implicit_const, &off); } } - if (root.abbrev->has_children) walk_for_subs(d, i, &off); + if (root.abbrev->has_children) + walk_for_subs(d, i, &off); } } -DwSubprog* dw_find_subprog(CfreeDebugInfo* d, u64 pc) { +DwSubprog *dw_find_subprog(CfreeDebugInfo *d, u64 pc) { u32 i; dw_build_subs(d); for (i = 0; i < d->nsubs; ++i) { - DwSubprog* sp = &d->subs[i]; - if (sp->low_pc <= pc && pc < sp->high_pc) return sp; + DwSubprog *sp = &d->subs[i]; + if (sp->low_pc <= pc && pc < sp->high_pc) + return sp; } return NULL; } @@ -239,46 +249,49 @@ DwSubprog* dw_find_subprog(CfreeDebugInfo* d, u64 pc) { /* ---- locals + parameters --------------------------------------------- */ typedef struct LocalCtx { - CfreeDebugInfo* d; + CfreeDebugInfo *d; u32 cu_idx; - DwLocal* params; + DwLocal *params; u32 nparams, params_cap; - DwLocal* locals; + DwLocal *locals; u32 nlocals, locals_cap; } LocalCtx; -static void push_param(LocalCtx* x, DwLocal* v) { +static void push_param(LocalCtx *x, DwLocal *v) { if (x->nparams == x->params_cap) { u32 ncap = x->params_cap ? x->params_cap * 2 : 4; - DwLocal* na = (DwLocal*)x->d->h->realloc( + DwLocal *na = (DwLocal *)x->d->h->realloc( x->d->h, x->params, x->params_cap * sizeof(*x->params), ncap * sizeof(*x->params), _Alignof(DwLocal)); - if (!na) return; + if (!na) + return; x->params = na; x->params_cap = ncap; } x->params[x->nparams++] = *v; } -static void push_local(LocalCtx* x, DwLocal* v) { +static void push_local(LocalCtx *x, DwLocal *v) { if (x->nlocals == x->locals_cap) { u32 ncap = x->locals_cap ? x->locals_cap * 2 : 4; - DwLocal* na = (DwLocal*)x->d->h->realloc( + DwLocal *na = (DwLocal *)x->d->h->realloc( x->d->h, x->locals, x->locals_cap * sizeof(*x->locals), ncap * sizeof(*x->locals), _Alignof(DwLocal)); - if (!na) return; + if (!na) + return; x->locals = na; x->locals_cap = ncap; } x->locals[x->nlocals++] = *v; } -static void walk_subprog_body(LocalCtx* x, u32* off, u64 scope_lo, u64 scope_hi, +static void walk_subprog_body(LocalCtx *x, u32 *off, u64 scope_lo, u64 scope_hi, u32 scope_die_off, u8 has_scope) { - CfreeDebugInfo* d = x->d; - DwCu* cu = &d->cus[x->cu_idx]; + CfreeDebugInfo *d = x->d; + DwCu *cu = &d->cus[x->cu_idx]; for (;;) { DwDie die; - if (!dw_read_die(d, cu, off, &die)) return; + if (!dw_read_die(d, cu, off, &die)) + return; if (die.abbrev->tag == DW_TAG_formal_parameter || die.abbrev->tag == DW_TAG_variable) { DieAttrPack p; @@ -321,7 +334,7 @@ static void walk_subprog_body(LocalCtx* x, u32* off, u64 scope_lo, u64 scope_hi, } else { u32 i; for (i = 0; i < die.abbrev->nattrs; ++i) { - DwAbbrevAttr* aa = &die.abbrev->attrs[i]; + DwAbbrevAttr *aa = &die.abbrev->attrs[i]; dw_skip_form(d, cu, aa->form, aa->implicit_const, off); } if (die.abbrev->has_children) @@ -330,22 +343,25 @@ static void walk_subprog_body(LocalCtx* x, u32* off, u64 scope_lo, u64 scope_hi, } } -void dw_build_locals(CfreeDebugInfo* d, DwSubprog* sp) { +void dw_build_locals(CfreeDebugInfo *d, DwSubprog *sp) { LocalCtx x; - DwCu* cu; + DwCu *cu; u32 off; DwDie die; - if (sp->cached_locals) return; + if (sp->cached_locals) + return; sp->cached_locals = 1; cu = &d->cus[sp->cu_idx]; off = sp->die_offset; - if (!dw_read_die(d, cu, &off, &die)) return; - if (!die.abbrev || !die.abbrev->has_children) return; + if (!dw_read_die(d, cu, &off, &die)) + return; + if (!die.abbrev || !die.abbrev->has_children) + return; /* Skip subprog attrs */ { u32 i; for (i = 0; i < die.abbrev->nattrs; ++i) { - DwAbbrevAttr* aa = &die.abbrev->attrs[i]; + DwAbbrevAttr *aa = &die.abbrev->attrs[i]; dw_skip_form(d, cu, aa->form, aa->implicit_const, &off); } } @@ -361,27 +377,31 @@ void dw_build_locals(CfreeDebugInfo* d, DwSubprog* sp) { /* ---- globals --------------------------------------------------------- */ -void dw_build_globals(CfreeDebugInfo* d) { +void dw_build_globals(CfreeDebugInfo *d) { u32 i; - if (d->globals_built) return; + if (d->globals_built) + return; d->globals_built = 1; for (i = 0; i < d->ncus; ++i) { - DwCu* cu = &d->cus[i]; + DwCu *cu = &d->cus[i]; u32 off = cu->die_start_off; DwDie root; - if (!dw_read_die(d, cu, &off, &root)) continue; + if (!dw_read_die(d, cu, &off, &root)) + continue; { u32 j; for (j = 0; j < root.abbrev->nattrs; ++j) { - DwAbbrevAttr* aa = &root.abbrev->attrs[j]; + DwAbbrevAttr *aa = &root.abbrev->attrs[j]; dw_skip_form(d, cu, aa->form, aa->implicit_const, &off); } } - if (!root.abbrev->has_children) continue; + if (!root.abbrev->has_children) + continue; /* Walk only top-level children of the CU; collect DW_TAG_variable. */ for (;;) { DwDie die; - if (!dw_read_die(d, cu, &off, &die)) break; + if (!dw_read_die(d, cu, &off, &die)) + break; if (die.abbrev->tag == DW_TAG_variable) { DieAttrPack p; DwLocal v; @@ -399,10 +419,11 @@ void dw_build_globals(CfreeDebugInfo* d) { v.is_global = 1; if (d->nglobals == d->globals_cap) { u32 ncap = d->globals_cap ? d->globals_cap * 2 : 8; - DwLocal* na = (DwLocal*)d->h->realloc( + DwLocal *na = (DwLocal *)d->h->realloc( d->h, d->globals, d->globals_cap * sizeof(*d->globals), ncap * sizeof(*d->globals), _Alignof(DwLocal)); - if (!na) break; + if (!na) + break; d->globals = na; d->globals_cap = ncap; } @@ -411,7 +432,8 @@ void dw_build_globals(CfreeDebugInfo* d) { /* Skip children. */ for (;;) { DwDie c; - if (!dw_read_die(d, cu, &off, &c)) break; + if (!dw_read_die(d, cu, &off, &c)) + break; dw_skip_die_subtree(d, cu, &c, &off); } } @@ -423,8 +445,8 @@ void dw_build_globals(CfreeDebugInfo* d) { } /* Public accessor for the type module: read attrs given die. */ -void dw_die_pack(CfreeDebugInfo* d, const DwCu* cu, DwDie* die, - DieAttrPack* p) { +void dw_die_pack(CfreeDebugInfo *d, const DwCu *cu, DwDie *die, + DieAttrPack *p) { u32 off = die->attrs_off; pack_init(p); read_pack(d, cu, die, p, &off); diff --git a/src/debug/dwarf_internal.h b/src/debug/dwarf_internal.h @@ -18,7 +18,7 @@ /* ---- Section & byte slice helpers ------------------------------------- */ typedef struct DwSection { - const u8* data; + const u8 *data; u32 size; u32 sec_idx; /* 0-based section index, or UINT32_MAX if missing */ } DwSection; @@ -36,14 +36,14 @@ typedef struct DwAbbrev { u32 tag; /* DW_TAG_* */ u8 has_children; u32 nattrs; - DwAbbrevAttr* attrs; /* heap-allocated */ + DwAbbrevAttr *attrs; /* heap-allocated */ } DwAbbrev; typedef struct DwAbbrevTable { u32 cu_abbrev_offset; /* offset into .debug_abbrev */ /* Dense map: code → index (or 0 if absent). For typical small tables we * keep them in a sorted array searched linearly. */ - DwAbbrev* abbrevs; + DwAbbrev *abbrevs; u32 nabbrevs; u32 cap; } DwAbbrevTable; @@ -67,8 +67,8 @@ typedef struct DwCu { u32 rnglists_base; u32 stmt_list; /* DW_AT_stmt_list value (offset into .debug_line) */ u8 has_stmt_list; - const char* comp_dir; - const char* name; + const char *comp_dir; + const char *name; /* Index of abbrev table in dbg->abbrevs */ u32 abbrev_table_idx; } DwCu; @@ -100,33 +100,33 @@ typedef enum DwTypeKind { } DwTypeKind; typedef struct DwField { - const char* name; + const char *name; u32 byte_offset; u32 bit_offset; u32 bit_size; - struct CfreeDwarfType* type; + struct CfreeDwarfType *type; } DwField; typedef struct DwEnumVal { - const char* name; + const char *name; i64 value; } DwEnumVal; struct CfreeDwarfType { DwTypeKind kind; u32 byte_size; - const char* name; + const char *name; u32 element_count; u32 die_offset; /* origin DIE for cycle-detection / dedup */ /* DT_PTR/ARRAY/TYPEDEF/CONST/VOLATILE/RESTRICT/FUNC: inner type */ - struct CfreeDwarfType* inner; + struct CfreeDwarfType *inner; /* Base type encoding (DW_ATE_*) — used to derive SINT/UINT/CHAR/BOOL/FLOAT */ u32 base_encoding; /* STRUCT/UNION fields */ - DwField* fields; + DwField *fields; u32 nfields; /* ENUM values */ - DwEnumVal* evals; + DwEnumVal *evals; u32 nevals; }; @@ -142,30 +142,30 @@ typedef struct DwLineRow { } DwLineRow; typedef struct DwLineFile { - const char* path; /* interned in our string table */ + const char *path; /* interned in our string table */ u32 dir_index; } DwLineFile; typedef struct DwLineProgram { /* Per-CU line program decoding state. We materialize all rows into a * single rows array for fast lookup. */ - DwLineRow* rows; + DwLineRow *rows; u32 nrows; u32 cap; /* File table (file_index 0 is the CU primary in DW5). */ - DwLineFile* files; + DwLineFile *files; u32 nfiles; - const char** dirs; + const char **dirs; u32 ndirs; /* Cached fully-qualified path per file, lazily built. */ - const char** file_norm; + const char **file_norm; u32 nfile_norm; } DwLineProgram; /* ---- Subprogram descriptor (cached) ---- */ typedef struct DwLocal { - const char* name; + const char *name; u32 die_offset; u32 type_die_offset; u64 scope_lo; /* PCs at which the var is in scope. */ @@ -173,7 +173,7 @@ typedef struct DwLocal { u32 scope_offset; /* offset of the lexical_block DIE; 0 = subprog scope */ u8 has_scope; /* Location form: either an exprloc or a loclistx index. */ - const u8* loc; + const u8 *loc; u32 loc_len; u8 has_loclist; u64 loclist_index; @@ -184,20 +184,21 @@ typedef struct DwLocal { } DwLocal; typedef struct DwSubprog { - const char* name; + const char *name; u64 low_pc; u64 high_pc; - const char* decl_file; + const char *decl_file; u32 decl_line; u32 cu_idx; u32 die_offset; /* offset of the subprogram DIE */ + u32 type_die_offset; /* Frame base — DW_AT_frame_base exprloc bytes (or NULL). */ - const u8* frame_base; + const u8 *frame_base; u32 frame_base_len; /* Cached params and locals (lazily). */ - DwLocal* params; + DwLocal *params; u32 nparams; - DwLocal* locals; + DwLocal *locals; u32 nlocals; u8 inlined; u8 cached_locals; @@ -210,9 +211,9 @@ typedef struct DwString { } DwString; struct CfreeDebugInfo { - CfreeCompiler* c; - Heap* h; - const CfreeObjFile* obj; + CfreeCompiler *c; + Heap *h; + const CfreeObjFile *obj; /* Sections */ DwSection abbrev; @@ -228,33 +229,33 @@ struct CfreeDebugInfo { DwSection aranges; /* Abbrev tables (one per unique abbrev_offset we've seen). */ - DwAbbrevTable* abbrevs; + DwAbbrevTable *abbrevs; u32 nabbrevs; u32 abbrevs_cap; /* CUs */ - DwCu* cus; + DwCu *cus; u32 ncus; u32 cus_cap; /* Line programs by CU index (parallel to cus). Each lazily built. */ - DwLineProgram* lines_by_cu; - u8* lines_built; /* parallel; 0 = not yet decoded */ + DwLineProgram *lines_by_cu; + u8 *lines_built; /* parallel; 0 = not yet decoded */ /* Subprograms (sorted by low_pc on first build). */ - DwSubprog* subs; + DwSubprog *subs; u32 nsubs; u32 subs_cap; u8 subs_built; /* Type cache: DIE-offset → CfreeDwarfType*. */ - CfreeDwarfType** types_by_off; /* parallel arrays */ - u32* types_off; + CfreeDwarfType **types_by_off; /* parallel arrays */ + u32 *types_off; u32 ntypes; u32 types_cap; /* Globals (top-level DW_TAG_variable in any CU). */ - DwLocal* globals; + DwLocal *globals; u32 nglobals; u32 globals_cap; u8 globals_built; @@ -264,37 +265,37 @@ struct CfreeDebugInfo { /* Section lookup by name. Sets out->data/size; sec_idx = UINT32_MAX if missing. */ -void dw_find_section(CfreeDebugInfo* d, const char* name, DwSection* out); +void dw_find_section(CfreeDebugInfo *d, const char *name, DwSection *out); /* Read primitives. Each returns the new offset on success and panics on EOF. */ -u8 dw_u8(const u8* base, u32 size, u32* off); -u16 dw_u16(const u8* base, u32 size, u32* off); -u32 dw_u24(const u8* base, u32 size, u32* off); -u32 dw_u32(const u8* base, u32 size, u32* off); -u64 dw_u64(const u8* base, u32 size, u32* off); -u64 dw_uleb(const u8* base, u32 size, u32* off); -i64 dw_sleb(const u8* base, u32 size, u32* off); -const char* dw_cstr(const u8* base, u32 size, u32* off); +u8 dw_u8(const u8 *base, u32 size, u32 *off); +u16 dw_u16(const u8 *base, u32 size, u32 *off); +u32 dw_u24(const u8 *base, u32 size, u32 *off); +u32 dw_u32(const u8 *base, u32 size, u32 *off); +u64 dw_u64(const u8 *base, u32 size, u32 *off); +u64 dw_uleb(const u8 *base, u32 size, u32 *off); +i64 dw_sleb(const u8 *base, u32 size, u32 *off); +const char *dw_cstr(const u8 *base, u32 size, u32 *off); /* Abbrev parsing: ensure (and return) the abbrev table for `offset`. */ -DwAbbrevTable* dw_abbrev_get(CfreeDebugInfo* d, u32 offset); -DwAbbrev* dw_abbrev_lookup(DwAbbrevTable* t, u64 code); +DwAbbrevTable *dw_abbrev_get(CfreeDebugInfo *d, u32 offset); +DwAbbrev *dw_abbrev_lookup(DwAbbrevTable *t, u64 code); /* Parse the CU header at offset `off` in .debug_info into `cu`. * Returns the offset of the next CU header. */ -u32 dw_cu_parse_header(CfreeDebugInfo* d, u32 off, DwCu* cu); +u32 dw_cu_parse_header(CfreeDebugInfo *d, u32 off, DwCu *cu); /* Skim every CU and populate dbg->cus. */ -void dw_parse_all_cus(CfreeDebugInfo* d); +void dw_parse_all_cus(CfreeDebugInfo *d); /* Open the .debug_str_offsets table indexed by str_offsets_base. */ -const char* dw_str(CfreeDebugInfo* d, u32 offset); -const char* dw_line_str(CfreeDebugInfo* d, u32 offset); -const char* dw_strx(CfreeDebugInfo* d, const DwCu* cu, u64 idx); +const char *dw_str(CfreeDebugInfo *d, u32 offset); +const char *dw_line_str(CfreeDebugInfo *d, u32 offset); +const char *dw_strx(CfreeDebugInfo *d, const DwCu *cu, u64 idx); /* Skip one attribute value of `form` size. *off is updated. */ -void dw_skip_form(CfreeDebugInfo* d, const DwCu* cu, u32 form, - i64 implicit_const, u32* off); +void dw_skip_form(CfreeDebugInfo *d, const DwCu *cu, u32 form, + i64 implicit_const, u32 *off); /* Read attribute value into a typed accumulator. Caller picks which getter. */ typedef struct DwAttrValue { @@ -302,19 +303,19 @@ typedef struct DwAttrValue { /* Values for various forms — only one slot is meaningful per form. */ u64 u; /* udata, addr, ref (CU-relative offset for local refs) */ i64 s; /* sdata */ - const char* str; /* strp/string/strx/line_strp resolved cstring */ - const u8* block; /* exprloc/block bytes */ + const char *str; /* strp/string/strx/line_strp resolved cstring */ + const u8 *block; /* exprloc/block bytes */ u32 block_len; } DwAttrValue; /* Read attr value at *off using `form`. Updates *off. */ -void dw_read_form(CfreeDebugInfo* d, const DwCu* cu, u32 form, - i64 implicit_const, u32* off, DwAttrValue* out); +void dw_read_form(CfreeDebugInfo *d, const DwCu *cu, u32 form, + i64 implicit_const, u32 *off, DwAttrValue *out); /* DIE iteration helpers. */ typedef struct DwDie { u64 abbrev_code; - DwAbbrev* abbrev; /* NULL if abbrev_code==0 (null entry) */ + DwAbbrev *abbrev; /* NULL if abbrev_code==0 (null entry) */ u32 die_off; /* offset of this DIE itself in .debug_info */ u32 attrs_off; /* where attribute encodings start */ u32 next_sibling_off; /* lazily computed */ @@ -323,45 +324,48 @@ typedef struct DwDie { /* Read one DIE header at *off. Updates *off to point past the abbrev code, * to the start of the attribute area. Returns 1 on success, 0 if this is a * null-entry (terminates a sibling chain). */ -int dw_read_die(CfreeDebugInfo* d, const DwCu* cu, u32* off, DwDie* out); +int dw_read_die(CfreeDebugInfo *d, const DwCu *cu, u32 *off, DwDie *out); /* Skip a DIE's attribute area, advancing *off past it. */ -void dw_skip_die_attrs(CfreeDebugInfo* d, const DwCu* cu, DwDie* die, u32* off); +void dw_skip_die_attrs(CfreeDebugInfo *d, const DwCu *cu, DwDie *die, u32 *off); /* Skip an entire DIE subtree (including children), starting at attrs_off. * On entry, *off == die->attrs_off. On exit, *off is past the children * terminator (if has_children) or just past the attrs (if no children). */ -void dw_skip_die_subtree(CfreeDebugInfo* d, const DwCu* cu, DwDie* die, - u32* off); +void dw_skip_die_subtree(CfreeDebugInfo *d, const DwCu *cu, DwDie *die, + u32 *off); /* Lookup an attribute on `die` by attr code. Returns 1 if found and fills * *out; 0 otherwise. Restartable (rewinds the cursor). */ -int dw_die_attr(CfreeDebugInfo* d, const DwCu* cu, DwDie* die, u32 attr, - DwAttrValue* out); +int dw_die_attr(CfreeDebugInfo *d, const DwCu *cu, DwDie *die, u32 attr, + DwAttrValue *out); /* String interning into the compiler's global pool. */ -const char* dw_intern(CfreeDebugInfo* d, const char* s, size_t len); +const char *dw_intern(CfreeDebugInfo *d, const char *s, size_t len); /* Inline strcmp/strlen — libcfree avoids a runtime libc dep beyond the * tightly-controlled allowlist (test/lib_deps.allowlist). */ -static inline int dw_streq(const char* a, const char* b) { - if (!a || !b) return 0; +static inline int dw_streq(const char *a, const char *b) { + if (!a || !b) + return 0; while (*a && *b && *a == *b) { a++; b++; } return *a == 0 && *b == 0; } -static inline size_t dw_strlen(const char* s) { +static inline size_t dw_strlen(const char *s) { size_t n = 0; - if (!s) return 0; - while (s[n]) n++; + if (!s) + return 0; + while (s[n]) + n++; return n; } /* DIE attribute pack — shared between dwarf_die.c and dwarf_type.c. */ typedef struct DieAttrPack { - const char* name; + const char *name; u64 low_pc; u64 high_pc_value; u32 high_pc_form; @@ -371,11 +375,11 @@ typedef struct DieAttrPack { u8 has_type; u32 decl_file; u32 decl_line; - const u8* loc_block; + const u8 *loc_block; u32 loc_block_len; u8 has_loclist; u64 loclist_index; - const u8* fb_block; + const u8 *fb_block; u32 fb_block_len; i64 const_value; u8 has_const_value; @@ -394,22 +398,22 @@ typedef struct DieAttrPack { u8 inlined; } DieAttrPack; -void dw_die_pack(CfreeDebugInfo* d, const DwCu* cu, DwDie* die, DieAttrPack* p); +void dw_die_pack(CfreeDebugInfo *d, const DwCu *cu, DwDie *die, DieAttrPack *p); /* Subprograms */ -void dw_build_subs(CfreeDebugInfo* d); -DwSubprog* dw_find_subprog(CfreeDebugInfo* d, u64 pc); -void dw_build_locals(CfreeDebugInfo* d, DwSubprog* sp); +void dw_build_subs(CfreeDebugInfo *d); +DwSubprog *dw_find_subprog(CfreeDebugInfo *d, u64 pc); +void dw_build_locals(CfreeDebugInfo *d, DwSubprog *sp); /* Globals */ -void dw_build_globals(CfreeDebugInfo* d); +void dw_build_globals(CfreeDebugInfo *d); /* Line program */ -void dw_build_line(CfreeDebugInfo* d, u32 cu_idx); +void dw_build_line(CfreeDebugInfo *d, u32 cu_idx); /* Type DIE → CfreeDwarfType*. die_offset is absolute offset in .debug_info. */ -CfreeDwarfType* dw_type_from_die(CfreeDebugInfo* d, u32 cu_idx, u32 die_offset); -CfreeDwarfType* dw_void_type(CfreeDebugInfo* d); +CfreeDwarfType *dw_type_from_die(CfreeDebugInfo *d, u32 cu_idx, u32 die_offset); +CfreeDwarfType *dw_void_type(CfreeDebugInfo *d); /* Loc-expr evaluator. Evaluates `expr` of length `len` in the context of * `frame` (regs, cfa) and `frame_base_expr` (the subprog's DW_AT_frame_base @@ -422,16 +426,16 @@ typedef struct DwExprResult { u64 value; /* address if kind=0; literal if kind=1; reg# if kind=2 */ } DwExprResult; -int dw_eval_expr(CfreeDebugInfo* d, const u8* expr, u32 len, const u8* fb_expr, - u32 fb_len, const CfreeUnwindFrame* frame, DwExprResult* out); +int dw_eval_expr(CfreeDebugInfo *d, const u8 *expr, u32 len, const u8 *fb_expr, + u32 fb_len, const CfreeUnwindFrame *frame, DwExprResult *out); /* CU lookup helpers. */ -DwCu* dw_cu_at_die_offset(CfreeDebugInfo* d, u32 die_offset); +DwCu *dw_cu_at_die_offset(CfreeDebugInfo *d, u32 die_offset); /* Resolve a DW_FORM_loclistx into the matching location list entry for * `pc`. Returns 1 and fills bytes/len on success; 0 if the section is * absent, the index is bad, or no entry covers `pc`. */ -int dw_loclist_resolve(CfreeDebugInfo* d, const DwCu* cu, u64 idx, u64 pc, - const u8** bytes, u32* len); +int dw_loclist_resolve(CfreeDebugInfo *d, const DwCu *cu, u64 idx, u64 pc, + const u8 **bytes, u32 *len); #endif diff --git a/src/debug/dwarf_query.c b/src/debug/dwarf_query.c @@ -13,37 +13,87 @@ #include "core/heap.h" #include "debug/dwarf_internal.h" -int cfree_dwarf_subprogram_at(CfreeDebugInfo* d, uint64_t pc, - CfreeDwarfSubprogram* out) { - DwSubprog* sp; - if (!d || !out) return 1; +static void fill_subprogram(CfreeDebugInfo *d, DwSubprog *sp, + CfreeDwarfSubprogram *out) { memset(out, 0, sizeof(*out)); - sp = dw_find_subprog(d, pc); - if (!sp) return 1; out->name = sp->name ? sp->name : ""; out->low_pc = sp->low_pc; out->high_pc = sp->high_pc; out->decl_file = sp->decl_file ? sp->decl_file : ""; out->decl_line = sp->decl_line; + out->return_type = sp->type_die_offset + ? dw_type_from_die(d, sp->cu_idx, sp->type_die_offset) + : dw_void_type(d); out->inlined = sp->inlined; +} + +int cfree_dwarf_subprogram_at(CfreeDebugInfo *d, uint64_t pc, + CfreeDwarfSubprogram *out) { + DwSubprog *sp; + if (!d || !out) + return 1; + sp = dw_find_subprog(d, pc); + if (!sp) + return 1; + fill_subprogram(d, sp, out); return 0; } -int cfree_dwarf_func_at(CfreeDebugInfo* d, uint64_t pc, const char** name_out, - uint64_t* low_out, uint64_t* high_out) { +static DwSubprog *dw_find_subprog_named(CfreeDebugInfo *d, const char *name) { + u32 i; + if (!d || !name) + return NULL; + dw_build_subs(d); + for (i = 0; i < d->nsubs; ++i) { + DwSubprog *sp = &d->subs[i]; + if (sp->inlined) + continue; + if (!sp->name || !dw_streq(sp->name, name)) + continue; + if (sp->high_pc > sp->low_pc) + return sp; + } + for (i = 0; i < d->nsubs; ++i) { + DwSubprog *sp = &d->subs[i]; + if (sp->inlined) + continue; + if (sp->name && dw_streq(sp->name, name)) + return sp; + } + return NULL; +} + +int cfree_dwarf_subprogram_named(CfreeDebugInfo *d, const char *name, + CfreeDwarfSubprogram *out) { + DwSubprog *sp; + if (!d || !name || !out) + return 1; + sp = dw_find_subprog_named(d, name); + if (!sp) + return 1; + fill_subprogram(d, sp, out); + return 0; +} + +int cfree_dwarf_func_at(CfreeDebugInfo *d, uint64_t pc, const char **name_out, + uint64_t *low_out, uint64_t *high_out) { CfreeDwarfSubprogram sp; - if (cfree_dwarf_subprogram_at(d, pc, &sp) != 0) return 1; - if (name_out) *name_out = sp.name; - if (low_out) *low_out = sp.low_pc; - if (high_out) *high_out = sp.high_pc; + if (cfree_dwarf_subprogram_at(d, pc, &sp) != 0) + return 1; + if (name_out) + *name_out = sp.name; + if (low_out) + *low_out = sp.low_pc; + if (high_out) + *high_out = sp.high_pc; return 0; } /* ---- variable resolution -------------------------------------------- */ -static void fill_varloc(CfreeDebugInfo* d, u32 cu_idx, const DwLocal* v, u64 pc, - CfreeDwarfVarLoc* out) { - const u8* lbytes = v->loc; +static void fill_varloc(CfreeDebugInfo *d, u32 cu_idx, const DwLocal *v, u64 pc, + CfreeDwarfVarLoc *out) { + const u8 *lbytes = v->loc; u32 llen = v->loc_len; memset(out, 0, sizeof(*out)); out->kind = CFREE_DLOC_EXPR; @@ -51,12 +101,13 @@ static void fill_varloc(CfreeDebugInfo* d, u32 cu_idx, const DwLocal* v, u64 pc, out->type = NULL; if (v->type_die_offset) { out->type = dw_type_from_die(d, cu_idx, v->type_die_offset); - if (out->type) out->byte_size = out->type->byte_size; + if (out->type) + out->byte_size = out->type->byte_size; } /* If the variable was emitted with a loclistx, resolve it now. The * resolved bytes get the same single-op fast-path treatment below. */ if (v->has_loclist && cu_idx < d->ncus) { - const u8* lb = NULL; + const u8 *lb = NULL; u32 ll = 0; if (dw_loclist_resolve(d, &d->cus[cu_idx], v->loclist_index, pc, &lb, &ll)) { @@ -74,7 +125,7 @@ static void fill_varloc(CfreeDebugInfo* d, u32 cu_idx, const DwLocal* v, u64 pc, * we expose the structured kind so callers can fast-path. Otherwise * we surface the raw bytes as EXPR. */ if (lbytes && llen > 0) { - const u8* e = lbytes; + const u8 *e = lbytes; if (llen == 1 && e[0] >= DW_OP_reg0 && e[0] <= DW_OP_reg0 + 31) { out->kind = CFREE_DLOC_REG; out->v.reg = e[0] - DW_OP_reg0; @@ -116,8 +167,8 @@ static void fill_varloc(CfreeDebugInfo* d, u32 cu_idx, const DwLocal* v, u64 pc, out->v.expr.len = 0; } -int cfree_dwarf_var_at(CfreeDebugInfo* d, uint64_t pc, const char* name, - CfreeDwarfVarLoc* out) { +int cfree_dwarf_var_at(CfreeDebugInfo *d, uint64_t pc, const char *name, + CfreeDwarfVarLoc *out) { /* Return codes: * 0 — found; *out filled. * 1 — invalid args, or `pc` lies inside a known subprogram but no @@ -126,9 +177,10 @@ int cfree_dwarf_var_at(CfreeDebugInfo* d, uint64_t pc, const char* name, * frame). REPL: "no debug info for this frame". Globals are * still consulted before returning 2 so a name lookup against a * global from a -g-less frame still resolves. */ - DwSubprog* sp; + DwSubprog *sp; u32 i; - if (!d || !name || !out) return 1; + if (!d || !name || !out) + return 1; memset(out, 0, sizeof(*out)); sp = dw_find_subprog(d, pc); if (sp) { @@ -136,16 +188,19 @@ int cfree_dwarf_var_at(CfreeDebugInfo* d, uint64_t pc, const char* name, /* Deepest scope first: walk locals from end (innermost blocks added * after enclosing). */ for (i = sp->nlocals; i > 0; --i) { - DwLocal* v = &sp->locals[i - 1]; - if (!v->name || !dw_streq(v->name, name)) continue; - if (v->has_scope && (pc < v->scope_lo || pc >= v->scope_hi)) continue; + DwLocal *v = &sp->locals[i - 1]; + if (!v->name || !dw_streq(v->name, name)) + continue; + if (v->has_scope && (pc < v->scope_lo || pc >= v->scope_hi)) + continue; fill_varloc(d, sp->cu_idx, v, pc, out); return 0; } /* Then params. */ for (i = 0; i < sp->nparams; ++i) { - DwLocal* v = &sp->params[i]; - if (!v->name || !dw_streq(v->name, name)) continue; + DwLocal *v = &sp->params[i]; + if (!v->name || !dw_streq(v->name, name)) + continue; fill_varloc(d, sp->cu_idx, v, pc, out); return 0; } @@ -153,73 +208,90 @@ int cfree_dwarf_var_at(CfreeDebugInfo* d, uint64_t pc, const char* name, /* Globals. */ dw_build_globals(d); for (i = 0; i < d->nglobals; ++i) { - DwLocal* v = &d->globals[i]; - if (!v->name || !dw_streq(v->name, name)) continue; + DwLocal *v = &d->globals[i]; + if (!v->name || !dw_streq(v->name, name)) + continue; fill_varloc(d, 0, v, pc, out); return 0; } return sp ? 1 : 2; } -int cfree_dwarf_loc_read(CfreeDebugInfo* d, const CfreeDwarfVarLoc* loc, - const CfreeUnwindFrame* frame, CfreeJitSession* sess, - void* dst, size_t cap, size_t* read_out) { +int cfree_dwarf_loc_read(CfreeDebugInfo *d, const CfreeDwarfVarLoc *loc, + const CfreeUnwindFrame *frame, CfreeJitSession *sess, + void *dst, size_t cap, size_t *read_out) { size_t want; - if (read_out) *read_out = 0; - if (!d || !loc || !frame || !dst) return 1; + if (read_out) + *read_out = 0; + if (!d || !loc || !frame || !dst) + return 1; want = loc->byte_size ? loc->byte_size : cap; - if (want > cap) want = cap; + if (want > cap) + want = cap; switch (loc->kind) { - case CFREE_DLOC_REG: { - uint64_t v = (loc->v.reg < 32) ? frame->regs[loc->v.reg] : 0; - size_t n = want > sizeof(v) ? sizeof(v) : want; - memcpy(dst, &v, n); - if (read_out) *read_out = n; + case CFREE_DLOC_REG: { + uint64_t v = (loc->v.reg < 32) ? frame->regs[loc->v.reg] : 0; + size_t n = want > sizeof(v) ? sizeof(v) : want; + memcpy(dst, &v, n); + if (read_out) + *read_out = n; + return 0; + } + case CFREE_DLOC_FRAME_OFS: { + uint64_t addr = frame->cfa + (uint64_t)(int64_t)loc->v.frame_ofs; + if (!sess) + return 1; + if (cfree_jit_session_read_mem(sess, addr, dst, want) != 0) + return 1; + if (read_out) + *read_out = want; + return 0; + } + case CFREE_DLOC_GLOBAL: { + uint64_t addr = loc->v.global; + if (!sess) + return 1; + if (cfree_jit_session_read_mem(sess, addr, dst, want) != 0) + return 1; + if (read_out) + *read_out = want; + return 0; + } + case CFREE_DLOC_EXPR: { + /* Evaluate. We don't have direct access to the variable's + * subprogram's frame_base here — caller-supplied frame must already + * carry the right CFA. The expression itself may be DW_OP_call_frame_cfa + * + DW_OP_consts + DW_OP_plus, etc. */ + DwExprResult r; + if (loc->v.expr.bytes == NULL || loc->v.expr.len == 0) + return 1; + if (dw_eval_expr(d, loc->v.expr.bytes, (u32)loc->v.expr.len, NULL, 0, frame, + &r) != 0) + return 1; + if (r.kind == 0) { + if (!sess) + return 1; + if (cfree_jit_session_read_mem(sess, r.value, dst, want) != 0) + return 1; + if (read_out) + *read_out = want; return 0; - } - case CFREE_DLOC_FRAME_OFS: { - uint64_t addr = frame->cfa + (uint64_t)(int64_t)loc->v.frame_ofs; - if (!sess) return 1; - if (cfree_jit_session_read_mem(sess, addr, dst, want) != 0) return 1; - if (read_out) *read_out = want; + } else if (r.kind == 1) { + size_t n = want > sizeof(r.value) ? sizeof(r.value) : want; + memcpy(dst, &r.value, n); + if (read_out) + *read_out = n; return 0; - } - case CFREE_DLOC_GLOBAL: { - uint64_t addr = loc->v.global; - if (!sess) return 1; - if (cfree_jit_session_read_mem(sess, addr, dst, want) != 0) return 1; - if (read_out) *read_out = want; + } else if (r.kind == 2) { + u64 v = (r.value < 32) ? frame->regs[r.value] : 0; + size_t n = want > sizeof(v) ? sizeof(v) : want; + memcpy(dst, &v, n); + if (read_out) + *read_out = n; return 0; } - case CFREE_DLOC_EXPR: { - /* Evaluate. We don't have direct access to the variable's - * subprogram's frame_base here — caller-supplied frame must already - * carry the right CFA. The expression itself may be DW_OP_call_frame_cfa - * + DW_OP_consts + DW_OP_plus, etc. */ - DwExprResult r; - if (loc->v.expr.bytes == NULL || loc->v.expr.len == 0) return 1; - if (dw_eval_expr(d, loc->v.expr.bytes, (u32)loc->v.expr.len, NULL, 0, - frame, &r) != 0) - return 1; - if (r.kind == 0) { - if (!sess) return 1; - if (cfree_jit_session_read_mem(sess, r.value, dst, want) != 0) return 1; - if (read_out) *read_out = want; - return 0; - } else if (r.kind == 1) { - size_t n = want > sizeof(r.value) ? sizeof(r.value) : want; - memcpy(dst, &r.value, n); - if (read_out) *read_out = n; - return 0; - } else if (r.kind == 2) { - u64 v = (r.value < 32) ? frame->regs[r.value] : 0; - size_t n = want > sizeof(v) ? sizeof(v) : want; - memcpy(dst, &v, n); - if (read_out) *read_out = n; - return 0; - } - return 1; - } + return 1; + } } return 1; } @@ -227,124 +299,132 @@ int cfree_dwarf_loc_read(CfreeDebugInfo* d, const CfreeDwarfVarLoc* loc, /* ---- vars_at_* iterator --------------------------------------------- */ struct CfreeDwarfVarIter { - CfreeDebugInfo* d; - DwSubprog* sp; + CfreeDebugInfo *d; + DwSubprog *sp; u64 pc; u32 mask; u32 phase; /* 0 = locals, 1 = params, 2 = globals, 3 = done */ u32 idx; }; -CfreeDwarfVarIter* cfree_dwarf_vars_at_new(CfreeDebugInfo* d, uint64_t pc, +CfreeDwarfVarIter *cfree_dwarf_vars_at_new(CfreeDebugInfo *d, uint64_t pc, uint32_t mask) { - CfreeDwarfVarIter* it; - if (!d) return NULL; - it = (CfreeDwarfVarIter*)d->h->alloc(d->h, sizeof(*it), - _Alignof(CfreeDwarfVarIter)); - if (!it) return NULL; + CfreeDwarfVarIter *it; + if (!d) + return NULL; + it = (CfreeDwarfVarIter *)d->h->alloc(d->h, sizeof(*it), + _Alignof(CfreeDwarfVarIter)); + if (!it) + return NULL; it->d = d; it->pc = pc; it->mask = mask; it->sp = dw_find_subprog(d, pc); - if (it->sp) dw_build_locals(d, it->sp); + if (it->sp) + dw_build_locals(d, it->sp); it->phase = 0; it->idx = it->sp ? it->sp->nlocals : 0; return it; } -int cfree_dwarf_vars_at_next(CfreeDwarfVarIter* it, CfreeDwarfVar* out) { - if (!it || !out) return 0; +int cfree_dwarf_vars_at_next(CfreeDwarfVarIter *it, CfreeDwarfVar *out) { + if (!it || !out) + return 0; for (;;) { switch (it->phase) { - case 0: { - if (!(it->mask & (1u << CFREE_DVR_LOCAL))) { - it->phase = 1; - it->idx = 0; - break; - } - if (it->idx == 0) { - it->phase = 1; - it->idx = 0; - break; - } - { - DwLocal* v = &it->sp->locals[--it->idx]; - if (v->has_scope && (it->pc < v->scope_lo || it->pc >= v->scope_hi)) - break; - out->name = v->name ? v->name : ""; - out->role = CFREE_DVR_LOCAL; - fill_varloc(it->d, it->sp->cu_idx, v, it->pc, &out->loc); - return 1; - } + case 0: { + if (!(it->mask & (1u << CFREE_DVR_LOCAL))) { + it->phase = 1; + it->idx = 0; + break; } - case 1: { - if (!it->sp || !(it->mask & (1u << CFREE_DVR_ARG))) { - it->phase = 2; - it->idx = 0; - break; - } - if (it->idx >= it->sp->nparams) { - it->phase = 2; - it->idx = 0; - break; - } - { - DwLocal* v = &it->sp->params[it->idx++]; - out->name = v->name ? v->name : ""; - out->role = CFREE_DVR_ARG; - fill_varloc(it->d, it->sp->cu_idx, v, it->pc, &out->loc); - return 1; - } + if (it->idx == 0) { + it->phase = 1; + it->idx = 0; + break; } - case 2: { - if (!(it->mask & (1u << CFREE_DVR_GLOBAL))) { - it->phase = 3; - break; - } - dw_build_globals(it->d); - if (it->idx >= it->d->nglobals) { - it->phase = 3; + { + DwLocal *v = &it->sp->locals[--it->idx]; + if (v->has_scope && (it->pc < v->scope_lo || it->pc >= v->scope_hi)) break; - } - { - DwLocal* v = &it->d->globals[it->idx++]; - out->name = v->name ? v->name : ""; - out->role = CFREE_DVR_GLOBAL; - fill_varloc(it->d, 0, v, it->pc, &out->loc); - return 1; - } + out->name = v->name ? v->name : ""; + out->role = CFREE_DVR_LOCAL; + fill_varloc(it->d, it->sp->cu_idx, v, it->pc, &out->loc); + return 1; + } + } + case 1: { + if (!it->sp || !(it->mask & (1u << CFREE_DVR_ARG))) { + it->phase = 2; + it->idx = 0; + break; + } + if (it->idx >= it->sp->nparams) { + it->phase = 2; + it->idx = 0; + break; + } + { + DwLocal *v = &it->sp->params[it->idx++]; + out->name = v->name ? v->name : ""; + out->role = CFREE_DVR_ARG; + fill_varloc(it->d, it->sp->cu_idx, v, it->pc, &out->loc); + return 1; } - default: - return 0; + } + case 2: { + if (!(it->mask & (1u << CFREE_DVR_GLOBAL))) { + it->phase = 3; + break; + } + dw_build_globals(it->d); + if (it->idx >= it->d->nglobals) { + it->phase = 3; + break; + } + { + DwLocal *v = &it->d->globals[it->idx++]; + out->name = v->name ? v->name : ""; + out->role = CFREE_DVR_GLOBAL; + fill_varloc(it->d, 0, v, it->pc, &out->loc); + return 1; + } + } + default: + return 0; } } } -void cfree_dwarf_vars_at_free(CfreeDwarfVarIter* it) { - if (!it) return; +void cfree_dwarf_vars_at_free(CfreeDwarfVarIter *it) { + if (!it) + return; it->d->h->free(it->d->h, it, sizeof(*it)); } /* ---- param_iter_* --------------------------------------------------- */ struct CfreeDwarfParamIter { - CfreeDebugInfo* d; - DwSubprog* sp; + CfreeDebugInfo *d; + DwSubprog *sp; u64 pc; u32 idx; }; -CfreeDwarfParamIter* cfree_dwarf_param_iter_new(CfreeDebugInfo* d, +CfreeDwarfParamIter *cfree_dwarf_param_iter_new(CfreeDebugInfo *d, uint64_t pc) { - CfreeDwarfParamIter* it; - DwSubprog* sp; - if (!d) return NULL; + CfreeDwarfParamIter *it; + DwSubprog *sp; + if (!d) + return NULL; sp = dw_find_subprog(d, pc); - if (!sp) return NULL; + if (!sp) + return NULL; dw_build_locals(d, sp); - it = (CfreeDwarfParamIter*)d->h->alloc(d->h, sizeof(*it), - _Alignof(CfreeDwarfParamIter)); - if (!it) return NULL; + it = (CfreeDwarfParamIter *)d->h->alloc(d->h, sizeof(*it), + _Alignof(CfreeDwarfParamIter)); + if (!it) + return NULL; it->d = d; it->sp = sp; it->pc = pc; @@ -352,11 +432,34 @@ CfreeDwarfParamIter* cfree_dwarf_param_iter_new(CfreeDebugInfo* d, return it; } -int cfree_dwarf_param_iter_next(CfreeDwarfParamIter* it, CfreeDwarfVar* out) { - if (!it || !out) return 0; - if (it->idx >= it->sp->nparams) return 0; +CfreeDwarfParamIter *cfree_dwarf_param_iter_new_named(CfreeDebugInfo *d, + const char *name) { + CfreeDwarfParamIter *it; + DwSubprog *sp; + if (!d || !name) + return NULL; + sp = dw_find_subprog_named(d, name); + if (!sp) + return NULL; + dw_build_locals(d, sp); + it = (CfreeDwarfParamIter *)d->h->alloc(d->h, sizeof(*it), + _Alignof(CfreeDwarfParamIter)); + if (!it) + return NULL; + it->d = d; + it->sp = sp; + it->pc = sp->low_pc; + it->idx = 0; + return it; +} + +int cfree_dwarf_param_iter_next(CfreeDwarfParamIter *it, CfreeDwarfVar *out) { + if (!it || !out) + return 0; + if (it->idx >= it->sp->nparams) + return 0; { - DwLocal* v = &it->sp->params[it->idx++]; + DwLocal *v = &it->sp->params[it->idx++]; out->name = v->name ? v->name : ""; out->role = CFREE_DVR_ARG; fill_varloc(it->d, it->sp->cu_idx, v, it->pc, &out->loc); @@ -364,7 +467,8 @@ int cfree_dwarf_param_iter_next(CfreeDwarfParamIter* it, CfreeDwarfVar* out) { return 1; } -void cfree_dwarf_param_iter_free(CfreeDwarfParamIter* it) { - if (!it) return; +void cfree_dwarf_param_iter_free(CfreeDwarfParamIter *it) { + if (!it) + return; it->d->h->free(it->d->h, it, sizeof(*it)); } diff --git a/src/link/link_jit.c b/src/link/link_jit.c @@ -11,8 +11,8 @@ #include <cfree.h> #include <string.h> -#include "core/bytes.h" #include "core/buf.h" +#include "core/bytes.h" #include "core/heap.h" #include "core/metrics.h" #include "core/pool.h" @@ -24,7 +24,7 @@ /* Defined in src/api/pipeline.c — allocates an empty CfreeObjFile with * a private Compiler and an empty ObjBuilder for caller population. */ -CfreeObjFile* cfree_objfile_empty_new(const CfreeEnv* env, CfreeTarget target, +CfreeObjFile *cfree_objfile_empty_new(const CfreeEnv *env, CfreeTarget target, CfreeObjFmt fmt); static SrcLoc no_loc(void) { @@ -32,16 +32,16 @@ static SrcLoc no_loc(void) { return l; } -static const CfreeExecMem* require_execmem(Compiler* c) { - const CfreeExecMem* m = c->env ? c->env->execmem : NULL; +static const CfreeExecMem *require_execmem(Compiler *c) { + const CfreeExecMem *m = c->env ? c->env->execmem : NULL; if (!m || !m->reserve || !m->protect || !m->release) { compiler_panic(c, no_loc(), "cfree_jit: env->execmem is required for JIT"); } return m; } -static u64 jit_page_size(Compiler* c) { - const CfreeExecMem* m = require_execmem(c); +static u64 jit_page_size(Compiler *c) { + const CfreeExecMem *m = require_execmem(c); return m->page_size ? (u64)m->page_size : 0x4000u; } @@ -53,8 +53,8 @@ static u64 jit_page_size(Compiler* c) { * its final perms. No virtual page is ever simultaneously writable and * executable. */ struct CfreeJit { - Compiler* c; - LinkImage* image; + Compiler *c; + LinkImage *image; /* Single contiguous reservation covering every segment. All segments * are sub-ranges of this region — runtime/write aliases are derived * by offsetting against (image-vaddr - image_base). Keeping them @@ -63,16 +63,16 @@ struct CfreeJit { * otherwise depend on the OS placing independent mmap'd segments * close together. */ CfreeExecMemRegion master; - u64 image_base; /* page-aligned image vaddr that maps to master.* */ - CfreeExecMemRegion* segs; /* one per image->nsegments; views into master */ + u64 image_base; /* page-aligned image vaddr that maps to master.* */ + CfreeExecMemRegion *segs; /* one per image->nsegments; views into master */ u32 nsegs; /* DWARF view, lazily constructed on first cfree_jit_view call. Built * over a private Compiler so its string pools and the new ObjBuilder * are owned end-to-end by the view; freed in cfree_jit_free. NULL * means "not yet built"; view_built distinguishes "tried and gave up" * (multi-input v1, etc.) from "untried". */ - CfreeObjFile* view; - Linker* linker; /* kept alive for append-time resolver/input context */ + CfreeObjFile *view; + Linker *linker; /* kept alive for append-time resolver/input context */ u64 append_cursor[SEG_NBUCKETS]; u64 append_limit[SEG_NBUCKETS]; u64 generation; @@ -81,8 +81,8 @@ struct CfreeJit { * borrowed from CfreeEnv (lives across the env's lifetime); `tls_ctx` * is owned by us and freed via tls_vtable->ctx_destroy in * cfree_jit_free. */ - const CfreeJitTls* tls_vtable; - void* tls_ctx; + const CfreeJitTls *tls_vtable; + void *tls_ctx; u8 view_built; u8 pad[7]; }; @@ -103,8 +103,10 @@ static int reloc_is_tlsle(RelocKind k) { static int perms_for(u32 secflags) { int p = CFREE_PROT_READ; - if (secflags & SF_EXEC) p |= CFREE_PROT_EXEC; - if (secflags & SF_WRITE) p |= CFREE_PROT_WRITE; + if (secflags & SF_EXEC) + p |= CFREE_PROT_EXEC; + if (secflags & SF_WRITE) + p |= CFREE_PROT_WRITE; return p; } @@ -116,20 +118,21 @@ static int perms_for(u32 secflags) { * one-past-end boundary (e.g. `__fini_array_end` when .fini_array is * the last section in its segment) still resolve, while preferring an * exact start-of-next-segment match when segments happen to abut. */ -static uintptr_t vaddr_to_runtime(const LinkImage* img, - const CfreeExecMemRegion* segs, u64 vaddr) { +static uintptr_t vaddr_to_runtime(const LinkImage *img, + const CfreeExecMemRegion *segs, u64 vaddr) { u32 i; for (i = 0; i < img->nsegments; ++i) { - const LinkSegment* s = &img->segments[i]; + const LinkSegment *s = &img->segments[i]; u64 lo = s->vaddr; u64 hi = lo + s->mem_size; if (vaddr >= lo && vaddr < hi) return (uintptr_t)segs[i].runtime + (uintptr_t)(vaddr - lo); } for (i = 0; i < img->nsegments; ++i) { - const LinkSegment* s = &img->segments[i]; + const LinkSegment *s = &img->segments[i]; u64 hi = s->vaddr + s->mem_size; - if (vaddr == hi) return (uintptr_t)segs[i].runtime + (uintptr_t)s->mem_size; + if (vaddr == hi) + return (uintptr_t)segs[i].runtime + (uintptr_t)s->mem_size; } return 0; } @@ -138,37 +141,39 @@ static uintptr_t vaddr_to_runtime(const LinkImage* img, * the byte position at which to apply a relocation. The PC-relative * arithmetic in link_reloc_apply uses the runtime address; the bytes * themselves get patched at the matching offset of the write alias. */ -static uintptr_t vaddr_to_write(const LinkImage* img, - const CfreeExecMemRegion* segs, u64 vaddr) { +static uintptr_t vaddr_to_write(const LinkImage *img, + const CfreeExecMemRegion *segs, u64 vaddr) { u32 i; for (i = 0; i < img->nsegments; ++i) { - const LinkSegment* s = &img->segments[i]; + const LinkSegment *s = &img->segments[i]; u64 lo = s->vaddr; u64 hi = lo + s->mem_size; if (vaddr >= lo && vaddr < hi) return (uintptr_t)segs[i].write + (uintptr_t)(vaddr - lo); } for (i = 0; i < img->nsegments; ++i) { - const LinkSegment* s = &img->segments[i]; + const LinkSegment *s = &img->segments[i]; u64 hi = s->vaddr + s->mem_size; - if (vaddr == hi) return (uintptr_t)segs[i].write + (uintptr_t)s->mem_size; + if (vaddr == hi) + return (uintptr_t)segs[i].write + (uintptr_t)s->mem_size; } return 0; } -static void jit_copy_input_section_bytes(LinkImage* img, - const CfreeExecMemRegion* segs) { - Compiler* c = img->c; - Linker* l = img->linker; +static void jit_copy_input_section_bytes(LinkImage *img, + const CfreeExecMemRegion *segs) { + Compiler *c = img->c; + Linker *l = img->linker; u32 i; for (i = 0; i < img->nsections; ++i) { - const LinkSection* ls = &img->sections[i]; - const LinkSegment* seg; - ObjBuilder* ob; - const Section* s; + const LinkSection *ls = &img->sections[i]; + const LinkSegment *seg; + ObjBuilder *ob; + const Section *s; u32 input_idx; - u8* dst; - if (ls->input_id == LINK_INPUT_NONE) continue; + u8 *dst; + if (ls->input_id == LINK_INPUT_NONE) + continue; input_idx = ls->input_id - 1u; if (ls->segment_id == LINK_SEG_NONE || ls->segment_id > img->nsegments) compiler_panic(c, no_loc(), @@ -181,9 +186,11 @@ static void jit_copy_input_section_bytes(LinkImage* img, compiler_panic(c, no_loc(), "cfree_jit_from_image: input section bytes unavailable"); s = obj_section_get(ob, ls->obj_section_id); - if (!s || s->sem == SSEM_NOBITS) continue; - if (s->bytes.total == 0) continue; - dst = (u8*)segs[seg->id - 1u].write + (size_t)(ls->vaddr - seg->vaddr); + if (!s || s->sem == SSEM_NOBITS) + continue; + if (s->bytes.total == 0) + continue; + dst = (u8 *)segs[seg->id - 1u].write + (size_t)(ls->vaddr - seg->vaddr); metrics_count(c, "jit.input_section_bytes", s->bytes.total); buf_flatten(&s->bytes, dst); } @@ -197,11 +204,13 @@ static void jit_copy_input_section_bytes(LinkImage* img, * The +16 reloc gives us the storage symbol's image vaddr; subtracting * img->tls_vaddr yields the per-thread byte offset our thunk adds to the * caller's TLS block on every access. */ -static void jit_patch_tlv_descriptors(CfreeJit* jit) { - LinkImage* img = jit->image; - Compiler* c = jit->c; - if (c->target.obj != CFREE_OBJ_MACHO) return; - if (img->tls_memsz == 0) return; +static void jit_patch_tlv_descriptors(CfreeJit *jit) { + LinkImage *img = jit->image; + Compiler *c = jit->c; + if (c->target.obj != CFREE_OBJ_MACHO) + return; + if (img->tls_memsz == 0) + return; /* Find every LinkSymId whose interned name is __tlv_bootstrap. The * symbol is emitted as a weak-undef per TU (one ObjBuilder appends @@ -213,14 +222,14 @@ static void jit_patch_tlv_descriptors(CfreeJit* jit) { * Bitmap over LinkSymId so the inner reloc test is O(1). */ Sym tlv_name = pool_intern_cstr(c->global, "__tlv_bootstrap"); u32 nsyms = LinkSyms_count(&img->syms); - Heap* h = (Heap*)c->env->heap; - u8* is_tlv_bootstrap = (u8*)h->alloc(h, nsyms + 1u, 1u); + Heap *h = (Heap *)c->env->heap; + u8 *is_tlv_bootstrap = (u8 *)h->alloc(h, nsyms + 1u, 1u); if (!is_tlv_bootstrap) compiler_panic(c, no_loc(), "cfree_jit: oom on tlv-bootstrap bitmap"); memset(is_tlv_bootstrap, 0, nsyms + 1u); int any_tlv = 0; for (u32 si = 0; si < nsyms; ++si) { - LinkSymbol* s = LinkSyms_at(&img->syms, si); + LinkSymbol *s = LinkSyms_at(&img->syms, si); if (s && s->name == tlv_name) { is_tlv_bootstrap[si + 1u] = 1u; any_tlv = 1; @@ -231,7 +240,7 @@ static void jit_patch_tlv_descriptors(CfreeJit* jit) { return; } - const CfreeJitTls* tls = c->env ? c->env->jit_tls : NULL; + const CfreeJitTls *tls = c->env ? c->env->jit_tls : NULL; if (!tls || !tls->ctx_new || !tls->ctx_destroy) compiler_panic(c, no_loc(), "cfree_jit: image needs TLV thunk but env->jit_tls is NULL " @@ -240,15 +249,15 @@ static void jit_patch_tlv_descriptors(CfreeJit* jit) { /* Snapshot the TLS image's init bytes from the write alias. The * write alias of any SF_TLS section stays readable for the lifetime * of CfreeJit; ctx_new is expected to copy what it needs. */ - const u8* init_bytes = NULL; + const u8 *init_bytes = NULL; if (img->tls_filesz) { - init_bytes = (const u8*)vaddr_to_write(img, jit->segs, img->tls_vaddr); + init_bytes = (const u8 *)vaddr_to_write(img, jit->segs, img->tls_vaddr); if (!init_bytes) compiler_panic(c, no_loc(), "cfree_jit: tls_vaddr does not map to any segment"); } size_t align = img->tls_align ? (size_t)img->tls_align : 1u; - void* ctx = tls->ctx_new(tls->user, init_bytes, (size_t)img->tls_filesz, + void *ctx = tls->ctx_new(tls->user, init_bytes, (size_t)img->tls_filesz, (size_t)img->tls_memsz, align); if (!ctx) compiler_panic(c, no_loc(), "cfree_jit: jit_tls->ctx_new returned NULL"); @@ -259,17 +268,19 @@ static void jit_patch_tlv_descriptors(CfreeJit* jit) { uintptr_t thunk_addr = (uintptr_t)&cfree_jit_tlv_thunk; u32 nrel = LinkRelocs_count(&img->relocs); for (u32 i = 0; i < nrel; ++i) { - const LinkRelocApply* r = LinkRelocs_at(&img->relocs, i); - if (r->target == LINK_SYM_NONE || !is_tlv_bootstrap[r->target]) continue; - if (r->kind != R_ABS64) continue; + const LinkRelocApply *r = LinkRelocs_at(&img->relocs, i); + if (r->target == LINK_SYM_NONE || !is_tlv_bootstrap[r->target]) + continue; + if (r->kind != R_ABS64) + continue; u64 desc_vaddr = r->write_vaddr; /* Locate the paired +16 reloc. Quadratic, but reloc counts are * small (one reloc pair per TLV var) so the inner scan amortizes. */ - const LinkRelocApply* r16 = NULL; + const LinkRelocApply *r16 = NULL; for (u32 j = 0; j < nrel; ++j) { - const LinkRelocApply* q = LinkRelocs_at(&img->relocs, j); + const LinkRelocApply *q = LinkRelocs_at(&img->relocs, j); if (q->kind == R_ABS64 && q->write_vaddr == desc_vaddr + 16u) { r16 = q; break; @@ -279,14 +290,13 @@ static void jit_patch_tlv_descriptors(CfreeJit* jit) { compiler_panic(c, no_loc(), "cfree_jit: TLV descriptor missing data-symbol reloc"); - const LinkSymbol* data_sym = LinkSyms_at(&img->syms, r16->target - 1); + const LinkSymbol *data_sym = LinkSyms_at(&img->syms, r16->target - 1); if (!data_sym || !data_sym->defined) compiler_panic(c, no_loc(), "cfree_jit: TLV descriptor data symbol is undefined"); - u64 offset_in_image = - (data_sym->vaddr + (u64)r16->addend) - img->tls_vaddr; + u64 offset_in_image = (data_sym->vaddr + (u64)r16->addend) - img->tls_vaddr; - u8* write = (u8*)vaddr_to_write(img, jit->segs, desc_vaddr); + u8 *write = (u8 *)vaddr_to_write(img, jit->segs, desc_vaddr); if (!write) compiler_panic(c, no_loc(), "cfree_jit: TLV descriptor vaddr does not map"); @@ -298,12 +308,12 @@ static void jit_patch_tlv_descriptors(CfreeJit* jit) { h->free(h, is_tlv_bootstrap, nsyms + 1u); } -CfreeJit* cfree_jit_from_image(LinkImage* img) { - Compiler* c; - Heap* heap; - const CfreeExecMem* mem; - CfreeJit* jit; - CfreeExecMemRegion* segs; +CfreeJit *cfree_jit_from_image(LinkImage *img) { + Compiler *c; + Heap *heap; + const CfreeExecMem *mem; + CfreeJit *jit; + CfreeExecMemRegion *segs; CfreeExecMemRegion master; u64 page; u64 image_base = (u64)-1; @@ -315,7 +325,8 @@ CfreeJit* cfree_jit_from_image(LinkImage* img) { int needs_input_materialize = 0; u32 i; - if (!img) return NULL; + if (!img) + return NULL; c = img->c; heap = img->heap; mem = require_execmem(c); @@ -330,11 +341,14 @@ CfreeJit* cfree_jit_from_image(LinkImage* img) { * align via ALIGN_UP at the page size), so the offset within the * master mapping is (vaddr - image_base). */ for (i = 0; i < img->nsegments; ++i) { - const LinkSegment* seg = &img->segments[i]; + const LinkSegment *seg = &img->segments[i]; u64 hi = ALIGN_UP(seg->vaddr + seg->mem_size, page); - if (seg->vaddr < image_base) image_base = seg->vaddr; - if (hi > image_end) image_end = hi; - if (seg->flags & SF_EXEC) needs_exec = 1; + if (seg->vaddr < image_base) + image_base = seg->vaddr; + if (hi > image_end) + image_end = hi; + if (seg->flags & SF_EXEC) + needs_exec = 1; } if (image_base & (page - 1u)) compiler_panic(c, no_loc(), @@ -352,17 +366,19 @@ CfreeJit* cfree_jit_from_image(LinkImage* img) { * perms are applied via mem->protect on sub-ranges below. */ { int master_prot = CFREE_PROT_READ | CFREE_PROT_WRITE; - if (needs_exec) master_prot |= CFREE_PROT_EXEC; + if (needs_exec) + master_prot |= CFREE_PROT_EXEC; metrics_scope_begin(c, "jit.reserve"); - if (mem->reserve(mem->user, (size_t)master_size, master_prot, &master) != 0) { + if (mem->reserve(mem->user, (size_t)master_size, master_prot, &master) != + 0) { compiler_panic(c, no_loc(), "cfree_jit_from_image: execmem.reserve failed"); } metrics_scope_end(c, "jit.reserve"); } - segs = (CfreeExecMemRegion*)heap->alloc(heap, sizeof(*segs) * img->nsegments, - _Alignof(CfreeExecMemRegion)); + segs = (CfreeExecMemRegion *)heap->alloc(heap, sizeof(*segs) * img->nsegments, + _Alignof(CfreeExecMemRegion)); if (!segs) { mem->release(mem->user, &master); compiler_panic(c, no_loc(), "cfree_jit_from_image: oom on segment table"); @@ -373,11 +389,11 @@ CfreeJit* cfree_jit_from_image(LinkImage* img) { * master reservation owns the underlying mapping and is released in * cfree_jit_free. */ for (i = 0; i < img->nsegments; ++i) { - const LinkSegment* seg = &img->segments[i]; + const LinkSegment *seg = &img->segments[i]; u64 off = seg->vaddr - image_base; size_t mlen = (size_t)ALIGN_UP(seg->mem_size, page); - segs[i].write = (u8*)master.write + off; - segs[i].runtime = (u8*)master.runtime + off; + segs[i].write = (u8 *)master.write + off; + segs[i].runtime = (u8 *)master.runtime + off; segs[i].size = mlen; segs[i].token = NULL; } @@ -388,8 +404,9 @@ CfreeJit* cfree_jit_from_image(LinkImage* img) { * and are materialized directly from input Buf chunks below. */ metrics_scope_begin(c, "jit.copy_segments"); for (i = 0; i < img->nsegments; ++i) { - const LinkSegment* seg = &img->segments[i]; - if (seg->file_size == 0) continue; + const LinkSegment *seg = &img->segments[i]; + if (seg->file_size == 0) + continue; if (!img->segment_bytes[i]) { needs_input_materialize = 1; continue; @@ -399,8 +416,9 @@ CfreeJit* cfree_jit_from_image(LinkImage* img) { } if (needs_input_materialize) { if (!img->linker || !img->linker->jit_mode) - compiler_panic(c, no_loc(), - "cfree_jit_from_image: segment bytes are not materialized"); + compiler_panic( + c, no_loc(), + "cfree_jit_from_image: segment bytes are not materialized"); jit_copy_input_section_bytes(img, segs); } metrics_scope_end(c, "jit.copy_segments"); @@ -409,10 +427,10 @@ CfreeJit* cfree_jit_from_image(LinkImage* img) { * alias; PC-relative arithmetic uses the runtime alias address. */ metrics_scope_begin(c, "jit.apply_relocs"); for (i = 0; i < LinkRelocs_count(&img->relocs); ++i) { - const LinkRelocApply* r = LinkRelocs_at(&img->relocs, i); - const LinkSymbol* tgt = LinkSyms_at(&img->syms, r->target - 1); + const LinkRelocApply *r = LinkRelocs_at(&img->relocs, i); + const LinkSymbol *tgt = LinkSyms_at(&img->syms, r->target - 1); u64 S, P; - u8* P_bytes; + u8 *P_bytes; if (reloc_is_tlsle(r->kind)) { /* TLSLE: S is the TP-relative offset of the target. Both * vaddrs are image-relative, so the runtime alias drops @@ -426,7 +444,7 @@ CfreeJit* cfree_jit_from_image(LinkImage* img) { S = (u64)vaddr_to_runtime(img, segs, tgt->vaddr); } P = (u64)vaddr_to_runtime(img, segs, r->write_vaddr); - P_bytes = (u8*)vaddr_to_write(img, segs, r->write_vaddr); + P_bytes = (u8 *)vaddr_to_write(img, segs, r->write_vaddr); /* Weak-undef target: vaddr is 0, address-of must evaluate to NULL * (§"weak attribute resolves to 0 at link time"). For an AArch64 * ADRP + ADD pair against such a target, the PCREL displacement @@ -483,7 +501,7 @@ CfreeJit* cfree_jit_from_image(LinkImage* img) { * accepts arbitrary [addr,size) inside the reservation. */ metrics_scope_begin(c, "jit.protect"); for (i = 0; i < img->nsegments; ++i) { - const LinkSegment* seg = &img->segments[i]; + const LinkSegment *seg = &img->segments[i]; if (mem->protect(mem->user, segs[i].runtime, segs[i].size, perms_for(seg->flags)) != 0) { mem->release(mem->user, &master); @@ -493,8 +511,8 @@ CfreeJit* cfree_jit_from_image(LinkImage* img) { } } if (append_total) { - void* slack_rt = - (u8*)master.runtime + (uintptr_t)(append_start - image_base); + void *slack_rt = + (u8 *)master.runtime + (uintptr_t)(append_start - image_base); (void)mem->protect(mem->user, slack_rt, (size_t)append_total, CFREE_PROT_NONE); } @@ -505,7 +523,7 @@ CfreeJit* cfree_jit_from_image(LinkImage* img) { if (mem->flush_icache) { metrics_scope_begin(c, "jit.flush_icache"); for (i = 0; i < img->nsegments; ++i) { - const LinkSegment* seg = &img->segments[i]; + const LinkSegment *seg = &img->segments[i]; if (seg->flags & SF_EXEC) mem->flush_icache(mem->user, segs[i].runtime, segs[i].size); } @@ -518,22 +536,22 @@ CfreeJit* cfree_jit_from_image(LinkImage* img) { * runtime address. The iplt stub then loads the slot and tail- * calls the chosen implementation on every invocation. */ if (img->niplt) { - typedef void* (*ResolverFn)(void); + typedef void *(*ResolverFn)(void); for (i = 0; i < img->niplt; ++i) { u64 resolver_vaddr = img->iplt_pairs[2u * i + 0]; u64 slot_vaddr = img->iplt_pairs[2u * i + 1]; uintptr_t resolver_rt = vaddr_to_runtime(img, segs, resolver_vaddr); uintptr_t slot_rt = vaddr_to_runtime(img, segs, slot_vaddr); - void* impl; + void *impl; if (!resolver_rt || !slot_rt) compiler_panic(c, no_loc(), "cfree_jit: iplt vaddr does not map to runtime"); impl = ((ResolverFn)resolver_rt)(); - *(void**)(uintptr_t)slot_rt = impl; + *(void **)(uintptr_t)slot_rt = impl; } } - jit = (CfreeJit*)heap->alloc(heap, sizeof(*jit), _Alignof(CfreeJit)); + jit = (CfreeJit *)heap->alloc(heap, sizeof(*jit), _Alignof(CfreeJit)); if (!jit) { mem->release(mem->user, &master); heap->free(heap, segs, sizeof(*segs) * img->nsegments); @@ -581,14 +599,15 @@ CfreeJit* cfree_jit_from_image(LinkImage* img) { /* Run .init_array constructors in forward order. */ { typedef void (*VoidFn)(void); - void* p_start = cfree_jit_lookup(jit, "__init_array_start"); - void* p_end = cfree_jit_lookup(jit, "__init_array_end"); + void *p_start = cfree_jit_lookup(jit, "__init_array_start"); + void *p_end = cfree_jit_lookup(jit, "__init_array_end"); if (p_start && p_end) { - VoidFn* fn = (VoidFn*)p_start; - VoidFn* end = (VoidFn*)p_end; + VoidFn *fn = (VoidFn *)p_start; + VoidFn *end = (VoidFn *)p_end; metrics_scope_begin(c, "jit.ctors"); for (; fn != end; ++fn) - if (*fn) (*fn)(); + if (*fn) + (*fn)(); metrics_scope_end(c, "jit.ctors"); } } @@ -596,11 +615,12 @@ CfreeJit* cfree_jit_from_image(LinkImage* img) { return jit; } -void cfree_jit_free(CfreeJit* jit) { - Heap* heap; - const CfreeExecMem* mem; - if (!jit) return; - heap = (Heap*)jit->c->env->heap; +void cfree_jit_free(CfreeJit *jit) { + Heap *heap; + const CfreeExecMem *mem; + if (!jit) + return; + heap = (Heap *)jit->c->env->heap; mem = jit->c->env->execmem; /* The debug view (if built) is closed first — it owns a private * Compiler whose pools must be released before the image's @@ -637,24 +657,29 @@ void cfree_jit_free(CfreeJit* jit) { heap->free(heap, jit, sizeof(*jit)); } -void* cfree_jit_lookup(CfreeJit* jit, const char* name) { +void *cfree_jit_lookup(CfreeJit *jit, const char *name) { Sym sym; LinkSymId id; - const LinkSymbol* s; - if (!jit || !name) return NULL; + const LinkSymbol *s; + if (!jit || !name) + return NULL; /* C-symbol mangling lives in obj_format_c_mangle so JIT lookups by * source-level name find the symbol regardless of target format. */ sym = obj_format_c_mangle(jit->c, name); id = symhash_get(&jit->image->globals, sym); - if (id == LINK_SYM_NONE) return NULL; + if (id == LINK_SYM_NONE) + return NULL; s = LinkSyms_at(&jit->image->syms, id - 1); - if (!s) return NULL; - if (!s->defined) return NULL; - if (s->kind == SK_ABS) return (void*)(uintptr_t)s->vaddr; - return (void*)vaddr_to_runtime(jit->image, jit->segs, s->vaddr); + if (!s) + return NULL; + if (!s->defined) + return NULL; + if (s->kind == SK_ABS) + return (void *)(uintptr_t)s->vaddr; + return (void *)vaddr_to_runtime(jit->image, jit->segs, s->vaddr); } -uint64_t cfree_jit_generation(CfreeJit* jit) { +uint64_t cfree_jit_generation(CfreeJit *jit) { return jit ? jit->generation : 0; } @@ -674,24 +699,24 @@ typedef struct JitAppendSec { static int jit_bind_strength(u8 bind) { switch (bind) { - case SB_GLOBAL: - return 3; - case SB_WEAK: - return 2; - case SB_LOCAL: - return 1; - default: - return 0; + case SB_GLOBAL: + return 3; + case SB_WEAK: + return 2; + case SB_LOCAL: + return 1; + default: + return 0; } } -static int jit_obj_sym_is_def(const ObjSym* s) { +static int jit_obj_sym_is_def(const ObjSym *s) { return s && s->kind != SK_UNDEF && (s->kind == SK_ABS || s->kind == SK_COMMON || s->kind == SK_FILE || s->section_id != OBJ_SEC_NONE); } -static int jit_obj_sym_is_spurious_undef(const ObjSym* s) { +static int jit_obj_sym_is_spurious_undef(const ObjSym *s) { return s && s->section_id == OBJ_SEC_NONE && s->kind != SK_ABS && s->kind != SK_COMMON && !s->referenced && (s->bind == SB_GLOBAL || s->bind == SB_WEAK); @@ -699,43 +724,44 @@ static int jit_obj_sym_is_spurious_undef(const ObjSym* s) { static u8 jit_reloc_width_local(RelocKind k) { switch (k) { - case R_ABS64: - case R_REL64: - case R_PC64: - case R_X64_TPOFF64: - return 8; - case R_AARCH64_ABS16: - case R_AARCH64_PREL16: - case R_RV_RVC_BRANCH: - case R_RV_RVC_JUMP: - return 2; - case R_RV_ADD8: - case R_RV_SUB8: - case R_RV_SUB6: - case R_RV_SET6: - case R_RV_SET8: - return 1; - default: - return 4; + case R_ABS64: + case R_REL64: + case R_PC64: + case R_X64_TPOFF64: + return 8; + case R_AARCH64_ABS16: + case R_AARCH64_PREL16: + case R_RV_RVC_BRANCH: + case R_RV_RVC_JUMP: + return 2; + case R_RV_ADD8: + case R_RV_SUB8: + case R_RV_SUB6: + case R_RV_SET6: + case R_RV_SET8: + return 1; + default: + return 4; } } -static InputMap jit_input_map_alloc(CfreeJit* jit, ObjBuilder* ob) { +static InputMap jit_input_map_alloc(CfreeJit *jit, ObjBuilder *ob) { InputMap m; - ObjSymIter* it; + ObjSymIter *it; ObjSymEntry e; u32 nsyms = 0; - Heap* h = jit->image->heap; + Heap *h = jit->image->heap; memset(&m, 0, sizeof(m)); it = obj_symiter_new(ob); - while (obj_symiter_next(it, &e)) ++nsyms; + while (obj_symiter_next(it, &e)) + ++nsyms; obj_symiter_free(it); m.nsym = nsyms + 1u; - m.sym = (LinkSymId*)h->alloc(h, sizeof(*m.sym) * m.nsym, - _Alignof(LinkSymId)); + m.sym = + (LinkSymId *)h->alloc(h, sizeof(*m.sym) * m.nsym, _Alignof(LinkSymId)); m.nsection = obj_section_count(ob); - m.section = (LinkSectionId*)h->alloc(h, sizeof(*m.section) * m.nsection, - _Alignof(LinkSectionId)); + m.section = (LinkSectionId *)h->alloc(h, sizeof(*m.section) * m.nsection, + _Alignof(LinkSectionId)); if (!m.sym || !m.section) compiler_panic(jit->c, no_loc(), "cfree_jit_append_obj: oom on input map"); memset(m.sym, 0, sizeof(*m.sym) * m.nsym); @@ -743,7 +769,7 @@ static InputMap jit_input_map_alloc(CfreeJit* jit, ObjBuilder* ob) { return m; } -static void jit_invalidate_view(CfreeJit* jit) { +static void jit_invalidate_view(CfreeJit *jit) { if (jit->view) { cfree_obj_close(jit->view); jit->view = NULL; @@ -751,12 +777,12 @@ static void jit_invalidate_view(CfreeJit* jit) { jit->view_built = 0u; } -static void jit_apply_one_reloc(CfreeJit* jit, const LinkRelocApply* r) { - LinkImage* img = jit->image; - const LinkSymbol* tgt = LinkSyms_at(&img->syms, r->target - 1); +static void jit_apply_one_reloc(CfreeJit *jit, const LinkRelocApply *r) { + LinkImage *img = jit->image; + const LinkSymbol *tgt = LinkSyms_at(&img->syms, r->target - 1); u64 S; u64 P; - u8* P_bytes; + u8 *P_bytes; if (reloc_is_tlsle(r->kind)) { S = (tgt->vaddr - img->tls_vaddr) + AARCH64_TCB_SIZE; } else if (tgt->kind == SK_ABS) { @@ -765,7 +791,7 @@ static void jit_apply_one_reloc(CfreeJit* jit, const LinkRelocApply* r) { S = (u64)vaddr_to_runtime(img, jit->segs, tgt->vaddr); } P = (u64)vaddr_to_runtime(img, jit->segs, r->write_vaddr); - P_bytes = (u8*)vaddr_to_write(img, jit->segs, r->write_vaddr); + P_bytes = (u8 *)vaddr_to_write(img, jit->segs, r->write_vaddr); if (!P_bytes) compiler_panic(jit->c, no_loc(), "cfree_jit_append_obj: relocation site is unmapped"); @@ -777,7 +803,8 @@ static void jit_apply_one_reloc(CfreeJit* jit, const LinkRelocApply* r) { wr_u32_le(P_bytes, 0xd2800000u | rd); return; } - if (r->kind == R_AARCH64_ADD_ABS_LO12_NC) return; + if (r->kind == R_AARCH64_ADD_ABS_LO12_NC) + return; } if (r->kind == R_AARCH64_TLVP_LOAD_PAGEOFF12) { u64 v = ((u64)S + (u64)r->addend) & 0xfffu; @@ -789,10 +816,10 @@ static void jit_apply_one_reloc(CfreeJit* jit, const LinkRelocApply* r) { link_reloc_apply(jit->c, r->kind, P_bytes, S, r->addend, P); } -static void jit_append_obj_inner(CfreeJit* jit, ObjBuilder* ob) { - LinkImage* img = jit->image; - Heap* h = img->heap; - const CfreeExecMem* mem = require_execmem(jit->c); +static void jit_append_obj_inner(CfreeJit *jit, ObjBuilder *ob) { + LinkImage *img = jit->image; + Heap *h = img->heap; + const CfreeExecMem *mem = require_execmem(jit->c); u64 page = jit_page_size(jit->c); u32 old_nsections = img->nsections; u32 old_nsegments = img->nsegments; @@ -802,17 +829,18 @@ static void jit_append_obj_inner(CfreeJit* jit, ObjBuilder* ob) { u32 old_nrelocs = LinkRelocs_count(&img->relocs); u64 old_cursor[SEG_NBUCKETS]; InputMap m; - JitAppendSec* secs = NULL; + JitAppendSec *secs = NULL; u32 nsecs = 0, sec_cap = 0; u32 obj_sec_count; u64 cursor[SEG_NBUCKETS]; LinkInputId new_input_id; u32 new_input_idx; - ObjSymIter* it; + ObjSymIter *it; ObjSymEntry e; u32 i; - for (i = 0; i < SEG_NBUCKETS; ++i) old_cursor[i] = jit->append_cursor[i]; + for (i = 0; i < SEG_NBUCKETS; ++i) + old_cursor[i] = jit->append_cursor[i]; if (!jit || !ob || !jit->linker || obj_compiler(ob) != jit->c) compiler_panic(jit ? jit->c : NULL, no_loc(), @@ -822,18 +850,19 @@ static void jit_append_obj_inner(CfreeJit* jit, ObjBuilder* ob) { * mutating image-visible state. */ it = obj_symiter_new(ob); while (obj_symiter_next(it, &e)) { - const ObjSym* s = e.sym; - if (jit_obj_sym_is_spurious_undef(s)) continue; + const ObjSym *s = e.sym; + if (jit_obj_sym_is_spurious_undef(s)) + continue; if (jit_obj_sym_is_def(s) && s->name != 0 && (s->bind == SB_GLOBAL || s->bind == SB_WEAK)) { LinkSymId existing = symhash_get(&img->globals, s->name); if (existing != LINK_SYM_NONE) { - LinkSymbol* prev = LinkSyms_at(&img->syms, existing - 1); + LinkSymbol *prev = LinkSyms_at(&img->syms, existing - 1); if (prev && prev->defined && jit_bind_strength((u8)s->bind) == jit_bind_strength(SB_GLOBAL) && jit_bind_strength(prev->bind) == jit_bind_strength(SB_GLOBAL)) { size_t namelen; - const char* nm = pool_str(jit->c->global, s->name, &namelen); + const char *nm = pool_str(jit->c->global, s->name, &namelen); obj_format_demangle_c(jit->c, &nm, &namelen); obj_symiter_free(it); compiler_panic(jit->c, no_loc(), @@ -845,14 +874,15 @@ static void jit_append_obj_inner(CfreeJit* jit, ObjBuilder* ob) { LinkSymId hit = symhash_get(&img->globals, s->name); int ok = 0; if (hit != LINK_SYM_NONE) { - LinkSymbol* def = LinkSyms_at(&img->syms, hit - 1); - if (def && def->defined) ok = 1; + LinkSymbol *def = LinkSyms_at(&img->syms, hit - 1); + if (def && def->defined) + ok = 1; } if (!ok) { - ObjSymIter* it2 = obj_symiter_new(ob); + ObjSymIter *it2 = obj_symiter_new(ob); ObjSymEntry e2; while (obj_symiter_next(it2, &e2)) { - const ObjSym* d = e2.sym; + const ObjSym *d = e2.sym; if (d && d->name == s->name && jit_obj_sym_is_def(d) && (d->bind == SB_GLOBAL || d->bind == SB_WEAK)) { ok = 1; @@ -863,14 +893,16 @@ static void jit_append_obj_inner(CfreeJit* jit, ObjBuilder* ob) { } if (!ok && jit->linker->resolver) { size_t namelen; - const char* nm = pool_str(jit->c->global, s->name, &namelen); + const char *nm = pool_str(jit->c->global, s->name, &namelen); (void)namelen; - if (jit->linker->resolver(jit->linker->resolver_user, nm)) ok = 1; + if (jit->linker->resolver(jit->linker->resolver_user, nm)) + ok = 1; } - if (!ok && s->bind == SB_WEAK) ok = 1; + if (!ok && s->bind == SB_WEAK) + ok = 1; if (!ok) { size_t nlen; - const char* nm = pool_str(jit->c->global, s->name, &nlen); + const char *nm = pool_str(jit->c->global, s->name, &nlen); if (nm && nlen == 15u && memcmp(nm, "__tlv_bootstrap", 15u) == 0) ok = 1; if (!ok) { @@ -887,16 +919,19 @@ static void jit_append_obj_inner(CfreeJit* jit, ObjBuilder* ob) { m = jit_input_map_alloc(jit, ob); obj_sec_count = obj_section_count(ob); - for (i = 0; i < SEG_NBUCKETS; ++i) cursor[i] = jit->append_cursor[i]; + for (i = 0; i < SEG_NBUCKETS; ++i) + cursor[i] = jit->append_cursor[i]; for (i = 1; i < obj_sec_count; ++i) { - const Section* s = obj_section_get(ob, (ObjSecId)i); + const Section *s = obj_section_get(ob, (ObjSecId)i); SegBucket b; u64 size; u64 vaddr; - if (!s || !link_section_kept(s)) continue; + if (!s || !link_section_kept(s)) + continue; size = (s->sem == SSEM_NOBITS) ? (u64)s->bss_size : (u64)s->bytes.total; - if (size == 0) continue; + if (size == 0) + continue; b = link_bucket_for(s->flags); vaddr = ALIGN_UP(cursor[b], (u64)(s->align ? s->align : 1u)); if (vaddr + size > jit->append_limit[b]) @@ -904,10 +939,9 @@ static void jit_append_obj_inner(CfreeJit* jit, ObjBuilder* ob) { "cfree_jit_append_obj: append slack exhausted"); if (nsecs == sec_cap) { u32 ncap = sec_cap ? sec_cap * 2u : 8u; - JitAppendSec* ns = - (JitAppendSec*)h->realloc(h, secs, sizeof(*secs) * sec_cap, - sizeof(*secs) * ncap, - _Alignof(JitAppendSec)); + JitAppendSec *ns = (JitAppendSec *)h->realloc( + h, secs, sizeof(*secs) * sec_cap, sizeof(*secs) * ncap, + _Alignof(JitAppendSec)); if (!ns) compiler_panic(jit->c, no_loc(), "cfree_jit_append_obj: oom on section plan"); @@ -929,24 +963,26 @@ static void jit_append_obj_inner(CfreeJit* jit, ObjBuilder* ob) { cursor[b] = vaddr + size; ++nsecs; } - for (i = 0; i < SEG_NBUCKETS; ++i) jit->append_cursor[i] = cursor[i]; + for (i = 0; i < SEG_NBUCKETS; ++i) + jit->append_cursor[i] = cursor[i]; it = obj_symiter_new(ob); while (obj_symiter_next(it, &e)) { - const ObjSym* s = e.sym; + const ObjSym *s = e.sym; int is_def; - if (e.id >= m.nsym || jit_obj_sym_is_spurious_undef(s)) continue; + if (e.id >= m.nsym || jit_obj_sym_is_spurious_undef(s)) + continue; is_def = jit_obj_sym_is_def(s); if (is_def && (s->bind == SB_GLOBAL || s->bind == SB_WEAK) && s->name != 0) { LinkSymId existing = symhash_get(&img->globals, s->name); if (existing != LINK_SYM_NONE) { - LinkSymbol* prev = LinkSyms_at(&img->syms, existing - 1); + LinkSymbol *prev = LinkSyms_at(&img->syms, existing - 1); if (prev && prev->defined && jit_bind_strength((u8)s->bind) == jit_bind_strength(SB_GLOBAL) && jit_bind_strength(prev->bind) == jit_bind_strength(SB_GLOBAL)) { size_t namelen; - const char* nm = pool_str(jit->c->global, s->name, &namelen); + const char *nm = pool_str(jit->c->global, s->name, &namelen); obj_format_demangle_c(jit->c, &nm, &namelen); obj_symiter_free(it); compiler_panic(jit->c, no_loc(), @@ -1003,14 +1039,16 @@ static void jit_append_obj_inner(CfreeJit* jit, ObjBuilder* ob) { /* Resolve newly appended undefs before any bytes become executable. */ for (i = 0; i < LinkSyms_count(&img->syms); ++i) { - LinkSymbol* s = LinkSyms_at(&img->syms, i); - if (s->input_id != (LinkInputId)(LinkInputs_count(&jit->linker->inputs) + 1u)) + LinkSymbol *s = LinkSyms_at(&img->syms, i); + if (s->input_id != + (LinkInputId)(LinkInputs_count(&jit->linker->inputs) + 1u)) + continue; + if (s->defined) continue; - if (s->defined) continue; if (s->name != 0) { LinkSymId hit = symhash_get(&img->globals, s->name); if (hit != LINK_SYM_NONE && hit != s->id) { - LinkSymbol* def = LinkSyms_at(&img->syms, hit - 1); + LinkSymbol *def = LinkSyms_at(&img->syms, hit - 1); if (def->defined) { s->section_id = def->section_id; s->value = def->value; @@ -1024,8 +1062,8 @@ static void jit_append_obj_inner(CfreeJit* jit, ObjBuilder* ob) { } if (jit->linker->resolver && s->name != 0) { size_t namelen; - const char* nm = pool_str(jit->c->global, s->name, &namelen); - void* p = jit->linker->resolver(jit->linker->resolver_user, nm); + const char *nm = pool_str(jit->c->global, s->name, &namelen); + void *p = jit->linker->resolver(jit->linker->resolver_user, nm); (void)namelen; if (p) { s->kind = SK_ABS; @@ -1042,7 +1080,7 @@ static void jit_append_obj_inner(CfreeJit* jit, ObjBuilder* ob) { } if (s->name != 0) { size_t nlen; - const char* nm = pool_str(jit->c->global, s->name, &nlen); + const char *nm = pool_str(jit->c->global, s->name, &nlen); if (nm && nlen == 15u && memcmp(nm, "__tlv_bootstrap", 15u) == 0) { s->kind = SK_ABS; s->vaddr = 0; @@ -1062,7 +1100,7 @@ static void jit_append_obj_inner(CfreeJit* jit, ObjBuilder* ob) { new_input_idx = new_input_id - 1u; { - InputMap* maps = (InputMap*)h->realloc( + InputMap *maps = (InputMap *)h->realloc( h, img->input_maps, sizeof(*img->input_maps) * img->ninput_maps, sizeof(*img->input_maps) * (new_input_idx + 1u), _Alignof(InputMap)); if (!maps) @@ -1078,26 +1116,25 @@ static void jit_append_obj_inner(CfreeJit* jit, ObjBuilder* ob) { } if (nsecs) { - LinkSection* nsections = (LinkSection*)h->realloc( + LinkSection *nsections = (LinkSection *)h->realloc( h, img->sections, sizeof(*img->sections) * old_nsections, sizeof(*img->sections) * (old_nsections + nsecs), _Alignof(LinkSection)); - LinkSegment* nsegments = (LinkSegment*)h->realloc( + LinkSegment *nsegments = (LinkSegment *)h->realloc( h, img->segments, sizeof(*img->segments) * old_nsegments, sizeof(*img->segments) * (old_nsegments + nsecs), _Alignof(LinkSegment)); - u8** nsegbytes = (u8**)h->realloc( + u8 **nsegbytes = (u8 **)h->realloc( h, img->segment_bytes, sizeof(*img->segment_bytes) * old_nsegments, - sizeof(*img->segment_bytes) * (old_nsegments + nsecs), _Alignof(u8*)); - size_t* nsegcaps = (size_t*)h->realloc( + sizeof(*img->segment_bytes) * (old_nsegments + nsecs), _Alignof(u8 *)); + size_t *nsegcaps = (size_t *)h->realloc( h, img->segment_bytes_cap, sizeof(*img->segment_bytes_cap) * old_nsegments, sizeof(*img->segment_bytes_cap) * (old_nsegments + nsecs), _Alignof(size_t)); - CfreeExecMemRegion* njsegs = (CfreeExecMemRegion*)h->realloc( + CfreeExecMemRegion *njsegs = (CfreeExecMemRegion *)h->realloc( h, jit->segs, sizeof(*jit->segs) * old_nsegs, - sizeof(*jit->segs) * (old_nsegs + nsecs), - _Alignof(CfreeExecMemRegion)); + sizeof(*jit->segs) * (old_nsegs + nsecs), _Alignof(CfreeExecMemRegion)); if (!nsections || !nsegments || !nsegbytes || !nsegcaps || !njsegs) compiler_panic(jit->c, no_loc(), "cfree_jit_append_obj: oom growing image tables"); @@ -1109,13 +1146,11 @@ static void jit_append_obj_inner(CfreeJit* jit, ObjBuilder* ob) { } for (i = 0; i < nsecs; ++i) { - JitAppendSec* ps = &secs[i]; - LinkSection* ls = &img->sections[old_nsections + i]; - LinkSegment* seg = &img->segments[old_nsegments + i]; - CfreeExecMemRegion* js = &jit->segs[old_nsegs + i]; - const Section* os = obj_section_get(ob, ps->obj_sec); - u64 page_lo = ps->vaddr & ~(page - 1u); - u64 page_hi = ALIGN_UP(ps->vaddr + ps->size, page); + JitAppendSec *ps = &secs[i]; + LinkSection *ls = &img->sections[old_nsections + i]; + LinkSegment *seg = &img->segments[old_nsegments + i]; + CfreeExecMemRegion *js = &jit->segs[old_nsegs + i]; + const Section *os = obj_section_get(ob, ps->obj_sec); memset(ls, 0, sizeof(*ls)); ls->id = ps->link_sec; ls->input_id = new_input_id; @@ -1133,9 +1168,12 @@ static void jit_append_obj_inner(CfreeJit* jit, ObjBuilder* ob) { memset(seg, 0, sizeof(*seg)); seg->id = ps->link_seg; seg->flags = SF_ALLOC; - if (ps->bucket == SEG_RX) seg->flags |= SF_EXEC; - if (ps->bucket == SEG_RW) seg->flags |= SF_WRITE; - if (ps->bucket == SEG_TLS) seg->flags |= SF_TLS; + if (ps->bucket == SEG_RX) + seg->flags |= SF_EXEC; + if (ps->bucket == SEG_RW) + seg->flags |= SF_WRITE; + if (ps->bucket == SEG_TLS) + seg->flags |= SF_TLS; seg->file_offset = ps->vaddr; seg->vaddr = ps->vaddr; seg->mem_size = ps->size; @@ -1146,15 +1184,15 @@ static void jit_append_obj_inner(CfreeJit* jit, ObjBuilder* ob) { img->segment_bytes_cap[old_nsegments + i] = 0; memset(js, 0, sizeof(*js)); - js->write = (u8*)jit->master.write + (uintptr_t)(page_lo - jit->image_base); + js->write = + (u8 *)jit->master.write + (uintptr_t)(ps->vaddr - jit->image_base); js->runtime = - (u8*)jit->master.runtime + (uintptr_t)(page_lo - jit->image_base); - js->size = (size_t)(page_hi - page_lo); + (u8 *)jit->master.runtime + (uintptr_t)(ps->vaddr - jit->image_base); + js->size = (size_t)ps->size; js->token = NULL; if (os && os->sem != SSEM_NOBITS && os->bytes.total) { - u8* dst = (u8*)js->write + (uintptr_t)(ps->vaddr - page_lo); - buf_flatten(&os->bytes, dst); + buf_flatten(&os->bytes, (u8 *)js->write); } img->nsections++; img->nsegments++; @@ -1164,14 +1202,15 @@ static void jit_append_obj_inner(CfreeJit* jit, ObjBuilder* ob) { { u32 total = obj_reloc_total(ob); for (i = 0; i < total; ++i) { - const Reloc* r = obj_reloc_at(ob, i); + const Reloc *r = obj_reloc_at(ob, i); LinkRelocApply rec; LinkSectionId ls_id; - const LinkSection* ls; + const LinkSection *ls; if (!r || r->section_id == OBJ_SEC_NONE || r->section_id >= m.nsection) continue; ls_id = m.section[r->section_id]; - if (ls_id == LINK_SEC_NONE) continue; + if (ls_id == LINK_SEC_NONE) + continue; if (r->sym == OBJ_SYM_NONE || r->sym >= m.nsym || m.sym[r->sym] == LINK_SYM_NONE) continue; @@ -1192,13 +1231,17 @@ static void jit_append_obj_inner(CfreeJit* jit, ObjBuilder* ob) { } for (i = old_nrelocs; i < LinkRelocs_count(&img->relocs); ++i) { - const LinkRelocApply* r = LinkRelocs_at(&img->relocs, i); + const LinkRelocApply *r = LinkRelocs_at(&img->relocs, i); jit_apply_one_reloc(jit, r); } for (i = old_nsegs; i < jit->nsegs; ++i) { - const LinkSegment* seg = &img->segments[i]; - if (mem->protect(mem->user, jit->segs[i].runtime, jit->segs[i].size, + const LinkSegment *seg = &img->segments[i]; + u64 page_lo = seg->vaddr & ~(page - 1u); + u64 page_hi = ALIGN_UP(seg->vaddr + seg->mem_size, page); + void *rt = + (u8 *)jit->master.runtime + (uintptr_t)(page_lo - jit->image_base); + if (mem->protect(mem->user, rt, (size_t)(page_hi - page_lo), perms_for(seg->flags)) != 0) { compiler_panic(jit->c, no_loc(), "cfree_jit_append_obj: execmem.protect failed"); @@ -1206,20 +1249,19 @@ static void jit_append_obj_inner(CfreeJit* jit, ObjBuilder* ob) { } if (mem->flush_icache) { for (i = old_nsegs; i < jit->nsegs; ++i) { - const LinkSegment* seg = &img->segments[i]; + const LinkSegment *seg = &img->segments[i]; if (seg->flags & SF_EXEC) mem->flush_icache(mem->user, jit->segs[i].runtime, jit->segs[i].size); } } { - ObjBuilder** nd = (ObjBuilder**)h->realloc( + ObjBuilder **nd = (ObjBuilder **)h->realloc( h, img->dbg_objs, sizeof(*img->dbg_objs) * old_dbg_n, - sizeof(*img->dbg_objs) * (new_input_idx + 1u), _Alignof(ObjBuilder*)); - u8* no = (u8*)h->realloc(h, img->dbg_objs_owned, - sizeof(*img->dbg_objs_owned) * old_dbg_n, - sizeof(*img->dbg_objs_owned) * (new_input_idx + 1u), - 1u); + sizeof(*img->dbg_objs) * (new_input_idx + 1u), _Alignof(ObjBuilder *)); + u8 *no = (u8 *)h->realloc( + h, img->dbg_objs_owned, sizeof(*img->dbg_objs_owned) * old_dbg_n, + sizeof(*img->dbg_objs_owned) * (new_input_idx + 1u), 1u); if (!nd || !no) compiler_panic(jit->c, no_loc(), "cfree_jit_append_obj: oom growing debug inputs"); @@ -1237,15 +1279,17 @@ static void jit_append_obj_inner(CfreeJit* jit, ObjBuilder* ob) { jit_invalidate_view(jit); jit->generation++; - if (secs) h->free(h, secs, sizeof(*secs) * sec_cap); + if (secs) + h->free(h, secs, sizeof(*secs) * sec_cap); (void)old_cursor; (void)old_nmaps; } -int cfree_jit_append_obj(CfreeJit* jit, CfreeObjBuilder* ob) { +int cfree_jit_append_obj(CfreeJit *jit, CfreeObjBuilder *ob) { PanicSave saved; - Compiler* c; - if (!jit || !ob) return 1; + Compiler *c; + if (!jit || !ob) + return 1; c = jit->c; compiler_panic_save(c, &saved); if (setjmp(c->panic)) { @@ -1262,8 +1306,9 @@ int cfree_jit_append_obj(CfreeJit* jit, CfreeObjBuilder* ob) { /* True if `name` (NUL-terminated) is a debug section the DWARF consumer * (src/debug/dwarf_open.c) might read. Everything else is skipped. */ -static int jit_view_is_debug_name(const char* name) { - if (!name) return 0; +static int jit_view_is_debug_name(const char *name) { + if (!name) + return 0; if (name[0] == '.' && name[1] == 'd' && name[2] == 'e' && name[3] == 'b' && name[4] == 'u' && name[5] == 'g' && name[6] == '_') return 1; /* .debug_* */ @@ -1281,21 +1326,25 @@ static int jit_view_is_debug_name(const char* name) { * Cheap walk over the input's section table. Sym values are pool-local, * so name strings must be dereferenced through the input's *own* * compiler pool — not the jit's pool. */ -static int jit_view_input_has_debug(CfreeJit* jit, u32 ii) { - ObjBuilder* ob; - Pool* in_pool; +static int jit_view_input_has_debug(CfreeJit *jit, u32 ii) { + ObjBuilder *ob; + Pool *in_pool; u32 nsec, k; - if (ii >= jit->image->dbg_objs_n) return 0; + if (ii >= jit->image->dbg_objs_n) + return 0; ob = jit->image->dbg_objs[ii]; - if (!ob) return 0; + if (!ob) + return 0; in_pool = obj_compiler(ob)->global; nsec = obj_section_count(ob); for (k = 0; k < nsec; ++k) { - const Section* s = obj_section_get(ob, (ObjSecId)(k + 1)); - const char* nm; - if (!s || !s->name) continue; + const Section *s = obj_section_get(ob, (ObjSecId)(k + 1)); + const char *nm; + if (!s || !s->name) + continue; nm = pool_str(in_pool, s->name, NULL); - if (jit_view_is_debug_name(nm)) return 1; + if (jit_view_is_debug_name(nm)) + return 1; } return 0; } @@ -1305,18 +1354,23 @@ static int jit_view_input_has_debug(CfreeJit* jit, u32 ii) { * image's LinkSyms table. Returns 0 if the symbol is undefined or the * mapping is missing — debug relocations against unresolved symbols * collapse to zero, which is the DWARF "absent" convention. */ -static u64 jit_view_sym_vaddr(CfreeJit* jit, u32 ii, ObjSymId obj_sym) { - const InputMap* m; +static u64 jit_view_sym_vaddr(CfreeJit *jit, u32 ii, ObjSymId obj_sym) { + const InputMap *m; LinkSymId lid; - const LinkSymbol* s; - if (obj_sym == OBJ_SYM_NONE) return 0; - if (ii >= jit->image->ninput_maps) return 0; + const LinkSymbol *s; + if (obj_sym == OBJ_SYM_NONE) + return 0; + if (ii >= jit->image->ninput_maps) + return 0; m = &jit->image->input_maps[ii]; - if (!m->sym || obj_sym >= m->nsym) return 0; + if (!m->sym || obj_sym >= m->nsym) + return 0; lid = m->sym[obj_sym]; - if (lid == LINK_SYM_NONE || lid > LinkSyms_count(&jit->image->syms)) return 0; + if (lid == LINK_SYM_NONE || lid > LinkSyms_count(&jit->image->syms)) + return 0; s = LinkSyms_at(&jit->image->syms, lid - 1); - if (!s || !s->defined) return 0; + if (!s || !s->defined) + return 0; return s->vaddr; /* image-relative — what DWARF was emitted in */ } @@ -1334,37 +1388,39 @@ typedef struct ViewSec { } ViewSec; /* Find-or-create a ViewSec entry by debug-section name. */ -static ViewSec* view_sec_for(CfreeJit* jit, ViewSec* tab, u32* ntab, - u32* cap_inout, const char* name, u16 flags, - u32 align, u32 entsize, ObjBuilder* view_ob, - ViewSec** tab_out) { - Heap* h = (Heap*)jit->c->env->heap; - Pool* view_pool = obj_compiler(view_ob)->global; +static ViewSec *view_sec_for(CfreeJit *jit, ViewSec *tab, u32 *ntab, + u32 *cap_inout, const char *name, u16 flags, + u32 align, u32 entsize, ObjBuilder *view_ob, + ViewSec **tab_out) { + Heap *h = (Heap *)jit->c->env->heap; + Pool *view_pool = obj_compiler(view_ob)->global; Sym vn = pool_intern_cstr(view_pool, name); u32 i; for (i = 0; i < *ntab; ++i) { if (tab[i].view_name == vn) { - if (tab_out) *tab_out = tab; + if (tab_out) + *tab_out = tab; return &tab[i]; } } if (*ntab == *cap_inout) { u32 ncap = *cap_inout ? *cap_inout * 2u : 4u; - ViewSec* na = (ViewSec*)h->realloc(h, tab, *cap_inout * sizeof(*tab), - ncap * sizeof(*tab), _Alignof(ViewSec)); - if (!na) return NULL; + ViewSec *na = (ViewSec *)h->realloc(h, tab, *cap_inout * sizeof(*tab), + ncap * sizeof(*tab), _Alignof(ViewSec)); + if (!na) + return NULL; tab = na; *cap_inout = ncap; - if (tab_out) *tab_out = tab; + if (tab_out) + *tab_out = tab; } else if (tab_out) { *tab_out = tab; } { - ViewSec* slot = &tab[(*ntab)++]; + ViewSec *slot = &tab[(*ntab)++]; slot->view_name = vn; - slot->view_id = - obj_section_ex(view_ob, vn, SEC_DEBUG, SSEM_PROGBITS, flags, - align ? align : 1u, entsize, 0, 0); + slot->view_id = obj_section_ex(view_ob, vn, SEC_DEBUG, SSEM_PROGBITS, flags, + align ? align : 1u, entsize, 0, 0); slot->cur_size = 0; slot->snap = 0; return slot; @@ -1372,10 +1428,11 @@ static ViewSec* view_sec_for(CfreeJit* jit, ViewSec* tab, u32* ntab, } /* Find a ViewSec by view-pool name (no creation). Returns NULL on miss. */ -static ViewSec* view_sec_find(ViewSec* tab, u32 ntab, Sym view_name) { +static ViewSec *view_sec_find(ViewSec *tab, u32 ntab, Sym view_name) { u32 i; for (i = 0; i < ntab; ++i) - if (tab[i].view_name == view_name) return &tab[i]; + if (tab[i].view_name == view_name) + return &tab[i]; return NULL; } @@ -1387,52 +1444,57 @@ static ViewSec* view_sec_find(ViewSec* tab, u32 ntab, Sym view_name) { * `tab` is the find-or-create table of view sections, keyed by name; * snapshots taken at the start of this input are read from it via * view_sec_find. */ -static void jit_view_copy_debug_section(CfreeJit* jit, u32 ii, - ObjSecId in_sec_id, ObjBuilder* view_ob, - ViewSec* tab, u32 ntab, - ViewSec* out_vs) { - ObjBuilder* in_ob = jit->image->dbg_objs[ii]; - const Section* in_sec = obj_section_get(in_ob, in_sec_id); - Pool* in_pool; - Pool* view_pool = obj_compiler(view_ob)->global; - Heap* h; +static void jit_view_copy_debug_section(CfreeJit *jit, u32 ii, + ObjSecId in_sec_id, ObjBuilder *view_ob, + ViewSec *tab, u32 ntab, + ViewSec *out_vs) { + ObjBuilder *in_ob = jit->image->dbg_objs[ii]; + const Section *in_sec = obj_section_get(in_ob, in_sec_id); + Pool *in_pool; + Pool *view_pool = obj_compiler(view_ob)->global; + Heap *h; u32 nbytes, k, total_relocs; - u8* bytes; - if (!in_sec) return; + u8 *bytes; + if (!in_sec) + return; nbytes = in_sec->bytes.total; - if (nbytes == 0) return; + if (nbytes == 0) + return; in_pool = obj_compiler(in_ob)->global; - h = (Heap*)jit->c->env->heap; + h = (Heap *)jit->c->env->heap; (void)in_pool; - bytes = (u8*)h->alloc(h, nbytes, 1); - if (!bytes) return; + bytes = (u8 *)h->alloc(h, nbytes, 1); + if (!bytes) + return; buf_flatten(&in_sec->bytes, bytes); /* Apply this section's relocations in place. obj_reloc_at returns * all relocations across the input; filter by section_id. */ total_relocs = obj_reloc_total(in_ob); for (k = 0; k < total_relocs; ++k) { - const Reloc* r = obj_reloc_at(in_ob, k); + const Reloc *r = obj_reloc_at(in_ob, k); u64 S = 0; int handled = 0; - if (!r || r->section_id != in_sec_id) continue; - if (r->offset >= nbytes) continue; /* malformed; skip */ + if (!r || r->section_id != in_sec_id) + continue; + if (r->offset >= nbytes) + continue; /* malformed; skip */ /* SK_SECTION target → resolve against the per-input snapshot of the * matching view section's prefix size. This is what makes the * concatenated multi-input view's cross-section offsets land in * the right slot. */ if (r->sym != OBJ_SYM_NONE) { - const ObjSym* ts = obj_symbol_get(in_ob, r->sym); + const ObjSym *ts = obj_symbol_get(in_ob, r->sym); if (ts && ts->kind == SK_SECTION && ts->section_id != OBJ_SEC_NONE) { - const Section* tsec = obj_section_get(in_ob, ts->section_id); + const Section *tsec = obj_section_get(in_ob, ts->section_id); if (tsec && tsec->kind == SEC_DEBUG && tsec->name) { size_t tnlen = 0; - const char* tnm = pool_str(obj_compiler(in_ob)->global, tsec->name, - &tnlen); + const char *tnm = + pool_str(obj_compiler(in_ob)->global, tsec->name, &tnlen); if (tnm) { Sym v_tn = pool_intern(view_pool, tnm, tnlen); - ViewSec* tgt = view_sec_find(tab, ntab, v_tn); + ViewSec *tgt = view_sec_find(tab, ntab, v_tn); if (tgt) { S = (u64)tgt->snap; handled = 1; @@ -1441,7 +1503,8 @@ static void jit_view_copy_debug_section(CfreeJit* jit, u32 ii, } } } - if (!handled) S = jit_view_sym_vaddr(jit, ii, r->sym); + if (!handled) + S = jit_view_sym_vaddr(jit, ii, r->sym); /* P is unused by ABS kinds; PC-relative debug-section relocs are * not produced by cfree's debug emitter, but if some external .o * carried one against a debug section, P=0 would give a @@ -1461,86 +1524,100 @@ static void jit_view_copy_debug_section(CfreeJit* jit, u32 ii, * sections. SK_SECTION relocations are resolved against the view-side * prefix length snapshotted at the start of each input, so the merged * CU2/CU3/... cross-section offsets land in the right slot. */ -static CfreeObjFile* jit_view_build(CfreeJit* jit) { - CfreeObjFile* view; - ObjBuilder* view_ob; - ViewSec* tab = NULL; +static CfreeObjFile *jit_view_build(CfreeJit *jit) { + CfreeObjFile *view; + ObjBuilder *view_ob; + ViewSec *tab = NULL; u32 ntab = 0, cap = 0; - Heap* h; + Heap *h; u32 ii, k; int any = 0; - if (!jit->image || jit->image->dbg_objs_n == 0) return NULL; + if (!jit->image || jit->image->dbg_objs_n == 0) + return NULL; for (ii = 0; ii < jit->image->dbg_objs_n; ++ii) { if (jit_view_input_has_debug(jit, ii)) { any = 1; break; } } - if (!any) return NULL; + if (!any) + return NULL; view = cfree_objfile_empty_new(jit->c->env, jit->c->target, jit->c->target.obj); - if (!view) return NULL; + if (!view) + return NULL; view_ob = cfree_obj_builder(view); if (!view_ob) { cfree_obj_close(view); return NULL; } - h = (Heap*)jit->c->env->heap; + h = (Heap *)jit->c->env->heap; for (ii = 0; ii < jit->image->dbg_objs_n; ++ii) { - ObjBuilder* in_ob; + ObjBuilder *in_ob; u32 nsec; - if (!jit_view_input_has_debug(jit, ii)) continue; + if (!jit_view_input_has_debug(jit, ii)) + continue; in_ob = jit->image->dbg_objs[ii]; /* Phase A: find-or-create every debug section this input contributes * to, and snapshot cur_size as the per-input prefix. */ nsec = obj_section_count(in_ob); for (k = 0; k < nsec; ++k) { - const Section* s = obj_section_get(in_ob, (ObjSecId)(k + 1)); - const char* nm; + const Section *s = obj_section_get(in_ob, (ObjSecId)(k + 1)); + const char *nm; size_t nlen = 0; - ViewSec* vs; - if (!s || !s->name) continue; + ViewSec *vs; + if (!s || !s->name) + continue; nm = pool_str(obj_compiler(in_ob)->global, s->name, &nlen); - if (!nm || !jit_view_is_debug_name(nm)) continue; + if (!nm || !jit_view_is_debug_name(nm)) + continue; vs = view_sec_for(jit, tab, &ntab, &cap, nm, s->flags, s->align ? s->align : 1u, s->entsize, view_ob, &tab); - if (!vs) continue; + if (!vs) + continue; } - for (k = 0; k < ntab; ++k) tab[k].snap = tab[k].cur_size; + for (k = 0; k < ntab; ++k) + tab[k].snap = tab[k].cur_size; /* Phase B: copy each debug section + apply relocs. cur_size grows * as bytes get appended; SK_SECTION resolution always reads `snap` * (the start-of-input snapshot), so intra-input references inside * any debug section still land in this input's slice. */ for (k = 0; k < nsec; ++k) { - const Section* s = obj_section_get(in_ob, (ObjSecId)(k + 1)); - const char* nm; + const Section *s = obj_section_get(in_ob, (ObjSecId)(k + 1)); + const char *nm; size_t nlen = 0; Sym v_nm; - ViewSec* vs; - if (!s || !s->name) continue; + ViewSec *vs; + if (!s || !s->name) + continue; nm = pool_str(obj_compiler(in_ob)->global, s->name, &nlen); - if (!nm || !jit_view_is_debug_name(nm)) continue; + if (!nm || !jit_view_is_debug_name(nm)) + continue; v_nm = pool_intern(obj_compiler(view_ob)->global, nm, nlen); vs = view_sec_find(tab, ntab, v_nm); - if (!vs) continue; + if (!vs) + continue; jit_view_copy_debug_section(jit, ii, (ObjSecId)(k + 1), view_ob, tab, ntab, vs); } } - if (tab) h->free(h, tab, sizeof(*tab) * cap); + if (tab) + h->free(h, tab, sizeof(*tab) * cap); obj_finalize(view_ob); return view; } -const CfreeObjFile* cfree_jit_view(CfreeJit* jit) { - if (!jit) return NULL; - if (jit->view_built) return jit->view; +const CfreeObjFile *cfree_jit_view(CfreeJit *jit) { + if (!jit) + return NULL; + if (jit->view_built) + return jit->view; jit->view = jit_view_build(jit); jit->view_built = 1u; return jit->view; @@ -1557,37 +1634,45 @@ static int jit_sym_kind_visible(u8 k) { /* Resolve a LinkSymbol's interned name to a stable C string, stripping * the target format's C-mangling prefix (Mach-O's leading `_`) so the * user sees the source-level name. */ -static const char* jit_sym_name_cstr(CfreeJit* jit, const LinkSymbol* s) { +static const char *jit_sym_name_cstr(CfreeJit *jit, const LinkSymbol *s) { size_t len = 0; - const char* nm = pool_str(jit->c->global, s->name, &len); - if (!nm) return NULL; + const char *nm = pool_str(jit->c->global, s->name, &len); + if (!nm) + return NULL; obj_format_demangle_c(jit->c, &nm, &len); return nm; } -static uint64_t jit_sym_runtime_addr(CfreeJit* jit, const LinkSymbol* s) { - if (s->kind == SK_ABS) return s->vaddr; +static uint64_t jit_sym_runtime_addr(CfreeJit *jit, const LinkSymbol *s) { + if (s->kind == SK_ABS) + return s->vaddr; return (uint64_t)vaddr_to_runtime(jit->image, jit->segs, s->vaddr); } -int cfree_jit_addr_to_sym(CfreeJit* jit, uint64_t addr, const char** name_out, - uint64_t* off_out) { +int cfree_jit_addr_to_sym(CfreeJit *jit, uint64_t addr, const char **name_out, + uint64_t *off_out) { u32 n; u32 i; - const LinkSymbol* best = NULL; + const LinkSymbol *best = NULL; uint64_t best_base = 0; uint64_t best_off = (uint64_t)-1; - if (name_out) *name_out = NULL; - if (off_out) *off_out = 0; - if (!jit) return 1; + if (name_out) + *name_out = NULL; + if (off_out) + *off_out = 0; + if (!jit) + return 1; n = LinkSyms_count(&jit->image->syms); for (i = 0; i < n; ++i) { - LinkSymbol* s = LinkSyms_at(&jit->image->syms, i); + LinkSymbol *s = LinkSyms_at(&jit->image->syms, i); uint64_t base; - if (!s || !s->defined) continue; - if (!jit_sym_kind_visible(s->kind)) continue; + if (!s || !s->defined) + continue; + if (!jit_sym_kind_visible(s->kind)) + continue; base = jit_sym_runtime_addr(jit, s); - if (!base) continue; + if (!base) + continue; if (addr >= base && (s->size == 0 || addr < base + s->size)) { uint64_t off = addr - base; if (off < best_off || @@ -1599,38 +1684,45 @@ int cfree_jit_addr_to_sym(CfreeJit* jit, uint64_t addr, const char** name_out, } } if (best) { - if (name_out) *name_out = jit_sym_name_cstr(jit, best); - if (off_out) *off_out = addr - best_base; + if (name_out) + *name_out = jit_sym_name_cstr(jit, best); + if (off_out) + *off_out = addr - best_base; return 0; } return 1; } struct CfreeJitSymIter { - CfreeJit* jit; + CfreeJit *jit; u32 next; }; -CfreeJitSymIter* cfree_jit_sym_iter_new(CfreeJit* jit) { - Heap* h; - CfreeJitSymIter* it; - if (!jit) return NULL; - h = (Heap*)jit->c->env->heap; - it = (CfreeJitSymIter*)h->alloc(h, sizeof(*it), _Alignof(CfreeJitSymIter)); - if (!it) return NULL; +CfreeJitSymIter *cfree_jit_sym_iter_new(CfreeJit *jit) { + Heap *h; + CfreeJitSymIter *it; + if (!jit) + return NULL; + h = (Heap *)jit->c->env->heap; + it = (CfreeJitSymIter *)h->alloc(h, sizeof(*it), _Alignof(CfreeJitSymIter)); + if (!it) + return NULL; it->jit = jit; it->next = 0; return it; } -int cfree_jit_sym_iter_next(CfreeJitSymIter* it, CfreeJitSym* out) { +int cfree_jit_sym_iter_next(CfreeJitSymIter *it, CfreeJitSym *out) { u32 n; - if (!it || !out) return 0; + if (!it || !out) + return 0; n = LinkSyms_count(&it->jit->image->syms); while (it->next < n) { - LinkSymbol* s = LinkSyms_at(&it->jit->image->syms, it->next++); - if (!s || !s->defined) continue; - if (!jit_sym_kind_visible(s->kind)) continue; + LinkSymbol *s = LinkSyms_at(&it->jit->image->syms, it->next++); + if (!s || !s->defined) + continue; + if (!jit_sym_kind_visible(s->kind)) + continue; out->name = jit_sym_name_cstr(it->jit, s); out->addr = jit_sym_runtime_addr(it->jit, s); out->size = s->size; @@ -1640,10 +1732,11 @@ int cfree_jit_sym_iter_next(CfreeJitSymIter* it, CfreeJitSym* out) { return 0; } -void cfree_jit_sym_iter_free(CfreeJitSymIter* it) { - Heap* h; - if (!it) return; - h = (Heap*)it->jit->c->env->heap; +void cfree_jit_sym_iter_free(CfreeJitSymIter *it) { + Heap *h; + if (!it) + return; + h = (Heap *)it->jit->c->env->heap; h->free(h, it, sizeof(*it)); } @@ -1654,15 +1747,17 @@ void cfree_jit_sym_iter_free(CfreeJitSymIter* it) { * reject breakpoint and read/write requests pointing outside the code * region) and a way to read the image's target arch. These accessors give * it just that, without exporting the segment table or the LinkImage. */ -int cfree_jit_image_contains(CfreeJit* jit, uint64_t runtime_addr) { +int cfree_jit_image_contains(CfreeJit *jit, uint64_t runtime_addr) { u32 i; uintptr_t a; - if (!jit || !jit->segs) return 0; + if (!jit || !jit->segs) + return 0; a = (uintptr_t)runtime_addr; for (i = 0; i < jit->nsegs; ++i) { uintptr_t lo = (uintptr_t)jit->segs[i].runtime; uintptr_t hi = lo + (uintptr_t)jit->segs[i].size; - if (a >= lo && a < hi) return 1; + if (a >= lo && a < hi) + return 1; } return 0; } @@ -1672,57 +1767,62 @@ int cfree_jit_image_contains(CfreeJit* jit, uint64_t runtime_addr) { * driver can cross the boundary at every DWARF call. Walks the * segment table (at most a handful of entries) so callers can do this * per stop without measurable cost. */ -uint64_t cfree_jit_runtime_to_image(CfreeJit* jit, uint64_t runtime_pc) { +uint64_t cfree_jit_runtime_to_image(CfreeJit *jit, uint64_t runtime_pc) { u32 i; uintptr_t a; - if (!jit || !jit->segs) return 0; + if (!jit || !jit->segs) + return 0; a = (uintptr_t)runtime_pc; for (i = 0; i < jit->nsegs; ++i) { uintptr_t lo = (uintptr_t)jit->segs[i].runtime; uintptr_t hi = lo + (uintptr_t)jit->segs[i].size; if (a >= lo && a < hi) { - const LinkSegment* s = &jit->image->segments[i]; + const LinkSegment *s = &jit->image->segments[i]; return s->vaddr + (uint64_t)(a - lo); } } /* One-past-end: lets a return-address that sits exactly at a * segment's end-boundary still round-trip. */ for (i = 0; i < jit->nsegs; ++i) { - uintptr_t hi = (uintptr_t)jit->segs[i].runtime + (uintptr_t)jit->segs[i].size; + uintptr_t hi = + (uintptr_t)jit->segs[i].runtime + (uintptr_t)jit->segs[i].size; if (a == hi) { - const LinkSegment* s = &jit->image->segments[i]; + const LinkSegment *s = &jit->image->segments[i]; return s->vaddr + s->mem_size; } } return 0; } -uint64_t cfree_jit_image_to_runtime(CfreeJit* jit, uint64_t image_vaddr) { +uint64_t cfree_jit_image_to_runtime(CfreeJit *jit, uint64_t image_vaddr) { uintptr_t rt; - if (!jit || !jit->segs) return 0; + if (!jit || !jit->segs) + return 0; rt = vaddr_to_runtime(jit->image, jit->segs, image_vaddr); return (uint64_t)rt; } -CfreeArchKind cfree_jit_image_arch(CfreeJit* jit) { +CfreeArchKind cfree_jit_image_arch(CfreeJit *jit) { return jit->c->target.arch; } -Compiler* cfree_jit_compiler(CfreeJit* jit) { return jit->c; } +Compiler *cfree_jit_compiler(CfreeJit *jit) { return jit->c; } -void cfree_jit_run_dtors(CfreeJit* jit) { +void cfree_jit_run_dtors(CfreeJit *jit) { typedef void (*VoidFn)(void); - void* p_start; - void* p_end; - if (!jit) return; + void *p_start; + void *p_end; + if (!jit) + return; p_start = cfree_jit_lookup(jit, "__fini_array_start"); p_end = cfree_jit_lookup(jit, "__fini_array_end"); if (p_start && p_end) { - VoidFn* begin = (VoidFn*)p_start; - VoidFn* fn = (VoidFn*)p_end; + VoidFn *begin = (VoidFn *)p_start; + VoidFn *fn = (VoidFn *)p_end; while (fn != begin) { --fn; - if (*fn) (*fn)(); + if (*fn) + (*fn)(); } } }