github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/btf/traversal.go (about) 1 package btf 2 3 import ( 4 "fmt" 5 ) 6 7 // Functions to traverse a cyclic graph of types. The below was very useful: 8 // https://eli.thegreenplace.net/2015/directed-graph-traversal-orderings-and-applications-to-data-flow-analysis/#post-order-and-reverse-post-order 9 10 // Visit all types reachable from root in postorder. 11 // 12 // Traversal stops if yield returns false. 13 // 14 // Returns false if traversal was aborted. 15 func visitInPostorder(root Type, visited map[Type]struct{}, yield func(typ Type) bool) bool { 16 if _, ok := visited[root]; ok { 17 return true 18 } 19 if visited == nil { 20 visited = make(map[Type]struct{}) 21 } 22 visited[root] = struct{}{} 23 24 cont := children(root, func(child *Type) bool { 25 return visitInPostorder(*child, visited, yield) 26 }) 27 if !cont { 28 return false 29 } 30 31 return yield(root) 32 } 33 34 // children calls yield on each child of typ. 35 // 36 // Traversal stops if yield returns false. 37 // 38 // Returns false if traversal was aborted. 39 func children(typ Type, yield func(child *Type) bool) bool { 40 // Explicitly type switch on the most common types to allow the inliner to 41 // do its work. This avoids allocating intermediate slices from walk() on 42 // the heap. 43 switch v := typ.(type) { 44 case *Void, *Int, *Enum, *Fwd, *Float: 45 // No children to traverse. 46 case *Pointer: 47 if !yield(&v.Target) { 48 return false 49 } 50 case *Array: 51 if !yield(&v.Index) { 52 return false 53 } 54 if !yield(&v.Type) { 55 return false 56 } 57 case *Struct: 58 for i := range v.Members { 59 if !yield(&v.Members[i].Type) { 60 return false 61 } 62 } 63 case *Union: 64 for i := range v.Members { 65 if !yield(&v.Members[i].Type) { 66 return false 67 } 68 } 69 case *Typedef: 70 if !yield(&v.Type) { 71 return false 72 } 73 case *Volatile: 74 if !yield(&v.Type) { 75 return false 76 } 77 case *Const: 78 if !yield(&v.Type) { 79 return false 80 } 81 case *Restrict: 82 if !yield(&v.Type) { 83 return false 84 } 85 case *Func: 86 if !yield(&v.Type) { 87 return false 88 } 89 case *FuncProto: 90 if !yield(&v.Return) { 91 return false 92 } 93 for i := range v.Params { 94 if !yield(&v.Params[i].Type) { 95 return false 96 } 97 } 98 case *Var: 99 if !yield(&v.Type) { 100 return false 101 } 102 case *Datasec: 103 for i := range v.Vars { 104 if !yield(&v.Vars[i].Type) { 105 return false 106 } 107 } 108 case *declTag: 109 if !yield(&v.Type) { 110 return false 111 } 112 case *typeTag: 113 if !yield(&v.Type) { 114 return false 115 } 116 case *cycle: 117 // cycle has children, but we ignore them deliberately. 118 default: 119 panic(fmt.Sprintf("don't know how to walk Type %T", v)) 120 } 121 122 return true 123 }