aboutsummaryrefslogtreecommitdiff
path: root/include/ccdjit.h
diff options
context:
space:
mode:
authorDavid Moc <personal@cdatgoose.org>2026-06-02 13:50:21 +0200
committerDavid Moc <personal@cdatgoose.org>2026-06-02 13:50:21 +0200
commita15cb041654ae307add0b998b526c87c3f42bf5f (patch)
tree225bb4b70e9fa05aa5f4d2722a1a9cf5fc6fca7f /include/ccdjit.h
parent6aeaa171dc1ca43392f53cbd02097f76e1b1c5a0 (diff)
Add plugin hooks and mode plugins
Diffstat (limited to 'include/ccdjit.h')
-rw-r--r--include/ccdjit.h262
1 files changed, 256 insertions, 6 deletions
diff --git a/include/ccdjit.h b/include/ccdjit.h
index f8a212b..7999125 100644
--- a/include/ccdjit.h
+++ b/include/ccdjit.h
@@ -33,26 +33,48 @@
* Function pointers returned by ccdjit_module_symbol() are invalid after
* ccdjit_module_free().
*
+ * Runtime policy:
+ * Module calls, symbol lookup, and emission intentionally consult the
+ * current context options, sandbox settings, resource limits, registered
+ * symbols, resolver callback, and loaded libraries. Machine code that
+ * has already been compiled may contain resolved external addresses; use
+ * a new module or function-handle replacement when changing symbol
+ * bindings must affect already compiled call sites.
+ *
* Threads:
- * Independent contexts may compile and run from different threads. Do
- * not mutate or use the same context or module concurrently from multiple
- * threads unless the host provides its own synchronization.
+ * Public API entry points are internally serialized, and module calls,
+ * symbol lookup, emission, and lazy compilation take a module lock. Raw
+ * function pointers returned by ccdjit_module_symbol() are still host
+ * pointers: do not free or replace their module while those pointers may
+ * run, and prefer typed handle/call helpers for dynamic bindings.
*
* Safety:
* Normal calls run in the host process. Set sandbox_execution to
* CCDJIT_SANDBOX_PROCESS to run ccdjit_module_call_main() in a child
- * process with optional resource, syscall, and filesystem limits.
+ * process with optional resource, syscall, and filesystem limits. Child
+ * crashes are reported through ccdjit_diagnostic.
*/
#include <stddef.h>
+#include <stdint.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
+#define CCDJIT_VERSION_MAJOR 1
+#define CCDJIT_VERSION_MINOR 0
+#define CCDJIT_VERSION_PATCH 0
+#define CCDJIT_VERSION_STRING "1.0.0"
+#define CCDJIT_API_ABI_VERSION 1
+#define CCDJITB2_FORMAT_VERSION 2
+#define CCDJITB2_FLAG_DEBUG_INFO 1u
+
typedef struct ccdjit_context ccdjit_context;
typedef struct ccdjit_module ccdjit_module;
+typedef struct ccdjit_function_handle ccdjit_function_handle;
+typedef struct ccdjit_execution_result ccdjit_execution_result;
typedef struct {
/* Host compiler or linker driver. NULL uses $CC, then cc. */
@@ -64,6 +86,12 @@ typedef struct {
/* Print the host linker command to stderr when nonzero. */
int verbose;
+
+ /* Wall-clock driver timeout. Zero uses the default. */
+ unsigned int timeout_ms;
+
+ /* Captured driver stdout/stderr cap. Zero uses the default. */
+ size_t output_limit_bytes;
} ccdjit_link_options;
/*
@@ -158,6 +186,9 @@ typedef struct {
*/
size_t sandbox_output_limit_bytes;
+ /* Emit and retain optional debug/source mapping metadata. */
+ int debug_info;
+
/*
* Preprocessor output byte cap. Zero uses the default currently 128
* MiB.
@@ -169,6 +200,18 @@ typedef struct {
/* Nested include cap. Zero uses the default. */
unsigned int preprocessor_include_depth_limit;
+
+ /*
+ * Optional compiler driver used for host system include and builtin
+ * macro probes. NULL auto-detects from $CC, then common cc drivers.
+ */
+ const char *preprocessor_compiler;
+
+ /* Wall-clock timeout for one compiler probe. Zero uses the default. */
+ unsigned int preprocessor_probe_timeout_ms;
+
+ /* Captured compiler-probe output cap. Zero uses the default. */
+ size_t preprocessor_probe_output_limit_bytes;
} ccdjit_options;
typedef struct {
@@ -189,18 +232,114 @@ typedef struct {
int line;
int column;
+ /* ccdjit_diagnostic_code plus optional code-specific detail. */
+ int code;
+ int subcode;
+
/* Raw child wait status or errno-style value for sandbox/API failures.
*/
int status;
/* Signal that terminated the sandbox child, or zero. */
int signal_number;
+
+ /* Faulting address for sandboxed crash diagnostics, when available. */
+ int has_fault_address;
+ uintptr_t fault_address;
} ccdjit_diagnostic;
-/* Create a compiler context. Passing NULL uses permissive CLI-like defaults.
+typedef enum {
+ CCDJIT_DIAG_NONE = 0,
+ CCDJIT_DIAG_LEXER = 1,
+ CCDJIT_DIAG_PARSER = 2,
+ CCDJIT_DIAG_PREPROCESSOR = 3,
+ CCDJIT_DIAG_TYPE = 4,
+ CCDJIT_DIAG_JIT = 5,
+ CCDJIT_DIAG_UNRESOLVED_SYMBOL = 6,
+ CCDJIT_DIAG_SANDBOX = 7,
+ CCDJIT_DIAG_SANDBOX_TIMEOUT = 8,
+ CCDJIT_DIAG_SANDBOX_FORBIDDEN_SYSCALL = 9,
+ CCDJIT_DIAG_SANDBOX_CRASH = 10,
+ CCDJIT_DIAG_INVALID_OPTIONS = 11,
+ CCDJIT_DIAG_INVALID_ARGUMENT = 12,
+ CCDJIT_DIAG_UNSUPPORTED_ABI = 13,
+ CCDJIT_DIAG_MALFORMED_BINARY = 14,
+ CCDJIT_DIAG_HOST_LINKER = 15,
+ CCDJIT_DIAG_OUT_OF_MEMORY = 16,
+} ccdjit_diagnostic_code;
+
+typedef enum {
+ CCDJIT_SYMBOL_UNKNOWN = 0,
+ CCDJIT_SYMBOL_FUNCTION = 1,
+ CCDJIT_SYMBOL_OBJECT = 2,
+} ccdjit_symbol_kind;
+
+typedef enum {
+ CCDJIT_TYPE_INT = 0,
+ CCDJIT_TYPE_CHAR = 1,
+ CCDJIT_TYPE_BOOL = 2,
+ CCDJIT_TYPE_VOID = 3,
+ CCDJIT_TYPE_FLOAT = 4,
+ CCDJIT_TYPE_DOUBLE = 5,
+ CCDJIT_TYPE_LONG = 6,
+ CCDJIT_TYPE_SHORT = 7,
+ CCDJIT_TYPE_STRUCT = 8,
+ CCDJIT_TYPE_ENUM = 9,
+ CCDJIT_TYPE_UNION = 10,
+ CCDJIT_TYPE_FLOAT128 = 11,
+} ccdjit_type_base;
+
+typedef struct {
+ int has_type;
+ int base;
+ int pointer_level;
+ int array_size;
+ int is_unsigned;
+ int is_complex;
+ int is_atomic;
+} ccdjit_type_info;
+
+typedef struct {
+ int kind;
+ int has_signature;
+ ccdjit_type_info type;
+ ccdjit_type_info return_type;
+ size_t parameter_count;
+ int is_variadic;
+ size_t size;
+} ccdjit_symbol_info;
+
+typedef struct {
+ int process;
+ int seccomp;
+ int landlock;
+} ccdjit_sandbox_capabilities;
+
+typedef struct {
+ const char *filename;
+ const char *function;
+ int line;
+ int column;
+ uintptr_t address;
+ size_t size;
+} ccdjit_debug_location;
+
+/*
+ * Create a compiler context. Passing NULL uses permissive CLI-like defaults.
+ * Invalid options return NULL; call ccdjit_context_last_error(NULL) for the
+ * thread-local creation diagnostic.
*/
ccdjit_context *ccdjit_context_new(const ccdjit_options *options);
+int ccdjit_version_major(void);
+int ccdjit_version_minor(void);
+int ccdjit_version_patch(void);
+const char *ccdjit_version_string(void);
+int ccdjit_api_abi_version(void);
+int ccdjit_binary_format_version(void);
+const char *ccdjit_git_commit(void);
+int ccdjit_sandbox_capabilities_query(ccdjit_sandbox_capabilities *out);
+
/* Free the context and all context-owned diagnostics/options/lists. */
void ccdjit_context_free(ccdjit_context *ctx);
@@ -239,6 +378,24 @@ int ccdjit_context_set_preprocessor_limits(ccdjit_context *ctx,
size_t output_limit_bytes, unsigned int macro_depth,
unsigned int include_depth);
+/* Select the compiler driver used by system include and builtin macro probes.
+ */
+int ccdjit_context_set_preprocessor_compiler(ccdjit_context *ctx,
+ const char *compiler);
+
+/* Update compiler-probe timeout/output limits. Passing zero keeps defaults. */
+int ccdjit_context_set_preprocessor_probe_limits(ccdjit_context *ctx,
+ unsigned int timeout_ms, size_t output_limit_bytes);
+
+/* Free this thread's cached compiler probe results and system include paths. */
+void ccdjit_preprocessor_free_probe_cache(void);
+
+/* Enable or disable executable memory for future compile/load/call paths. */
+int ccdjit_context_set_executable_memory(ccdjit_context *ctx, int allow);
+
+/* Enable or disable optional debug/source mapping metadata. */
+int ccdjit_context_set_debug_info(ccdjit_context *ctx, int enable);
+
/*
* Add a Landlock filesystem root for sandboxed execution.
*
@@ -249,13 +406,40 @@ int ccdjit_context_set_preprocessor_limits(ccdjit_context *ctx,
int ccdjit_context_add_sandbox_filesystem_root(ccdjit_context *ctx,
const char *path, int writable);
-/* Return the last error for this context. The pointer is context-owned. */
+/*
+ * Return the last error for this context. Passing NULL returns the
+ * thread-local diagnostic for context creation or NULL-context API failures.
+ * The pointer is context-owned or thread-local.
+ */
const ccdjit_diagnostic *ccdjit_context_last_error(ccdjit_context *ctx);
/* Return captured sandbox stdout/stderr from the last sandboxed main call. */
const char *ccdjit_context_last_stdout(ccdjit_context *ctx);
const char *ccdjit_context_last_stderr(ccdjit_context *ctx);
+/*
+ * Owned execution result snapshot for bindings and concurrent hosts.
+ *
+ * Result objects keep copies of the call status, integer result, diagnostic,
+ * captured stdout, and captured stderr. They are not invalidated by later
+ * calls on the same context.
+ */
+void ccdjit_execution_result_free(ccdjit_execution_result *result);
+int ccdjit_execution_result_status(const ccdjit_execution_result *result);
+int ccdjit_execution_result_has_value(const ccdjit_execution_result *result);
+int ccdjit_execution_result_value(const ccdjit_execution_result *result);
+const ccdjit_diagnostic *ccdjit_execution_result_diagnostic(
+ const ccdjit_execution_result *result);
+const char *ccdjit_execution_result_stdout(
+ const ccdjit_execution_result *result);
+const char *ccdjit_execution_result_stderr(
+ const ccdjit_execution_result *result);
+int ccdjit_execution_result_signal(const ccdjit_execution_result *result);
+int ccdjit_execution_result_has_fault_address(
+ const ccdjit_execution_result *result);
+uintptr_t ccdjit_execution_result_fault_address(
+ const ccdjit_execution_result *result);
+
/* Compile a source file into a live JIT module. */
int ccdjit_compile_file(ccdjit_context *ctx, const char *path,
ccdjit_module **out);
@@ -291,9 +475,75 @@ int ccdjit_eval_string(ccdjit_context *ctx, const char *source,
*/
void *ccdjit_module_symbol(ccdjit_module *module, const char *name);
+/*
+ * Inspect a module symbol without forcing the caller to cast blindly.
+ *
+ * JIT functions expose return type, parameter count, variadic flag, and
+ * per-parameter metadata through ccdjit_module_function_parameter_type().
+ * Object symbols expose their object type and size. Loaded CCDJITB2 binaries
+ * expose function/object kind and size but not full C signatures.
+ */
+int ccdjit_module_symbol_info(ccdjit_module *module, const char *name,
+ ccdjit_symbol_info *out);
+
+int ccdjit_module_function_parameter_type(ccdjit_module *module,
+ const char *name, size_t index, ccdjit_type_info *out);
+
+/*
+ * Return a callable function pointer only when the JIT signature exactly
+ * matches the expected return and parameter types.
+ */
+void *ccdjit_module_function_symbol_checked(ccdjit_module *module,
+ const char *name, const ccdjit_type_info *return_type,
+ const ccdjit_type_info *parameter_types, size_t parameter_count,
+ int allow_variadic);
+
+/* Map a live JIT instruction address to lightweight module-owned debug info. */
+int ccdjit_module_debug_location(ccdjit_module *module, const void *address,
+ ccdjit_debug_location *out);
+
/* Call module main(argc, argv). Honors CCDJIT_SANDBOX_PROCESS. */
int ccdjit_module_call_main(ccdjit_module *module, int argc, char **argv,
int *result_out);
+int ccdjit_module_call_main_result(ccdjit_module *module, int argc, char **argv,
+ ccdjit_execution_result **out);
+
+/*
+ * Call an exported JIT function with signature int name(int).
+ *
+ * Honors CCDJIT_SANDBOX_PROCESS like ccdjit_module_call_main(). Other
+ * signatures and binary modules are rejected with a diagnostic.
+ */
+int ccdjit_module_call_i32(ccdjit_module *module, const char *symbol, int arg,
+ int *result_out);
+int ccdjit_module_call_i32_result(ccdjit_module *module, const char *symbol,
+ int arg, ccdjit_execution_result **out);
+
+/*
+ * Compile and publish a named function behind a stable handle.
+ *
+ * The initial source and every replacement must define the same function
+ * signature. Calls through the handle do not expose raw function pointers, so
+ * replacements can wait for active callers and then free old generated code.
+ */
+int ccdjit_function_handle_new(ccdjit_context *ctx, const char *source,
+ const char *filename, const char *symbol, ccdjit_function_handle **out);
+
+/*
+ * Compile replacement source and atomically publish it on success.
+ *
+ * On compile failure or signature mismatch the old implementation remains
+ * active and the context diagnostic describes the failure.
+ */
+int ccdjit_function_handle_replace(ccdjit_function_handle *handle,
+ const char *source, const char *filename);
+
+/* Call a handle whose published function has signature int name(int). */
+int ccdjit_function_handle_call_i32(ccdjit_function_handle *handle, int arg,
+ int *result_out);
+
+/* Free a function handle and the currently published implementation. */
+void ccdjit_function_handle_free(ccdjit_function_handle *handle);
/* Emit textual assembly-like bytes for inspection. */
int ccdjit_module_emit_assembly(ccdjit_module *module, FILE *out);