# Understanding the bpftime Architecture: Core Components and Design

> Explore the bpftime architecture and its six core components: VM, runtime, attach system, verifier, loader, and daemon. Understand how they enable high-performance userspace eBPF execution.

- Repository: [eunomia-bpf/bpftime](https://github.com/eunomia-bpf/bpftime)
- Tags: architecture
- Published: 2026-03-01

---

**The bpftime architecture consists of six primary modules—a modular VM for bytecode execution, a runtime for object management and shared memory, an attach system for event hooking, a userspace verifier for safety analysis, an LD_PRELOAD loader for process injection, and an optional daemon for kernel integration—that together enable high-performance userspace eBPF execution.**

The bpftime project, hosted at `eunomia-bpf/bpftime`, provides a complete userspace eBPF runtime designed for attaching to arbitrary processes without kernel cooperation. Understanding the bpftime architecture is essential for developers extending the platform or optimizing eBPF program performance in userspace environments.

## Core Components of the bpftime Architecture

The bpftime architecture is organized into distinct layers, each responsible for a specific aspect of the eBPF lifecycle. These components interact through well-defined APIs to provide a seamless execution environment.

### 1. VM (Virtual Machine)

The **VM** component executes eBPF bytecode and supports multiple backend implementations for different performance and compatibility requirements. Located in the `vm/` directory, it abstracts the execution engine from the rest of the system.

Key implementations include:
- **LLVM-based JIT/AOT**: Uses `llvmbpf` for native code generation
- **ubpf**: Provides both interpreter and JIT compilation modes
- **Standalone library**: For embedded scenarios requiring minimal dependencies

The VM interface is defined in [`vm/vm-core/include/ebpf-vm.h`](https://github.com/eunomia-bpf/bpftime/blob/main/vm/vm-core/include/ebpf-vm.h), which serves as the primary contract between execution engines and the runtime.

### 2. Runtime

The **Runtime** manages eBPF objects including maps, helpers, and user functions (`ufuncs`). Implemented primarily in the `runtime/` directory, it provides the shared-memory infrastructure that enables zero-copy map access between processes.

Core responsibilities include:
- Object lifecycle management for programs and maps
- Safety checks and resource limits
- Shared memory allocation for `bpftime` maps accessible across process boundaries

The public API is exposed through [`runtime/include/bpftime.hpp`](https://github.com/eunomia-bpf/bpftime/blob/main/runtime/include/bpftime.hpp), while internal object tracking occurs in [`runtime/src/handler/handler_manager.hpp`](https://github.com/eunomia-bpf/bpftime/blob/main/runtime/src/handler/handler_manager.hpp).

### 3. Attach Events

The **Attach** component provides the plugin system for hooking eBPF programs to event sources. Located in `attach/`, it abstracts the mechanism by which execution is triggered.

Supported attachment types include:
- **Uprobes**: User-space function interception
- **Syscall tracepoints**: System call monitoring
- **XDP**: Network packet processing (userspace implementation)
- **GPU kernels**: Accelerated computing event hooks

The reference implementation for simple uprobes resides in [`attach/simple_attach_impl/simple_attach_impl.cpp`](https://github.com/eunomia-bpf/bpftime/blob/main/attach/simple_attach_impl/simple_attach_impl.cpp).

### 4. Verifier

The **Verifier** performs static safety analysis on eBPF programs before loading. Found in `bpftime-verifier/`, it ensures programs cannot crash the runtime or access unauthorized memory.

Key characteristics:
- Uses the **PREVAIL** userspace verifier by default
- Can delegate verification to the Linux kernel verifier when available
- Validates memory access patterns and instruction sequences

The entry point is [`bpftime-verifier/src/bpftime-verifier.cpp`](https://github.com/eunomia-bpf/bpftime/blob/main/bpftime-verifier/src/bpftime-verifier.cpp).

### 5. Loader and Agent

The **Loader** injects the bpftime runtime into target processes without requiring application recompilation. It consists of:

- **LD_PRELOAD agent**: A shared library (`libbpftime-agent.so`) that initializes the runtime when injected via `LD_PRELOAD`
- **CLI tools**: The `bpftime` command-line interface for loading objects and attaching to processes

Implementation resides in [`runtime/syscall-server/loader.cpp`](https://github.com/eunomia-bpf/bpftime/blob/main/runtime/syscall-server/loader.cpp).

### 6. Daemon

The optional **Daemon** enables interoperability between userspace bpftime programs and the kernel eBPF subsystem. Located in `daemon/`, it allows hybrid deployments where some programs run in kernel space and others in userspace.

## How the bpftime Architecture Works

The components interact in a defined pipeline to execute eBPF programs:

1. **Compilation**: Developers compile eBPF programs using standard `clang` and `libbpf` toolchains.
2. **Verification**: The verifier validates bytecode safety using PREVAIL or kernel verification.
3. **Loading**: The loader injects the runtime via `LD_PRELOAD` or explicit CLI commands.
4. **Execution**: The VM executes bytecode, utilizing runtime-managed maps and helpers.
5. **Attachment**: The attach system rewrites target binaries or intercepts syscalls to trigger program execution on events.
6. **Inter-process sharing**: Maps reside in shared memory, enabling zero-copy data exchange between processes.

## Implementation Details and Key Files

Understanding the source layout is crucial for extending the architecture:

- **[`vm/vm-core/include/ebpf-vm.h`](https://github.com/eunomia-bpf/bpftime/blob/main/vm/vm-core/include/ebpf-vm.h)**: Defines the VM interface used by all execution backends.
- **[`runtime/include/bpftime.hpp`](https://github.com/eunomia-bpf/bpftime/blob/main/runtime/include/bpftime.hpp)**: Public API for map creation, program loading, and runtime interaction.
- **[`runtime/src/handler/handler_manager.hpp`](https://github.com/eunomia-bpf/bpftime/blob/main/runtime/src/handler/handler_manager.hpp)**: Central registry managing eBPF objects in shared memory.
- **[`attach/simple_attach_impl/simple_attach_impl.cpp`](https://github.com/eunomia-bpf/bpftime/blob/main/attach/simple_attach_impl/simple_attach_impl.cpp)**: Reference uprobe attachment implementation.
- **[`bpftime-verifier/src/bpftime-verifier.cpp`](https://github.com/eunomia-bpf/bpftime/blob/main/bpftime-verifier/src/bpftime-verifier.cpp)**: Entry point for the PREVAIL safety verifier.
- **[`runtime/syscall-server/loader.cpp`](https://github.com/eunomia-bpf/bpftime/blob/main/runtime/syscall-server/loader.cpp)**: Implements the `LD_PRELOAD` injection mechanism.
- **`daemon/`**: Contains kernel interoperability daemon code.

## Practical Examples

### Loading and Running a Uprobe Program

Compile and execute an eBPF program targeting `malloc` calls:

```bash

# Build the example

make -C example/malloc

# Add bpftime to PATH

export PATH=$PATH:~/.bpftime/

# Load the eBPF object

bpftime load ./example/malloc/malloc

# Start the target program

bpftime start ./example/malloc/victim

```

### Attaching to a Running Process

Inject bpftime into an already executing process:

```bash

# Start target in background and capture PID

./example/malloc/victim & echo $!  # Output: 101771

# Attach loaded eBPF program to PID

sudo bpftime attach 101771

```

### Using the LD_PRELOAD Agent

Directly inject the runtime without CLI tools:

```bash

# Set the agent library path

export LD_PRELOAD=$HOME/.bpftime/libbpftime-agent.so

# Execute any binary; runtime initializes automatically

./my_app

```

## Summary

- The **bpftime architecture** comprises six modular components: VM, Runtime, Attach, Verifier, Loader/Agent, and Daemon.
- The **VM** supports multiple backends (LLVM, ubpf) for flexible bytecode execution.
- The **Runtime** manages shared-memory maps and eBPF objects, enabling inter-process communication.
- The **Attach** system provides pluggable event sources from uprobes to GPU kernels.
- The **Verifier** ensures safety using PREVAIL or kernel verification before execution.
- The **Loader** uses `LD_PRELOAD` for non-invasive process injection, while the **Daemon** enables kernel interoperability.

## Frequently Asked Questions

### What is the bpftime architecture designed for?

The bpftime architecture is designed to execute eBPF programs entirely in userspace without kernel dependencies. It enables attaching eBPF programs to arbitrary user-space functions, system calls, and even GPU kernels while providing kernel-compatible map semantics and verification.

### How does bpftime differ from kernel eBPF?

Unlike kernel eBPF, which requires root privileges and kernel version compatibility, bpftime runs in userspace using `LD_PRELOAD` injection. It uses shared memory for maps instead of kernel objects, supports attaching to already-running processes, and can operate without kernel eBPF support entirely.

### What verifier does bpftime use for safety checks?

Bpftime uses the **PREVAIL** userspace verifier by default, located in [`bpftime-verifier/src/bpftime-verifier.cpp`](https://github.com/eunomia-bpf/bpftime/blob/main/bpftime-verifier/src/bpftime-verifier.cpp). It can also delegate verification to the Linux kernel verifier when available, providing flexibility in safety validation approaches.

### Can bpftime attach to processes that are already running?

Yes, bpftime supports attaching to existing processes through the `bpftime attach <PID>` command. This uses the agent infrastructure in [`runtime/syscall-server/loader.cpp`](https://github.com/eunomia-bpf/bpftime/blob/main/runtime/syscall-server/loader.cpp) to inject the runtime into a running process without requiring restart or recompilation.