github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/examples/uretprobe/main.go (about) 1 // This program demonstrates how to attach an eBPF program to a uretprobe. 2 // The program will be attached to the 'readline' symbol in the binary '/bin/bash' and print out 3 // the line which 'readline' functions returns to the caller. 4 5 //go:build amd64 6 7 package main 8 9 import ( 10 "bytes" 11 "encoding/binary" 12 "errors" 13 "log" 14 "os" 15 "os/signal" 16 "syscall" 17 18 "github.com/cilium/ebpf/link" 19 "github.com/cilium/ebpf/perf" 20 "github.com/cilium/ebpf/rlimit" 21 "golang.org/x/sys/unix" 22 ) 23 24 //go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target amd64 -type event bpf uretprobe.c -- -I../headers 25 26 const ( 27 // The path to the ELF binary containing the function to trace. 28 // On some distributions, the 'readline' function is provided by a 29 // dynamically-linked library, so the path of the library will need 30 // to be specified instead, e.g. /usr/lib/libreadline.so.8. 31 // Use `ldd /bin/bash` to find these paths. 32 binPath = "/bin/bash" 33 symbol = "readline" 34 ) 35 36 func main() { 37 stopper := make(chan os.Signal, 1) 38 signal.Notify(stopper, os.Interrupt, syscall.SIGTERM) 39 40 // Allow the current process to lock memory for eBPF resources. 41 if err := rlimit.RemoveMemlock(); err != nil { 42 log.Fatal(err) 43 } 44 45 // Load pre-compiled programs and maps into the kernel. 46 objs := bpfObjects{} 47 if err := loadBpfObjects(&objs, nil); err != nil { 48 log.Fatalf("loading objects: %s", err) 49 } 50 defer objs.Close() 51 52 // Open an ELF binary and read its symbols. 53 ex, err := link.OpenExecutable(binPath) 54 if err != nil { 55 log.Fatalf("opening executable: %s", err) 56 } 57 58 // Open a Uretprobe at the exit point of the symbol and attach 59 // the pre-compiled eBPF program to it. 60 up, err := ex.Uretprobe(symbol, objs.UretprobeBashReadline, nil) 61 if err != nil { 62 log.Fatalf("creating uretprobe: %s", err) 63 } 64 defer up.Close() 65 66 // Open a perf event reader from userspace on the PERF_EVENT_ARRAY map 67 // described in the eBPF C program. 68 rd, err := perf.NewReader(objs.Events, os.Getpagesize()) 69 if err != nil { 70 log.Fatalf("creating perf event reader: %s", err) 71 } 72 defer rd.Close() 73 74 go func() { 75 // Wait for a signal and close the perf reader, 76 // which will interrupt rd.Read() and make the program exit. 77 <-stopper 78 log.Println("Received signal, exiting program..") 79 80 if err := rd.Close(); err != nil { 81 log.Fatalf("closing perf event reader: %s", err) 82 } 83 }() 84 85 log.Printf("Listening for events..") 86 87 // bpfEvent is generated by bpf2go. 88 var event bpfEvent 89 for { 90 record, err := rd.Read() 91 if err != nil { 92 if errors.Is(err, perf.ErrClosed) { 93 return 94 } 95 log.Printf("reading from perf event reader: %s", err) 96 continue 97 } 98 99 if record.LostSamples != 0 { 100 log.Printf("perf event ring buffer full, dropped %d samples", record.LostSamples) 101 continue 102 } 103 104 // Parse the perf event entry into a bpfEvent structure. 105 if err := binary.Read(bytes.NewBuffer(record.RawSample), binary.LittleEndian, &event); err != nil { 106 log.Printf("parsing perf event: %s", err) 107 continue 108 } 109 110 log.Printf("%s:%s return value: %s", binPath, symbol, unix.ByteSliceToString(event.Line[:])) 111 } 112 }