github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/internal/kallsyms/kallsyms.go (about) 1 package kallsyms 2 3 import ( 4 "bufio" 5 "bytes" 6 "io" 7 "os" 8 "sync" 9 ) 10 11 var kernelModules struct { 12 sync.RWMutex 13 // function to kernel module mapping 14 kmods map[string]string 15 } 16 17 // KernelModule returns the kernel module, if any, a probe-able function is contained in. 18 func KernelModule(fn string) (string, error) { 19 kernelModules.RLock() 20 kmods := kernelModules.kmods 21 kernelModules.RUnlock() 22 23 if kmods == nil { 24 kernelModules.Lock() 25 defer kernelModules.Unlock() 26 kmods = kernelModules.kmods 27 } 28 29 if kmods != nil { 30 return kmods[fn], nil 31 } 32 33 f, err := os.Open("/proc/kallsyms") 34 if err != nil { 35 return "", err 36 } 37 defer f.Close() 38 kmods, err = loadKernelModuleMapping(f) 39 if err != nil { 40 return "", err 41 } 42 43 kernelModules.kmods = kmods 44 return kmods[fn], nil 45 } 46 47 // FlushKernelModuleCache removes any cached information about function to kernel module mapping. 48 func FlushKernelModuleCache() { 49 kernelModules.Lock() 50 defer kernelModules.Unlock() 51 52 kernelModules.kmods = nil 53 } 54 55 func loadKernelModuleMapping(f io.Reader) (map[string]string, error) { 56 mods := make(map[string]string) 57 scanner := bufio.NewScanner(f) 58 for scanner.Scan() { 59 fields := bytes.Fields(scanner.Bytes()) 60 if len(fields) < 4 { 61 continue 62 } 63 switch string(fields[1]) { 64 case "t", "T": 65 mods[string(fields[2])] = string(bytes.Trim(fields[3], "[]")) 66 default: 67 continue 68 } 69 } 70 if scanner.Err() != nil { 71 return nil, scanner.Err() 72 } 73 return mods, nil 74 }