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