diff options
| author | David Moc <personal@cdatgoose.org> | 2026-06-02 13:50:21 +0200 |
|---|---|---|
| committer | David Moc <personal@cdatgoose.org> | 2026-06-02 13:50:21 +0200 |
| commit | a15cb041654ae307add0b998b526c87c3f42bf5f (patch) | |
| tree | 225bb4b70e9fa05aa5f4d2722a1a9cf5fc6fca7f /include/ccdjit.h | |
| parent | 6aeaa171dc1ca43392f53cbd02097f76e1b1c5a0 (diff) | |
Add plugin hooks and mode plugins
Diffstat (limited to 'include/ccdjit.h')
| -rw-r--r-- | include/ccdjit.h | 262 |
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); |
