bpftrace vs BCC

Necco Ceresani
Necco Ceresani··26 min read

Fifteen years building engineering platforms, currently focused on advanced AI infrastructure at yeet. I love turning the deeply complex topics into something everyone can understand. I relate deeply with the core yeet philosophy that you can just build things.

Start with bpftrace. For most projects it is the right first move, and it is the cheapest one to be wrong about: it installs from a package manager, answers a question in one line, and leaves nothing on the host. bpftrace -e 'tracepoint:syscalls:sys_enter_openat { @[comm] = count(); }' is a complete program that tells you which processes are opening files. Start with BCC instead if you already know your project needs command line flags for other people, floating-point math on the results, or has to run on hosts where you cannot install a compiler. Those three are the only reasons to skip the easier tool, and the rest of this post is how to tell today whether one of them applies to you.

Both of these have been open on my desk for years. I write eBPF tooling for Linux hosts, which means I have shipped things in bpftrace that should have been BCC programs, and written BCC programs that a three-line bpftrace script would have covered, and the second mistake costs more than the first. What I cannot tell you is how either behaves as the backbone of a decade-old observability stack, because I build the probes rather than operate someone else's fleet. What I can tell you is which one a project regrets picking, and the pattern is consistent enough to be worth writing down: almost nobody regrets starting with bpftrace, and the people who regret starting with BCC all started there because they assumed the serious choice was the correct one.

It is worth knowing before you choose that the projects themselves do not consider this a rivalry. bpftrace's own language documentation, under a heading called Complex Tools, tells you to "consider switching to bcc" once a tool involves "command line options, positional parameters, argument processing, and customized output", concedes that "bcc is much more verbose and laborious to program", and states plainly that "Together, bpftrace and bcc are complimentary." The maintainers describe an expected path of one-liners, then ad hoc bpftrace scripting, then BCC when needed. That is not a compromise position. It is the answer, from the people with the most reason to argue for their own tool.

Should I use bpftrace or BCC for my project?

bpftrace, unless someone other than you will run it. That one question predicts the answer better than anything about the complexity of the measurement, because bpftrace's limits are almost all limits on packaging rather than on what it can observe. bpftrace's own documentation names the boundary as command line options, positional parameters, argument processing and customized output, and every item on that list is about handing the thing to someone else.

Three tests, answerable before you write a line:

  1. Will someone else run this? If they will, they need flags, and flags mean BCC. A script you edit before each run has exactly one user, and that arrangement works right until you hand it to a different team at 3am.
  2. Does the answer need division, a ratio or a percentile as a number? BPF has no floating point, so that arithmetic has to happen in a userspace language. BCC has one and bpftrace does not.
  3. Can you install a compiler on the target host? If not, neither the BCC Python tools nor bpftrace fit, and you want CO-RE binaries or a runtime that loads programs for you.

Answer no, no, yes and start with bpftrace without further thought. Any other combination is worth ten minutes of planning before you type.

The trap is measuring by length. A 60-line bpftrace script that still runs as ./thing.bt with no flags is fine, and a 20-line one where you have started editing the source to change a pid filter has already crossed the line, because that edit is an argument you have not implemented yet. BCC's Python half exists to serve that second user: it brings argparse, so --pid, --interval and --duration become flags rather than lines someone has to go find and change.

The BCC tools show what that looks like at rest. Each shipped tool is a Python file that parses arguments, builds the BPF C source, attaches it, and formats the output, and the kernel-side program is a C string in the middle of it. That structure is more code than a bpftrace script by a factor of several, which is the "verbose and laborious" the bpftrace docs concede. What you buy is a tool that behaves like a tool.

How do I get a latency histogram in bpftrace vs BCC?

In bpftrace you call hist() and the histogram is built and printed for you. In BCC you assemble the same thing from a BPF_HISTOGRAM declaration, a C probe that computes the delta, and a Python loop that prints it. Latency histograms are the case bpftrace was shaped around, so the whole program is one invocation:

bpftrace -e 'kprobe:vfs_read { @start[tid] = nsecs; }
  kretprobe:vfs_read /@start[tid]/ {
    @us = hist((nsecs - @start[tid]) / 1000); delete(@start[tid]); }'

