Map

gobee — README

gobee — README

Source: https://github.com/boratanrikulu/gobee (fetched via gh api on 2026-05-22)

Metadata: MIT, Go, 25 stars at fetch time, created 2026-05-01, language Go, topics: bpf, cilium-ebpf, ebpf, golang, kernel, linux, transpiler. Author: Bora Tanrıkulu me@bora.sh.

Note: user-provided URL was github.com/boratanrikulu/gobeeq (404). The correct repo for Bora's Go-to-BPF transpiler is boratanrikulu/gobee.


gobee

Write your BPF programs in Go, not C. gobee transpiles a strict subset of Go into BPF C, generates typed Go bindings for the userspace side, and gates loads against the running kernel.

The Go ecosystem has solid userspace tooling for BPF. The kernel side has always ended with "now write your program in C." Aya brought eBPF to Rust by writing a new BPF backend in rustc. gobee gets there a different way: by transpiling to C and reusing clang's mature backend.

A Go file in, a BPF program out

A tracepoint that streams every execve to userspace via a ringbuf:

//go:build ignore

package main

import "github.com/boratanrikulu/gobee/bpf"

//bpf:license GPL

type Event struct {
    Pid  uint32
    Comm [16]byte
}

var Events = bpf.RingBuf[Event]{
    MaxEntries: 4096,
}

//bpf:section tracepoint/syscalls/sys_enter_execve
func OnExec(ctx *bpf.ExecveEnterCtx) bpf.TpReturn {
    e, ok := Events.Reserve()
    if !ok {
        return bpf.TpOk
    }
    e.Pid = bpf.GetCurrentPid()
    bpf.GetTaskComm(&e.Comm)
    Events.Submit(e)
    return bpf.TpOk
}

func main() {}

gobee translate --bindings-dir ./bpf ./bpf/src produces both .bpf.c and typed bindings, plus a sourcemap (events.bpf.c.map) so verifier errors map back to Go lines and a typed bindings file (bpf/events_bindings.go) so the userspace driver writes objs.Events, objs.AttachOnExec(), and decodes ringbuf payloads straight into bpf.Event instead of stringly-typed coll.Programs["..."] lookups.

The C is readable on purpose. If gobee emits something weird, you can see it. For tracepoints + kprobes + XDP combined into one binary, see example/sysmon/.

How it compares

gobee C + clang + bpf2go Aya (Rust) bpftrace BCC
Kernel-side language Go subset C Rust DSL C
Userspace integration typed Go bindings + cilium/ebpf bpf2go aya-runtime none python
CO-RE ✅ via clang ✅ via LLVM
Helper coverage 200 typed Go wrappers full (write C) full limited full (write C)
Verifier error → source ✅ Go file:line:col ❌ raw C ✅ Rust file:line partial
Kernel-version gate at load ✅ via bpfvet manual manual n/a runtime
Toolchain deps Go + clang clang + bpf2go rustc + LLVM bpftrace python + bcc
Generated artifact .bpf.o + Go binary .bpf.o + Go binary .bpf.o + Rust binary JIT JIT

What's supported today

Surface Coverage
Program types (8) XDP, tracepoint, kprobe/kretprobe, uprobe/uretprobe, sock_ops, TC, cgroup_skb, LSM
Map types (19) array, hash, lru_hash, per-CPU variants, bloom_filter, lpm_trie, ringbuf, perf_event_array, prog_array, queue, stack, sk/task/inode storage, devmap/cpumap/xskmap
BPF helpers ~200 typed Go stubs from libbpf v1.5.0 headers; subset exercised in real-kernel CI
CO-RE auto-detected; BPF_CORE_READ for kernel-internal struct fields, direct ctx->field for UAPI BPF context structs
User-defined helpers top-level Go funcs without //bpf:section emitted as static __always_inline
Verifier error → Go source auto-annotated inside Load<Stem>; *ebpf.VerifierError includes → counter.go:18:5 markers
Sourcemap sidecar <stem>.bpf.c.map written next to every .bpf.c
Kernel-version gate bpfvet runs at load time; fails fast with bpf program needs kernel >= 5.8, host is 5.4 instead of EINVAL
Cross-arch Linux arm64 + amd64

What gobee won't do

  • Replace clang (clang's BPF backend gives CO-RE, BTF, verifier-friendly codegen for free — multi-year reimplementation cost).
  • Replace cilium/ebpf (generated bindings sit on top of it).
  • Hide BPF (Go subset maps 1:1 to BPF C idioms).
  • Run clang for you (compile/embed/load remain user-owned; same pattern as bpf2go).

Why transpile, not generate BPF directly

gc, the Go compiler, has no LLVM-based BPF backend. Adding one is a multi-year compiler project. rustc is built on LLVM and that's why Aya works. So gobee emits C and reuses clang's BPF backend, which gives us mature codegen, BTF, and CO-RE relocations for free.

Quickstart

go install github.com/boratanrikulu/gobee/cmd/gobee@latest
cd example/helloworld
make build                     # gobee translate, clang, go build
sudo ./helloworld eth0

Inspirations

  • Solod: the Go-to-C transpiler that proved this pattern works.
  • Aya: the Rust eBPF framework whose ergonomics gobee chases.

License

MIT.