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:
| M | driver/dbg.c | | | 1639 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------- |
| M | driver/driver.h | | | 107 | ++++++++++++++++++++++++++++++++++++++++++------------------------------------- |
| M | driver/env.c | | | 738 | +++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------- |
| M | driver/inputs.c | | | 98 | ++++++++++++++++++++++++++++++++++++++++++++++--------------------------------- |
| M | driver/inputs.h | | | 36 | +++++++++++++++++------------------- |
| M | include/cfree.h | | | 593 | ++++++++++++++++++++++++++++++++++++++++--------------------------------------- |
| M | src/api/cg.c | | | 2501 | ++++++++++++++++++++++++++++++++++++++++++++++--------------------------------- |
| M | src/arch/aa64/emit.c | | | 159 | ++++++++++++++++++++++++++++++++++++++++++++----------------------------------- |
| M | src/arch/rv64/emit.c | | | 79 | +++++++++++++++++++++++++++++++++++++++++++++++-------------------------------- |
| M | src/arch/rv64/internal.h | | | 97 | +++++++++++++++++++++++++++++++++++++++++-------------------------------------- |
| M | src/arch/x64/emit.c | | | 256 | +++++++++++++++++++++++++++++++++++++++++++++++-------------------------------- |
| M | src/arch/x64/internal.h | | | 131 | ++++++++++++++++++++++++++++++++++++++++--------------------------------------- |
| M | src/debug/debug_emit.c | | | 578 | ++++++++++++++++++++++++++++++++++++++++++------------------------------------- |
| M | src/debug/dwarf_die.c | | | 314 | ++++++++++++++++++++++++++++++++++++++++++------------------------------------- |
| M | src/debug/dwarf_internal.h | | | 176 | ++++++++++++++++++++++++++++++++++++++++--------------------------------------- |
| M | src/debug/dwarf_query.c | | | 436 | +++++++++++++++++++++++++++++++++++++++++++++++++------------------------------ |
| M | src/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, ¶m)) {
+ 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, "ed_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, ®s, &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)();
}
}
}