@start[tid] is a BPF map keyed by thread id, nsecs is the kernel's monotonic clock, and hist() builds a power-of-two histogram that prints itself when the program exits. Three concepts, no build step, nothing to clean up. The same measurement in BCC means writing the C, declaring a BPF_HASH for the start timestamps and a BPF_HISTOGRAM for the buckets, then writing the Python that attaches both probes and prints the table. For scale, BCC's shipped biolatency.py is 425 lines, though that is a finished tool with flags, several grouping modes and a man page rather than a minimal equivalent.

The reason bpftrace wins here is that its maps are the language's primary data structure rather than an API you call. @name[key] = count() is a complete program fragment, and the printing at exit is automatic: bpftrace prints all maps to stdout when the program exits unless you override print_maps_on_exit or clear them in an end probe. That default is the difference between a one-liner and a script with a teardown section.

BCC catches up the moment the histogram is not the output. If what you want is a histogram plus a top-10 table plus a rate line, refreshed every second, you are writing a print loop either way, and Python is a much better place to write one.

What do I need to install for bpftrace vs BCC?

Almost the same list, which surprises people who assume bpftrace is the lightweight one. bpftrace "uses LLVM as a compiler backend, and libbpf for interacting with the Linux BPF subsystem" by its own description, so the LLVM dependency is present in both. The BCC install guide asks for LLVM 3.7.1 or newer compiled with BPF support, clang built from the same tree, plus kernel headers matching the running kernel.

The real divergence is the third option inside BCC. The libbpf-tools directory holds 58 CO-RE programs that are compiled ahead of time and, per their README, "linked statically against a version of libbpf that BCC links against", leaving only libc, libelf and libz dynamic. Those binaries carry none of the toolchain to the target host. Same project, opposite deployment story.

ToolWhat runs on the target hostCompiles on the targetShips ready-made tools
bpftraceThe bpftrace binary, LLVM, libbpfYes, at program start39 .bt scripts
BCC Python toolsPython, BCC, LLVM, clang, kernel headersYes, every run105 Python tools
BCC libbpf-toolsOne static binary per toolNo, ahead of time58 CO-RE programs
yeetThe daemon, once, plus a JS fileNo, the daemon loads itPublic scripts, per tool

The column that decides most arguments is the third one. A team that treats production hosts as things you do not install compilers on will reject the first two rows on that basis alone, regardless of which language they prefer.

Why does my BCC tool work on my laptop but not on the server?

The kernel headers, nine times out of ten, because BCC compiles the BPF program on the machine where you run it and needs headers matching the running kernel to do so. A laptop with a development toolchain has them. A server that took a kernel upgrade without a matching headers package does not, and the failure arrives as a compilation error naming a header rather than anything that says "wrong kernel."

BCC's install guide asks for CONFIG_IKHEADERS=y, which exposes the headers through /sys/kernel/kheaders.tar.xz, and is the reason some hosts work with no headers package installed at all. bpftrace hits a related version of this: its docs note it "requires kernel headers for certain features, which are searched for by default in /lib/modules/$(uname -r)", overridable with BPFTRACE_KERNEL_SOURCE.

Check the running host before blaming the tool:

uname -r                                  # the running kernel
ls /lib/modules/$(uname -r)/build         # headers present for it?
ls /sys/kernel/btf/vmlinux                # BTF present, so CO-RE works

The third line is the one that decides your escape route. If /sys/kernel/btf/vmlinux exists, the CO-RE libbpf-tools build will run there without headers or a compiler, and moving to one of those 58 tools solves the problem permanently rather than for this kernel version.

bpftrace error: "Looks like the BPF stack limit of 512 bytes is exceeded"

Because BPF programs get 512 bytes of stack and the verifier rejects anything larger at load time, so the error means the program never ran rather than that it ran badly. bpftrace reports it as "Looks like the BPF stack limit of 512 bytes is exceeded", and its docs list four remedies in order: reduce the size of the data used, avoid strings where something smaller works ("use pid instead of comm"), use fewer map keys, and split the program over multiple probes.

The one that catches people is strings. max_strlen defaults to 1024 bytes, and a single str() value can therefore exceed the entire stack budget on its own, which is why raising max_strlen to capture a long path can break a script that was working. Two string keys in one map is usually where a growing script dies.

Switching to BCC does not fix this. The 512-byte limit is a kernel property, so a C program written against libbpf hits the same wall in the same place. What BCC changes is the workaround budget: you can do the assembly in Python after the events leave the kernel, keeping the kernel-side program small and dumb, which is a restructuring bpftrace cannot express because it has no userspace half to move work into.

Can bpftrace calculate a p99 latency?

