github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/examples/ringbuffer/main.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"errors"
     7  	"log"
     8  	"os"
     9  	"os/signal"
    10  	"syscall"
    11  
    12  	"github.com/cilium/ebpf/link"
    13  	"github.com/cilium/ebpf/ringbuf"
    14  	"github.com/cilium/ebpf/rlimit"
    15  	"golang.org/x/sys/unix"
    16  )
    17  
    18  //go:generate go run github.com/cilium/ebpf/cmd/bpf2go -type event bpf ringbuffer.c -- -I../headers
    19  
    20  func main() {
    21  	// Name of the kernel function to trace.
    22  	fn := "sys_execve"
    23  
    24  	// Subscribe to signals for terminating the program.
    25  	stopper := make(chan os.Signal, 1)
    26  	signal.Notify(stopper, os.Interrupt, syscall.SIGTERM)
    27  
    28  	// Allow the current process to lock memory for eBPF resources.
    29  	if err := rlimit.RemoveMemlock(); err != nil {
    30  		log.Fatal(err)
    31  	}
    32  
    33  	// Load pre-compiled programs and maps into the kernel.
    34  	objs := bpfObjects{}
    35  	if err := loadBpfObjects(&objs, nil); err != nil {
    36  		log.Fatalf("loading objects: %v", err)
    37  	}
    38  	defer objs.Close()
    39  
    40  	// Open a Kprobe at the entry point of the kernel function and attach the
    41  	// pre-compiled program. Each time the kernel function enters, the program
    42  	// will emit an event containing pid and command of the execved task.
    43  	kp, err := link.Kprobe(fn, objs.KprobeExecve, nil)
    44  	if err != nil {
    45  		log.Fatalf("opening kprobe: %s", err)
    46  	}
    47  	defer kp.Close()
    48  
    49  	// Open a ringbuf reader from userspace RINGBUF map described in the
    50  	// eBPF C program.
    51  	rd, err := ringbuf.NewReader(objs.Events)
    52  	if err != nil {
    53  		log.Fatalf("opening ringbuf reader: %s", err)
    54  	}
    55  	defer rd.Close()
    56  
    57  	// Close the reader when the process receives a signal, which will exit
    58  	// the read loop.
    59  	go func() {
    60  		<-stopper
    61  
    62  		if err := rd.Close(); err != nil {
    63  			log.Fatalf("closing ringbuf reader: %s", err)
    64  		}
    65  	}()
    66  
    67  	log.Println("Waiting for events..")
    68  
    69  	// bpfEvent is generated by bpf2go.
    70  	var event bpfEvent
    71  	for {
    72  		record, err := rd.Read()
    73  		if err != nil {
    74  			if errors.Is(err, ringbuf.ErrClosed) {
    75  				log.Println("Received signal, exiting..")
    76  				return
    77  			}
    78  			log.Printf("reading from reader: %s", err)
    79  			continue
    80  		}
    81  
    82  		// Parse the ringbuf event entry into a bpfEvent structure.
    83  		if err := binary.Read(bytes.NewBuffer(record.RawSample), binary.LittleEndian, &event); err != nil {
    84  			log.Printf("parsing ringbuf event: %s", err)
    85  			continue
    86  		}
    87  
    88  		log.Printf("pid: %d\tcomm: %s\n", event.Pid, unix.ByteSliceToString(event.Comm[:]))
    89  	}
    90  }