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