Not in floating point, and this is a hard stop rather than an inconvenience. The bpftrace documentation states that "floating-point numbers are not supported by BPF and therefore not by bpftrace." Integer nanoseconds are the currency, and the power-of-two buckets hist() produces are approximations by construction.

For a lot of work that is fine, because a latency histogram in power-of-two buckets answers "is this bimodal" and "did the tail move" perfectly well. It stops being fine when someone asks for a p99 as a number to put in a ticket, or a ratio between two measurements, because bucket boundaries are not percentiles and integer division loses the precision you need to compute one.

This is where the split-the-work structure earns its keep. Aggregate in the kernel, where integers are all you get, then compute in userspace where they are not. BCC does this in Python. The same reasoning is why runtimes with a real language on the userspace side exist at all: the kernel half stays a counter, and the arithmetic happens somewhere with floats.

Is there already a bpftrace or BCC tool that does this?

Check first, because between them these projects ship over 200 tools and duplicates are common. bpftrace has 39 .bt scripts in its tools/ directory as of v0.26.1. BCC has 105 Python tools plus the 58 CO-RE programs under libbpf-tools as of v0.37.0. Names like opensnoop, execsnoop and biolatency exist in both, because the BCC versions came first and were ported.

bpftrace -l 'tracepoint:syscalls:sys_enter_open*'   # what can I even attach to?
ls /usr/share/bpftrace/tools/                        # what ships with bpftrace here
ls /usr/share/bcc/tools/                             # what ships with BCC here

bpftrace -l takes a search pattern and lists matching probes, which is the fastest way to find out whether the event you want is exposed as a tracepoint before you write anything against a kprobe. A tracepoint is the better attachment point when one exists, because tracepoints are a stable kernel interface and kprobes attach to function names that change between kernel versions.

The version skew is worth checking too. Distribution packages lag upstream, so bpftrace --version and the tool list on the box may not match what you read on GitHub, and a one-liner using a recent builtin will fail with a parse error rather than anything explaining why.

Can bpftrace or BCC display a live dashboard?

Only as a print loop you write yourself, in both cases, which is where both tools are answering a question you did not ask. bpftrace prints maps when the program exits and can print on an interval probe, so a repainting screen means clearing and reprinting on a timer, with no cursor control. BCC's Python side can do better, because Python can hold state and repaint, and several shipped tools take an interval argument and reprint on it.

Neither project is trying to be a UI toolkit, and that is a reasonable scope decision rather than a gap. bpftrace is a tracing language; BCC is a toolkit for building tracing programs. The interface is left to whatever you point the output at, which for most people is a terminal scrollback and, occasionally, a pipe into something else.

If a repainting screen is what you are actually building, both tools will get you there and neither will help much with the part you care about. That is the gap the third option below exists in.

Is there a third option besides bpftrace and BCC?

Yes, and the useful way to think about it is that bpftrace and BCC both decide your userspace language for you, one by not having a userspace half at all and the other by making it Python. A runtime inverts that: it loads and manages the BPF program, then hands the events to whatever language it embeds, so the kernel side stops being the thing you are working on. Several projects take this shape, and yeet is the one I work on, so treat this paragraph as disclosed interest rather than a neutral survey.

Concretely, a daemon performs the privileged load and your program is a JavaScript file: import { BpfObject, RingBuf } from "yeet:bpf" gives it the events, yeet run needs no sudo because the daemon holds the capability rather than your shell, and yeet run -d leaves the script running after the SSH session ends. What that buys over BCC is a userspace language with a real UI story and no compiler on the target host. What it costs is a daemon to install, which is one more thing than apt install bpftrace and reason enough to skip it for a one-off question.

Where it loses, specifically: for a question you want answered in the next 60 seconds, bpftrace is better than any runtime, including this one, because nothing beats a one-liner that leaves nothing behind. For a tool that other people will run from a terminal with flags, BCC is the well-trodden path and has 105 worked examples to copy from. A runtime earns its place when the deliverable is a live interface, when the userspace half is substantial enough that its language matters, or when production hosts cannot have LLVM and clang on them. Outside those three, the simpler tool wins and this section is not trying to talk you out of it.

Is eBPF tooling a build or buy decision?

It is a build versus build decision, which is why framing it as build versus buy leads people astray. Both are open source, both are free, and neither is a vendor relationship. What actually differs is who maintains the thing you end up with, and the honest cost is the maintenance tail rather than the writing.

