github.com/cilium/ebpf@v0.15.0/examples/tracepoint_in_go/main.go (about) 1 // This program demonstrates how to attach an eBPF program to a tracepoint. 2 // The program is attached to the syscall/sys_enter_openat tracepoint and 3 // prints out the integer 123 every time the syscall is entered. 4 package main 5 6 import ( 7 "errors" 8 "log" 9 "os" 10 "os/signal" 11 "syscall" 12 13 "github.com/cilium/ebpf" 14 "github.com/cilium/ebpf/asm" 15 "github.com/cilium/ebpf/link" 16 "github.com/cilium/ebpf/perf" 17 "github.com/cilium/ebpf/rlimit" 18 ) 19 20 // Metadata for the eBPF program used in this example. 21 var progSpec = &ebpf.ProgramSpec{ 22 Name: "my_trace_prog", // non-unique name, will appear in `bpftool prog list` while attached 23 Type: ebpf.TracePoint, // only TracePoint programs can be attached to trace events created by link.Tracepoint() 24 License: "GPL", // license must be GPL for calling kernel helpers like perf_event_output 25 } 26 27 func main() { 28 29 // Subscribe to signals for terminating the program. 30 stopper := make(chan os.Signal, 1) 31 signal.Notify(stopper, os.Interrupt, syscall.SIGTERM) 32 33 // Allow the current process to lock memory for eBPF resources. 34 if err := rlimit.RemoveMemlock(); err != nil { 35 log.Fatal(err) 36 } 37 38 // Create a perf event array for the kernel to write perf records to. 39 // These records will be read by userspace below. 40 events, err := ebpf.NewMap(&ebpf.MapSpec{ 41 Type: ebpf.PerfEventArray, 42 Name: "my_perf_array", 43 }) 44 if err != nil { 45 log.Fatalf("creating perf event array: %s", err) 46 } 47 defer events.Close() 48 49 // Open a perf reader from userspace into the perf event array 50 // created earlier. 51 rd, err := perf.NewReader(events, os.Getpagesize()) 52 if err != nil { 53 log.Fatalf("creating event 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 rd.Close() 62 }() 63 64 // Minimal program that writes the static value '123' to the perf ring on 65 // each event. Note that this program refers to the file descriptor of 66 // the perf event array created above, which needs to be created prior to the 67 // program being verified by and inserted into the kernel. 68 progSpec.Instructions = asm.Instructions{ 69 // store the integer 123 at FP[-8] 70 asm.Mov.Imm(asm.R2, 123), 71 asm.StoreMem(asm.RFP, -8, asm.R2, asm.Word), 72 73 // load registers with arguments for call of FnPerfEventOutput 74 asm.LoadMapPtr(asm.R2, events.FD()), // file descriptor of the perf event array 75 asm.LoadImm(asm.R3, 0xffffffff, asm.DWord), 76 asm.Mov.Reg(asm.R4, asm.RFP), 77 asm.Add.Imm(asm.R4, -8), 78 asm.Mov.Imm(asm.R5, 4), 79 80 // call FnPerfEventOutput, an eBPF kernel helper 81 asm.FnPerfEventOutput.Call(), 82 83 // set exit code to 0 84 asm.Mov.Imm(asm.R0, 0), 85 asm.Return(), 86 } 87 88 // Instantiate and insert the program into the kernel. 89 prog, err := ebpf.NewProgram(progSpec) 90 if err != nil { 91 log.Fatalf("creating ebpf program: %s", err) 92 } 93 defer prog.Close() 94 95 // Open a trace event based on a pre-existing kernel hook (tracepoint). 96 // Each time a userspace program uses the 'openat()' syscall, the eBPF 97 // program specified above will be executed and a '123' value will appear 98 // in the perf ring. 99 tp, err := link.Tracepoint("syscalls", "sys_enter_openat", prog, nil) 100 if err != nil { 101 log.Fatalf("opening tracepoint: %s", err) 102 } 103 defer tp.Close() 104 105 log.Println("Waiting for events..") 106 107 for { 108 record, err := rd.Read() 109 if err != nil { 110 if errors.Is(err, perf.ErrClosed) { 111 log.Println("Received signal, exiting..") 112 return 113 } 114 log.Printf("reading from reader: %s", err) 115 continue 116 } 117 118 log.Println("Record:", record) 119 } 120 }