This document provides a comprehensive reference for all builtin functions available in KernelScript. These functions are context-aware and translate differently depending on the execution environment (eBPF, userspace, or kernel module).
KernelScript builtin functions provide essential functionality across different execution contexts:
- eBPF Context: Functions available within eBPF programs running in kernel space
- Userspace Context: Functions available in userspace programs that manage eBPF programs
- Kernel Module Context: Functions available when compiling to kernel modules
Signature: print(...) -> u32
Variadic: Yes (accepts any number of arguments)
Context: All contexts
Description: Print formatted output to the appropriate output stream based on context.
Context-specific implementations:
- eBPF: Uses
bpf_printkto write to kernel trace log (limited to format string + 3 arguments) - Userspace: Uses
printfto write to console/stdout - Kernel Module: Uses
printkto write to kernel log
Parameters:
- Variable number of arguments of any type
- First argument typically used as format string in userspace/kernel contexts
Return Value:
- Returns
0on success (like standard printf family) - Returns error code on failure
Examples:
print("Hello, world!")
print("Value:", 42)
print("Multiple values:", x, y, z)
Notes:
- In eBPF context, limited to 4 total arguments due to
bpf_printkrestrictions - Automatically handles type conversion for different contexts
Signature: load(function) -> ProgramHandle
Variadic: No
Context: Userspace only
Description: Load an eBPF program function and return a handle for subsequent operations.
Parameters:
function: Any function with eBPF attributes (@xdp,@kprobe,@tracepoint, etc.)
Return Value:
- Returns a
ProgramHandlethat can be used withattach()anddetach() - Handle represents the loaded eBPF program file descriptor
Examples:
@xdp
fn my_xdp_program(ctx: *xdp_md) -> xdp_action {
return XDP_PASS
}
fn main() -> i32 {
var prog = load(my_xdp_program)
// Use prog with attach()
return 0
}
Context-specific implementations:
- eBPF: Not available
- Userspace: Uses
bpf_prog_loadsystem call - Kernel Module: Not available
Signature: attach(handle: ProgramHandle, target: str(128), flags: u32) -> u32
Signature: attach(handle: ProgramHandle, opts: perf_options, flags: u32) -> PerfAttachment
Variadic: No
Context: Userspace only
Description: Attach a loaded eBPF program to a target interface or attachment point, or to a perf event counter described by perf_options. Both forms take three arguments, keeping a uniform call shape across all program types.
Parameters:
- Standard form:
handle: Program handle returned fromload()target: Target interface name (e.g., "eth0", "lo") or attachment pointflags: Attachment flags (context-dependent)
- Perf event form:
handle: Program handle returned fromload()opts:perf_optionsvalue — onlyperf_typeandperf_configare required; all other fields have defaults, including no group (groupinvalid andgroup_fd=-1)flags: Must be0for perf attaches; nonzero values are rejected
Return Value:
- Standard form returns
0on success and an error code on failure - Perf event form returns a
PerfAttachmentvalue with the open counter/link identity and an internal stale-handle token
Examples:
var prog = load(my_xdp_program)
var result = attach(prog, "eth0", 0)
if (result != 0) {
print("Failed to attach program")
}
// Minimal perf attach — all non-perf_type/perf_config fields use defaults:
// pid=-1 (all procs), cpu=0, period=1_000_000, wakeup=1; perf attach flags must be 0
var perf_prog = load(on_branch_miss)
var perf_att = attach(perf_prog, perf_options { perf_type: perf_type_hardware, perf_config: branch_misses }, 0)
var count = read(perf_att).scaled
detach(perf_att)
detach(perf_prog)
// Grouped perf events: branch joins cache's leader group. Adding a member restarts the group.
var cache = attach(perf_prog, perf_options { perf_type: perf_type_hardware, perf_config: cache_misses }, 0)
var branch = attach(perf_prog, perf_options {
perf_type: perf_type_hardware,
perf_config: branch_misses,
group: cache,
}, 0)
detach(branch)
detach(cache)
Grouped events are scheduled as one atomic PMU unit. Separate events and separate groups may be multiplexed, but members inside one group cannot be independently multiplexed. Static groups that exceed the target PMU counter limit are rejected at compile time; override the detected/default limit with KERNELSCRIPT_PERF_GROUP_MAX_EVENTS when compiling for a different target. The effective limit is capped at 16 to match PerfRead.
Context-specific implementations:
- eBPF: Not available
- Userspace: Uses
attach_bpf_program_by_fdfor standard targets andks_attach_perf_eventfor perf events - Kernel Module: Not available
Signature: detach(handle: ProgramHandle) -> void
Signature: detach(handle: PerfAttachment) -> void
Variadic: No
Context: Userspace only
Description: Detach a loaded eBPF program from its current attachment point, or tear down one perf attachment.
Parameters:
handle: Program handle returned fromload(), or aPerfAttachmentreturned from perfattach()
Return Value:
- No return value (void)
Examples:
var prog = load(my_xdp_program)
attach(prog, "eth0", 0)
// ... program runs ...
detach(prog) // Clean up
Context-specific implementations:
- eBPF: Not available
- Userspace: Uses
detach_bpf_program_by_fdfor program handles andks_detach_perf_attachmentfor perf attachments - Kernel Module: Not available
Signature: read(handle: PerfAttachment) -> PerfRead
Variadic: No
Context: Userspace only
Description: Read a perf attachment snapshot. The result includes this attachment's raw and scaled count, multiplex timing, and same-time group arrays.
Parameters:
handle: Perf attachment returned fromattach(handle, perf_options, flags)
Return Value:
raw: this event's unscaled counter value, or-1on invalid/stale attachment or read failurescaled: this event's multiplex-corrected value, or-1on timing/read errortime_enabled: perf enabled timetime_running: perf running timecount: number of group entries returned;1for a standalone eventvalues: multiplex-scaled group values, capped at 16;values[0] == scaledids: perf event IDs for the returned values- Reads use the attachment's
perf_fddirectly; the internal token detects copied handles used after detach.
Signature: register(impl_instance) -> u32
Variadic: No
Context: Userspace only
Description: Register an implementation block instance with the kernel for struct_ops programs.
Parameters:
impl_instance: Instance of a struct with@struct_opsattribute
Return Value:
- Returns
0on success - Returns error code on failure
Validation:
- Only accepts impl block instances with
@struct_opsattribute - Validates that the struct_ops type is known to the kernel
- Must be used with properly attributed implementation blocks
Examples:
@struct_ops("tcp_congestion_ops")
impl TcpCongestion {
// Implementation methods here
}
fn main() -> i32 {
var tcp_impl = TcpCongestion {}
var result = register(tcp_impl)
return result
}
Context-specific implementations:
- eBPF: Not available
- Userspace: Uses
IRStructOpsRegisterinstruction - Kernel Module: Not available
Signature: test(program, test_data) -> u32
Variadic: No
Context: Userspace only (from @test functions only)
Description: Execute an eBPF program with test data and return the program's return value.
Parameters:
program: eBPF program to testtest_data: Test input data for the program
Return Value:
- Returns the program's return value
- Can be used to verify program behavior in tests
Restrictions:
- Can only be called from functions with the
@testattribute - Used for unit testing eBPF programs
Examples:
@test
fn test_my_program() -> i32 {
var result = test(my_xdp_program, test_packet_data)
// Assert result == expected_value
return result
}
Context-specific implementations:
- eBPF: Not available
- Userspace: Uses
bpf_prog_test_runsystem call - Kernel Module: Not available
Signature: dispatch(ringbuf1, ringbuf2, ...) -> i32
Variadic: Yes (accepts multiple ring buffer arguments)
Context: Userspace only
Description: Poll multiple ring buffers for events and dispatch them to their registered callbacks.
Parameters:
- Variable number of ring buffer arguments (RingbufRef or Ringbuf types)
- Each ring buffer should have associated event callbacks
Return Value:
- Returns
0on success - Returns error code on failure
Validation:
- All arguments must be ring buffer types
- Requires at least one ring buffer argument
Examples:
var rb1: ringbuf<u32>(1024)
var rb2: ringbuf<u64>(2048)
fn main() -> i32 {
// Poll both ring buffers for events
var result = dispatch(rb1, rb2)
return result
}
Context-specific implementations:
- eBPF: Not available
- Userspace: Uses
ring_buffer__pollfrom libbpf - Kernel Module: Not available
Signature: daemon() -> void
Variadic: No
Context: Userspace only
Description: Become a daemon process by detaching from the terminal and running in the background.
Parameters:
- No parameters
Return Value:
- Never returns in practice (process becomes daemon)
- Type system requires void return type
Examples:
fn main() -> i32 {
print("Starting daemon...")
daemon() // Process detaches from terminal
// Code here runs as daemon
return 0
}
Context-specific implementations:
- eBPF: Not available
- Userspace: Uses
daemon_builtincustom implementation - Kernel Module: Not available
Signature: exec(python_script: str(256)) -> void
Variadic: No
Context: Userspace only
Description: Replace the current process with a Python script, inheriting all eBPF maps and file descriptors.
Parameters:
python_script: Path to Python script file (must have .py extension)
Return Value:
- Never returns (replaces current process)
- Type system requires void return type
Validation:
- Script path must be a string
- File suffix validation occurs during code generation
- Python script inherits eBPF program state
Examples:
fn main() -> i32 {
// Set up eBPF programs and maps
var prog = load(my_program)
attach(prog, "eth0", 0)
// Hand off to Python for advanced processing
exec("advanced_analysis.py") // Never returns
}
Context-specific implementations:
- eBPF: Not available
- Userspace: Uses
exec_builtincustom implementation - Kernel Module: Not available
| Function | eBPF | Userspace | Kernel Module | Notes |
|---|---|---|---|---|
print() |
✅ | ✅ | ✅ | Different output destinations |
load() |
❌ | ✅ | ❌ | Program management only |
attach() |
❌ | ✅ | ❌ | Standard attach and perf_options attach |
detach() |
❌ | ✅ | ❌ | Program management only |
register() |
❌ | ✅ | ❌ | struct_ops registration |
test() |
❌ | ✅ | ❌ | Testing framework only |
dispatch() |
❌ | ✅ | ❌ | Event processing only |
daemon() |
❌ | ✅ | ❌ | Process management only |
exec() |
❌ | ✅ | ❌ | Process replacement only |
- Builtin Functions: Defined by KernelScript, context-aware, part of the language
- Helper Functions: User-defined functions with
@helperattribute, compiled as eBPF helpers - Kernel Functions (kfuncs): External kernel functions declared with
externor@kfunc
KernelScript also supports external kernel functions that can be declared and called:
// External eBPF helper functions
extern bpf_ktime_get_ns() -> u64
extern bpf_trace_printk(fmt: *u8, fmt_size: u32) -> i32
extern bpf_get_current_pid_tgid() -> u64
// Usage in eBPF programs
@xdp
fn my_program(ctx: *xdp_md) -> xdp_action {
var timestamp = bpf_ktime_get_ns()
return XDP_PASS
}
Most builtin functions return error codes where appropriate:
0: Success- Non-zero: Error (specific meaning depends on function)
Always check return values for functions that can fail:
var result = attach(prog, "eth0", 0)
if (result != 0) {
print("Failed to attach program, error:", result)
return result
}
- SPEC.md: Language specification and features
- examples/: Example programs demonstrating builtin function usage