A bpftrace one-liner has no tail: you run it, you get the answer, nothing is left. A shipped tool from either project has someone else's tail, because upstream carries it across kernel versions. A BCC tool you write has your tail, and it is longer than the writing suggested, because kprobe attachment points move between kernel versions and the tool that worked on 5.15 needs attention on 6.8.

If you needReach forBecause
An answer in the next 60 secondsbpftrace one-linerNo build step, nothing left behind
A common measurementA shipped tool from eitherSomeone else carries the kernel-version tail
A tool with flags for other peopleBCC Python, or libbpf-tools for CO-REargparse and a userspace half
Floating-point math on the resultsBCC, or any runtime with userspace codeBPF has no floats, so it happens after
A live interface people watchA runtime such as yeet, or BCC plus workNeither project ships a UI layer
No compiler on production hostsBCC libbpf-tools, or yeetStatic binaries, or a daemon that loads for you

The buy decision, when it appears, is a different one entirely: whether to run any of this yourself or pay a vendor whose agent does it. That comparison is worth having, and it is not this comparison, because a Datadog agent and a bpftrace one-liner do not overlap enough to be alternatives.

When should I not use bpftrace or BCC at all?

When the question is about history rather than about right now. Both tools observe events as they happen and forget them when the program exits, so "what was this box doing at 4am on Tuesday" is not answerable by either, at any level of skill. That needs storage, which means a metrics platform, a log pipeline or a continuous profiler, and reaching for a tracing tool to answer it wastes an afternoon before you conclude the same thing.

The other case is fleet scope. A bpftrace one-liner runs on the host you typed it on. Running it across 400 hosts is an orchestration problem the tool does not address, and doing it badly by looping SSH gives you 400 terminal outputs and no aggregate. The category post on monitoring HTTP traffic on Linux covers the cluster-scoped options, and the short version is that they are different tools with different requirements rather than these two at larger scale.

Cross-host correlation is the third gap and the least obvious. A request that crosses four services is visible as four unrelated local events to four independent kernel probes, with nothing connecting them, because the connection is a trace context your application propagates and the kernel never sees. That is instrumentation's job, and no eBPF tool changes it.

The bottom line: start with bpftrace unless one of three things is already true

Start with bpftrace, and check the 39 shipped .bt tools and BCC's 105 Python tools before writing anything, because the measurement you want may already exist under a name you have not searched for. Start with BCC instead only if one of three things is already true today: other people will run it and therefore need flags, the answer requires floating-point math, or the target hosts cannot have a compiler on them. That is the boundary the bpftrace maintainers themselves draw, and picking BCC without hitting one of the three buys verbosity for nothing. Take the libbpf-tools route inside BCC when production hosts should not have LLVM, clang and kernel headers on them, because those 58 tools ship as static binaries and relocate against BTF at load. Use yeet when the deliverable is a live interface rather than a stream of lines and you would rather write the userspace half in JavaScript than a print loop. Use none of them when the question is about last Tuesday or about 400 hosts at once, because a tracing tool that forgets everything on exit is the wrong shape for both, and no amount of cleverness in the probe fixes it.

The failure worth avoiding is treating the choice as permanent and therefore weighty. A bpftrace script that outgrows itself has cost you an afternoon and taught you exactly what the BCC version needs to do, which is the cheapest possible way to arrive at a specification. Starting with BCC to avoid a rewrite you may never need is how teams end up with 300-line Python tools answering questions that were one bpftrace line.

Frequently asked questions

Is bpftrace faster than BCC at runtime?

Neither is meaningfully faster once the program is loaded, because both compile to BPF bytecode that the same kernel JIT executes. The difference is startup. A BCC Python tool compiles its C source with LLVM every time you run it, which is why the first output can take a second or two on a slow box. bpftrace also uses LLVM as its compiler backend, so it pays a similar cost. The libbpf-tools in the BCC repository are the exception: they are compiled ahead of time into static binaries, so they start immediately.

Do I need to know C to use BCC?

To use the shipped tools, no. BCC includes 105 Python tools in its tools/ directory that you run like any other command. To write a new BCC tool, yes, because the kernel-side half is C embedded in a Python string, and the Python half handles arguments and output. bpftrace is the route that avoids C entirely, using an awk-inspired language, and its own documentation points at BCC once a tool needs command line options and customized output.

What is the 512-byte BPF stack limit?

