How to Dynamically Attach bpftime to a Running Process: Complete Guide

Use the bpftime attach <PID> command to inject the userspace eBPF runtime into an existing process via Frida, enabling dynamic instrumentation without restarting the target.

The eunomia-bpf/bpftime repository provides a userspace eBPF runtime that allows you to dynamically attach bpftime to a running process without requiring a restart or code modification. This capability leverages Frida's dynamic instrumentation framework to inject the libbpftime-agent.so shared object into the target process's address space, establishing a shared-memory connection to the eBPF runtime.

Understanding the Dynamic Attachment Architecture

The dynamic attachment system in bpftime operates through three distinct layers that handle the transition from CLI command to active instrumentation.

CLI Front-End Layer

The command-line interface parses the bpftime attach <PID> instruction and forwards the request to the injection subsystem. This layer handles PID validation to ensure the target process exists and is accessible to the current user, as documented in tools/README.md.

Frida Injection Layer

The Frida-based injector uses the Frida library to perform a remote dlopen of the agent shared object (libbpftime-agent.so) inside the target process. This implementation resides in attach/frida_uprobe_attach_impl/include/frida_uprobe_attach_impl.hpp, which manages the low-level process injection without requiring target cooperation.

Agent Runtime Layer

Once injected, the agent registers the Frida attach implementation (frida_attach_impl) with the global handler manager. This class, defined in attach/base_attach_impl/base_attach_impl.hpp, creates uprobe and uretprobe entries, stores them in the shared-memory manager (runtime/include/bpftime_shm.hpp), and executes eBPF programs when probed functions fire.

Step-by-Step Guide to Attach bpftime to a Running Process

Follow this workflow to dynamically instrument an existing process using the bpftime CLI.

Prerequisites

  • bpftime tools installed and available in your PATH
  • Target process running with appropriate permissions
  • Sudo access for cross-user attachment

Step 1: Load eBPF Programs into Shared Memory

Before attaching to a process, load the eBPF programs that will instrument the target:

bpftime load ./example/malloc/malloc

This registers the eBPF program with the shared-memory manager, making it available to any process you subsequently attach.

Step 2: Identify the Target Process

Locate the PID of the running process you want to instrument:

./example/malloc/victim &
pid=$!
echo "Target PID: $pid"

Step 3: Execute Dynamic Attachment

Inject the bpftime agent into the running process using the attach command:

sudo bpftime attach $pid

The output confirms successful injection:

Inject: "/root/.bpftime/libbpftime-agent.so"
Successfully injected. ID: 1

Optional: Enable syscall tracing during attachment by adding the -s flag:

sudo bpftime attach -s $pid

Step 4: Verify Attachment

Once attached, the eBPF program will begin collecting data. Verify the instrumentation is active by checking the program output:


# The agent feeds map data to the shared memory

# Sample output showing malloc call counts:

pid=247299  malloc calls: 10
pid=247322  malloc calls: 10

Programmatic Attachment Using the C++ API

For custom controllers or embedded scenarios, you can invoke the attachment mechanism programmatically using the bpftime runtime API. This approach uses the same underlying classes as the CLI.

#include "runtime/include/bpftime.hpp"
#include "runtime/include/bpftime_shm.hpp"
#include "attach/base_attach_impl/base_attach_impl.hpp"
#include "attach/frida_uprobe_attach_impl/include/frida_uprobe_attach_impl.hpp"

int main()
{
    // 1. Connect to the shared-memory manager
    auto shm = bpftime::shm::open_or_create();

    // 2. Load an eBPF program
    auto prog_fd = bpftime::load_elf("./example/malloc/malloc", shm);

    // 3. Initialize Frida attach implementation
    pid_t target = 101771;  // Replace with actual target PID
    bpftime::attach::frida_attach_impl frida_impl;
    
    // Register with global handler manager (automatic in constructor)
    bpftime::handler_manager::instance().register_attach_impl(&frida_impl);

    // 4. Create a uprobe on target function
    void *malloc_addr = /* resolve symbol address */;
    int attach_id = frida_impl.create_uprobe_at(
        malloc_addr,
        [](const pt_regs &regs){ /* optional callback */ }
    );

    // eBPF programs now execute when malloc is called in the target
    return 0;
}

Note: The programmatic API is rarely required for standard use cases; the CLI bpftime attach command performs these steps internally.

Managing Attached Agents

After dynamic attachment, you may need to detach agents or modify tracing behavior.

Detaching from Processes

To remove the bpftime agent from all attached processes, use the detach command:

bpftime detach

This sends SIGUSR1 to every process that received an agent, causing the injected code to clean up and unload.

Summary

Dynamic attachment in bpftime enables runtime instrumentation of existing processes without restarts or code changes. Key takeaways include:

  • Use bpftime attach <PID> to inject the agent into running processes via Frida.
  • The injection loads libbpftime-agent.so, which registers the Frida attach implementation and connects to the shared-memory eBPF runtime.
  • Pre-load eBPF programs using bpftime load so attached processes can immediately access them.
  • Detach agents globally using bpftime detach when instrumentation is complete.
  • The underlying implementation spans tools/README.md, frida_uprobe_attach_impl.hpp, and base_attach_impl.hpp.

Frequently Asked Questions

Does bpftime require restarting the target process?

No. The dynamic attachment mechanism uses Frida to remotely inject the libbpftime-agent.so shared object into the target process's address space. This allows you to attach bpftime to long-running services or critical infrastructure without downtime or process restarts.

What permissions are needed to attach to a process?

You must have permission to send signals and access the target process's memory. Typically, this means running as the same user who owns the target process, or using sudo for cross-user attachment. The CLI validates the PID and ownership before attempting injection.

How does bpftime communicate with the attached process?

After injection, the agent establishes a connection to the bpftime shared-memory region (bpftime_shm). This shared-memory manager, defined in runtime/include/bpftime_shm.hpp, stores eBPF programs and maps, allowing the attached process to execute eBPF logic and share data with other instrumented processes.

Can I attach to multiple processes simultaneously?

Yes. You can run bpftime attach <PID> multiple times with different process IDs. Each injection loads an independent agent instance that connects to the same shared-memory runtime. To detach all agents at once, use bpftime detach, which signals every injected process to clean up.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →