033 Project 33: eBPF Tracepoint Basics

033 Build eBPF Tracepoint Basics

Capture process exec events from sys_enter_execve using eBPF.

kernel tracepoint -> eBPF program -> ring/perf buffer -> userspace reader

Setup

go mod init example.com/ebpf-trace
go get github.com/cilium/ebpf@latest
# also install clang/llvm and bpf2go tooling

Files

  1. main.go userspace loader/reader
  2. exec.bpf.c kernel-side program
  3. generated exec_bpfel.go from bpf2go

main.go (userspace)

package main

import (
    "bytes"
    "encoding/binary"
    "fmt"
    "log"
    "os"
    "os/signal"

    "github.com/cilium/ebpf/link"
    "github.com/cilium/ebpf/perf"
)

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

func main() {
    objs := bpfObjects{}
    if err := loadBpfObjects(&objs, nil); err != nil {
        log.Fatal(err)
    }
    defer objs.Close()

    tp, err := link.Tracepoint("syscalls", "sys_enter_execve", objs.HandleExec, nil)
    if err != nil {
        log.Fatal(err)
    }
    defer tp.Close()

    rd, err := perf.NewReader(objs.Events, os.Getpagesize())
    if err != nil {
        log.Fatal(err)
    }
    defer rd.Close()

    sig := make(chan os.Signal, 1)
    signal.Notify(sig, os.Interrupt)
    go func() { <-sig; _ = rd.Close() }()

    for {
        rec, err := rd.Read()
        if err != nil {
            break
        }
        var e event
        if err := binary.Read(bytes.NewBuffer(rec.RawSample), binary.LittleEndian, &e); err != nil {
            continue
        }
        fmt.Printf("pid=%d comm=%s\n", e.Pid, bytes.TrimRight(e.Comm[:], "\x00"))
    }
}

Notes

  • Requires Linux kernel with eBPF support.
  • Run with root privileges.
  • This is a lab starter; add filtering and structured output next.

Step-by-Step Explanation

  1. Keep kernel-side eBPF logic minimal and focused.
  2. Load and attach program from userspace.
  3. Stream events or counters from maps/buffers.
  4. Handle shutdown and detachment cleanly.
  5. Validate behavior in an isolated Linux lab environment.

Code Anatomy

  • eBPF program runs in kernel hook.
  • Userspace Go loader manages attach/read lifecycle.
  • Reader loop transforms low-level events into readable output.

Learning Goals

  • Understand event-driven observability close to the kernel.
  • Learn safe iteration practices for low-level tooling.
  • Build confidence with modern Linux instrumentation.