Every BPF program gets 512 bytes of stack, enforced by the kernel verifier, and a program exceeding it is rejected at load time rather than failing at runtime. bpftrace surfaces this as the error Looks like the BPF stack limit of 512 bytes is exceeded. The bpftrace documentation lists four remedies: reduce the size of the data used, avoid strings where a pid would do, use fewer map keys, and split the program across multiple probes. It is a kernel constraint, so BCC programs hit the same wall.

Can bpftrace handle floating-point numbers?

No. The bpftrace documentation states that floating-point numbers are not supported by BPF and therefore not by bpftrace. This is a property of the BPF instruction set rather than of bpftrace, so a BCC program written in C hits the same restriction on the kernel side. Anything requiring floating-point math has to happen in userspace, after the values leave the kernel, which BCC's Python half can do and a pure bpftrace script cannot.

What kernel version do I need for bpftrace or BCC?

BCC's install guide states a Linux kernel version 4.1 or newer, compiled with CONFIG_BPF=y, CONFIG_BPF_SYSCALL=y, CONFIG_BPF_JIT=y and CONFIG_BPF_EVENTS=y, plus CONFIG_IKHEADERS=y to reach kernel headers through /sys/kernel/kheaders.tar.xz. The CO-RE libbpf-tools also want CONFIG_DEBUG_INFO_BTF=y so BPF programs can relocate against the running kernel's type information. Distribution kernels shipping in 2026 generally satisfy all of this.

Why does my BCC tool work on one server and fail on another?

Usually because BCC compiles the BPF program on the machine where you run it, so it needs a working LLVM, clang and kernel headers matching the running kernel on every host. A box that had headers installed and then took a kernel upgrade without a matching headers package will fail where an identical box succeeds. The CO-RE libbpf-tools avoid this by compiling ahead of time and relocating against BTF at load, which is most of why they exist.

Should a beginner start with bpftrace or BCC?

bpftrace, in almost every case. It installs from a package manager, a useful program is one line, and the concepts you learn transfer directly: probes, maps and aggregation are the same ideas BCC exposes with more ceremony. The bpftrace documentation itself describes an expected path of one-liners, then ad hoc bpftrace scripting, then BCC when a tool needs argument processing and customized output. Starting at the BCC end means learning the BPF model and C plumbing simultaneously, which is two problems where bpftrace gives you one.

How many ready-made tools ship with bpftrace and BCC?

As of bpftrace v0.26.1 and BCC v0.37.0, bpftrace ships 39 .bt scripts in its tools/ directory and BCC ships 105 Python tools in its tools/ directory plus 58 CO-RE programs under libbpf-tools. Many names appear in both, such as opensnoop, execsnoop and biolatency, because the BCC versions came first and were ported. Checking whether a tool already exists is worth doing before writing anything.

Do I need root to run eBPF tracing tools?

Loading a BPF program requires privilege: root, or CAP_BPF and CAP_PERFMON on a modern kernel. bpftrace and BCC tools are conventionally run with sudo directly, which means the tracing process itself holds those capabilities. Some runtimes split this, performing the privileged load in a daemon so the command you type stays unprivileged. That distinction matters mostly when a shared box has people who should be able to trace but should not have root.

What is CO-RE and why does it change the BCC story?

CO-RE stands for Compile Once, Run Everywhere. It lets a BPF program compiled on one machine load on a kernel with different struct layouts, relocating field offsets at load time against BTF type information in the running kernel. It matters for BCC because the libbpf-tools built this way ship as static binaries linked against libc, libelf and libz only, removing the LLVM, clang and kernel-headers dependency that the Python tools carry onto every host.

Can I use bpftrace inside a container or on a Kubernetes node?

You run it on the node rather than in the workload container, because BPF programs attach to the kernel and a node has exactly one kernel shared by every container on it. A probe attached from the node sees events from all of them, and filtering to one workload means filtering by cgroup id or pid namespace inside the program. Running the tool inside an unprivileged application container generally fails at load, and it is the wrong shape even when it works.

Can I convert a bpftrace script into a BCC tool later?

The logic ports directly, because both compile to BPF and express the same primitives: a probe attachment, a map, and an aggregation. What does not port is the syntax, so a bpftrace map becomes a BPF_HASH declaration and an awk-style action block becomes a C function. Expect to rewrite rather than translate, and expect the rewrite to be fast, because the hard part was deciding what to measure and the working bpftrace script already answered that.

