github.com/cilium/ebpf@v0.10.0/examples/kprobepin/main.go (about)

     1  // This program demonstrates attaching an eBPF program to a kernel symbol.
     2  // The eBPF program will be attached to the start of the sys_execve
     3  // kernel function and prints out the number of times it has been called
     4  // every second.
     5  package main
     6  
     7  import (
     8  	"log"
     9  	"os"
    10  	"path"
    11  	"time"
    12  
    13  	"github.com/cilium/ebpf"
    14  	"github.com/cilium/ebpf/link"
    15  	"github.com/cilium/ebpf/rlimit"
    16  )
    17  
    18  // $BPF_CLANG and $BPF_CFLAGS are set by the Makefile.
    19  //go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc $BPF_CLANG -cflags $BPF_CFLAGS bpf kprobe_pin.c -- -I../headers
    20  
    21  const (
    22  	mapKey    uint32 = 0
    23  	bpfFSPath        = "/sys/fs/bpf"
    24  )
    25  
    26  func main() {
    27  
    28  	// Name of the kernel function to trace.
    29  	fn := "sys_execve"
    30  
    31  	// Allow the current process to lock memory for eBPF resources.
    32  	if err := rlimit.RemoveMemlock(); err != nil {
    33  		log.Fatal(err)
    34  	}
    35  
    36  	pinPath := path.Join(bpfFSPath, fn)
    37  	if err := os.MkdirAll(pinPath, os.ModePerm); err != nil {
    38  		log.Fatalf("failed to create bpf fs subpath: %+v", err)
    39  	}
    40  
    41  	var objs bpfObjects
    42  	if err := loadBpfObjects(&objs, &ebpf.CollectionOptions{
    43  		Maps: ebpf.MapOptions{
    44  			// Pin the map to the BPF filesystem and configure the
    45  			// library to automatically re-write it in the BPF
    46  			// program so it can be re-used if it already exists or
    47  			// create it if not
    48  			PinPath: pinPath,
    49  		},
    50  	}); err != nil {
    51  		log.Fatalf("loading objects: %v", err)
    52  	}
    53  	defer objs.Close()
    54  
    55  	// Open a Kprobe at the entry point of the kernel function and attach the
    56  	// pre-compiled program. Each time the kernel function enters, the program
    57  	// will increment the execution counter by 1. The read loop below polls this
    58  	// map value once per second.
    59  	kp, err := link.Kprobe(fn, objs.KprobeExecve, nil)
    60  	if err != nil {
    61  		log.Fatalf("opening kprobe: %s", err)
    62  	}
    63  	defer kp.Close()
    64  
    65  	// Read loop reporting the total amount of times the kernel
    66  	// function was entered, once per second.
    67  	ticker := time.NewTicker(1 * time.Second)
    68  	defer ticker.Stop()
    69  
    70  	log.Println("Waiting for events..")
    71  
    72  	for range ticker.C {
    73  		var value uint64
    74  		if err := objs.KprobeMap.Lookup(mapKey, &value); err != nil {
    75  			log.Fatalf("reading map: %v", err)
    76  		}
    77  		log.Printf("%s called %d times\n", fn, value)
    78  	}
    79  }