Sources

  • bpftrace language documentation (bpftrace docs, release 0.26) — the Complex Tools section stating that for tools involving "command line options, positional parameters, argument processing, and customized output, consider switching to bcc", that "bcc is much more verbose and laborious to program", and that "Together, bpftrace and bcc are complimentary"; the expected development path from one-liners to ad hoc scripting to bcc; the 512-byte BPF stack limit error and its four remedies; max_strlen defaulting to 1024 bytes; floating-point unsupported by BPF and therefore bpftrace; kernel headers searched in /lib/modules/$(uname -r), overridable via BPFTRACE_KERNEL_SOURCE; maps printed to stdout on exit unless print_maps_on_exit is overridden.
  • bpftrace on GitHub (bpftrace project, 2026) — describes itself as "a general purpose tracing tool and language for Linux" using a language "inspired by awk, C, and predecessor tracers such as DTrace and SystemTap", employing "LLVM as a compiler backend, and libbpf for interacting with the Linux BPF subsystem"; supports kprobes, uprobes, USDT, tracepoints, raw tracepoints, fentry/fexit, profile, interval, watchpoint and hardware and software perf events; Apache 2.0; packaged for Ubuntu, Debian, Fedora, CentOS, Alpine, Arch, Gentoo, nixpkgs and openSUSE.
  • BCC install guide (BCC project, 2026) — "a Linux kernel version 4.1 or newer is required", with CONFIG_BPF=y, CONFIG_BPF_SYSCALL=y, CONFIG_BPF_JIT=y, CONFIG_HAVE_BPF_JIT=y for 4.1 through 4.6 or CONFIG_HAVE_EBPF_JIT=y for 4.7 and later, CONFIG_BPF_EVENTS=y for kprobes, and CONFIG_IKHEADERS=y to reach headers through /sys/kernel/kheaders.tar.xz; requires "LLVM 3.7.1 or newer, compiled with BPF support" and "Clang, built from the same tree as LLVM", plus cmake 3.1+, gcc 4.7+, flex, bison and matching kernel headers; flags checkable via /proc/config.gz or /boot/config-<version>.
  • BCC on GitHub (BCC project, 2026) — "a toolkit for creating efficient kernel tracing and manipulation programs", with kernel instrumentation written in C behind a C wrapper around LLVM and front-ends in Python and Lua; integration with the llvm-bpf backend for JIT and dynamic loading and unloading of JITed programs; ships tools including tcpconnect, opensnoop, funclatency, memleak, biolatency, profile and tcplife.
  • BCC libbpf-tools README (BCC project, 2026) — CO-RE tools "linked statically against a version of libbpf that BCC links against", leaving only libc, libelf and libz dynamically linked "given their widespread availability"; naming convention of <tool>.c for userspace and <tool>.bpf.c for the BPF program compiled into an ELF and a <tool>.skel.h skeleton; a pre-generated vmlinux.h checked into the tree to avoid depending on the build host's kernel configuration, generated from a kernel built with CONFIG_DEBUG_INFO_BTF=y; BTFGen and BTFHub named as the route for kernels lacking BTF.
  • BCC reference guide (BCC project, 2026) — the BPF(text=...) object as "the main object for defining a BPF program, and interacting with its output", accepting inline C or a src_file; attach_kprobe, attach_kretprobe and attach_uprobe for attachment; BPF_HASH for associative arrays, BPF_PERF_OUTPUT for per-event data and BPF_RINGBUF_OUTPUT preferred on Linux 5.8 and later; open_perf_buffer, open_ring_buffer and perf_buffer_poll for consuming output; a cflags parameter passing arguments to the compiler at runtime.
  • bpftrace command-line documentation (bpftrace docs, release 0.26) — -e PROGRAM to "Execute PROGRAM instead of reading the program from a file or stdin"; -l [SEARCH] to "List all probes that match the SEARCH pattern"; -p PID to attach to or filter by a process; -c COMMAND to run a command as a child process; --dry-run to "Terminate execution right after attaching all the probes"; -f selecting json or text output; -B setting buffer mode to none, line or full; --unsafe to enable calls such as system; scripts runnable by filename or via a shebang.
  • BPF Portability and CO-RE (Andrii Nakryiko, February 2020) — the reference explanation of Compile Once Run Everywhere, linked from the libbpf-tools README as the background reading for why field offsets are relocated at load time against the running kernel's BTF rather than compiled against local headers.

Related resources


Built with yeet, a JS runtime for writing eBPF programs on Linux machines. Join us on discord.