github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/btf/format.go (about) 1 package btf 2 3 import ( 4 "errors" 5 "fmt" 6 "strings" 7 ) 8 9 var errNestedTooDeep = errors.New("nested too deep") 10 11 // GoFormatter converts a Type to Go syntax. 12 // 13 // A zero GoFormatter is valid to use. 14 type GoFormatter struct { 15 w strings.Builder 16 17 // Types present in this map are referred to using the given name if they 18 // are encountered when outputting another type. 19 Names map[Type]string 20 21 // Identifier is called for each field of struct-like types. By default the 22 // field name is used as is. 23 Identifier func(string) string 24 25 // EnumIdentifier is called for each element of an enum. By default the 26 // name of the enum type is concatenated with Identifier(element). 27 EnumIdentifier func(name, element string) string 28 } 29 30 // TypeDeclaration generates a Go type declaration for a BTF type. 31 func (gf *GoFormatter) TypeDeclaration(name string, typ Type) (string, error) { 32 gf.w.Reset() 33 if err := gf.writeTypeDecl(name, typ); err != nil { 34 return "", err 35 } 36 return gf.w.String(), nil 37 } 38 39 func (gf *GoFormatter) identifier(s string) string { 40 if gf.Identifier != nil { 41 return gf.Identifier(s) 42 } 43 44 return s 45 } 46 47 func (gf *GoFormatter) enumIdentifier(name, element string) string { 48 if gf.EnumIdentifier != nil { 49 return gf.EnumIdentifier(name, element) 50 } 51 52 return name + gf.identifier(element) 53 } 54 55 // writeTypeDecl outputs a declaration of the given type. 56 // 57 // It encodes https://golang.org/ref/spec#Type_declarations: 58 // 59 // type foo struct { bar uint32; } 60 // type bar int32 61 func (gf *GoFormatter) writeTypeDecl(name string, typ Type) error { 62 if name == "" { 63 return fmt.Errorf("need a name for type %s", typ) 64 } 65 66 typ = skipQualifiers(typ) 67 fmt.Fprintf(&gf.w, "type %s ", name) 68 if err := gf.writeTypeLit(typ, 0); err != nil { 69 return err 70 } 71 72 e, ok := typ.(*Enum) 73 if !ok || len(e.Values) == 0 { 74 return nil 75 } 76 77 gf.w.WriteString("; const ( ") 78 for _, ev := range e.Values { 79 id := gf.enumIdentifier(name, ev.Name) 80 var value any 81 if e.Signed { 82 value = int64(ev.Value) 83 } else { 84 value = ev.Value 85 } 86 fmt.Fprintf(&gf.w, "%s %s = %d; ", id, name, value) 87 } 88 gf.w.WriteString(")") 89 90 return nil 91 } 92 93 // writeType outputs the name of a named type or a literal describing the type. 94 // 95 // It encodes https://golang.org/ref/spec#Types. 96 // 97 // foo (if foo is a named type) 98 // uint32 99 func (gf *GoFormatter) writeType(typ Type, depth int) error { 100 typ = skipQualifiers(typ) 101 102 name := gf.Names[typ] 103 if name != "" { 104 gf.w.WriteString(name) 105 return nil 106 } 107 108 return gf.writeTypeLit(typ, depth) 109 } 110 111 // writeTypeLit outputs a literal describing the type. 112 // 113 // The function ignores named types. 114 // 115 // It encodes https://golang.org/ref/spec#TypeLit. 116 // 117 // struct { bar uint32; } 118 // uint32 119 func (gf *GoFormatter) writeTypeLit(typ Type, depth int) error { 120 depth++ 121 if depth > maxResolveDepth { 122 return errNestedTooDeep 123 } 124 125 var err error 126 switch v := skipQualifiers(typ).(type) { 127 case *Int: 128 err = gf.writeIntLit(v) 129 130 case *Enum: 131 if !v.Signed { 132 gf.w.WriteRune('u') 133 } 134 switch v.Size { 135 case 1: 136 gf.w.WriteString("int8") 137 case 2: 138 gf.w.WriteString("int16") 139 case 4: 140 gf.w.WriteString("int32") 141 case 8: 142 gf.w.WriteString("int64") 143 default: 144 err = fmt.Errorf("invalid enum size %d", v.Size) 145 } 146 147 case *Typedef: 148 err = gf.writeType(v.Type, depth) 149 150 case *Array: 151 fmt.Fprintf(&gf.w, "[%d]", v.Nelems) 152 err = gf.writeType(v.Type, depth) 153 154 case *Struct: 155 err = gf.writeStructLit(v.Size, v.Members, depth) 156 157 case *Union: 158 // Always choose the first member to represent the union in Go. 159 err = gf.writeStructLit(v.Size, v.Members[:1], depth) 160 161 case *Datasec: 162 err = gf.writeDatasecLit(v, depth) 163 164 default: 165 return fmt.Errorf("type %T: %w", v, ErrNotSupported) 166 } 167 168 if err != nil { 169 return fmt.Errorf("%s: %w", typ, err) 170 } 171 172 return nil 173 } 174 175 func (gf *GoFormatter) writeIntLit(i *Int) error { 176 bits := i.Size * 8 177 switch i.Encoding { 178 case Bool: 179 if i.Size != 1 { 180 return fmt.Errorf("bool with size %d", i.Size) 181 } 182 gf.w.WriteString("bool") 183 case Char: 184 if i.Size != 1 { 185 return fmt.Errorf("char with size %d", i.Size) 186 } 187 // BTF doesn't have a way to specify the signedness of a char. Assume 188 // we are dealing with unsigned, since this works nicely with []byte 189 // in Go code. 190 fallthrough 191 case Unsigned, Signed: 192 stem := "uint" 193 if i.Encoding == Signed { 194 stem = "int" 195 } 196 if i.Size > 8 { 197 fmt.Fprintf(&gf.w, "[%d]byte /* %s%d */", i.Size, stem, i.Size*8) 198 } else { 199 fmt.Fprintf(&gf.w, "%s%d", stem, bits) 200 } 201 default: 202 return fmt.Errorf("can't encode %s", i.Encoding) 203 } 204 return nil 205 } 206 207 func (gf *GoFormatter) writeStructLit(size uint32, members []Member, depth int) error { 208 gf.w.WriteString("struct { ") 209 210 prevOffset := uint32(0) 211 skippedBitfield := false 212 for i, m := range members { 213 if m.BitfieldSize > 0 { 214 skippedBitfield = true 215 continue 216 } 217 218 offset := m.Offset.Bytes() 219 if n := offset - prevOffset; skippedBitfield && n > 0 { 220 fmt.Fprintf(&gf.w, "_ [%d]byte /* unsupported bitfield */; ", n) 221 } else { 222 gf.writePadding(n) 223 } 224 225 fieldSize, err := Sizeof(m.Type) 226 if err != nil { 227 return fmt.Errorf("field %d: %w", i, err) 228 } 229 230 prevOffset = offset + uint32(fieldSize) 231 if prevOffset > size { 232 return fmt.Errorf("field %d of size %d exceeds type size %d", i, fieldSize, size) 233 } 234 235 if err := gf.writeStructField(m, depth); err != nil { 236 return fmt.Errorf("field %d: %w", i, err) 237 } 238 } 239 240 gf.writePadding(size - prevOffset) 241 gf.w.WriteString("}") 242 return nil 243 } 244 245 func (gf *GoFormatter) writeStructField(m Member, depth int) error { 246 if m.BitfieldSize > 0 { 247 return fmt.Errorf("bitfields are not supported") 248 } 249 if m.Offset%8 != 0 { 250 return fmt.Errorf("unsupported offset %d", m.Offset) 251 } 252 253 if m.Name == "" { 254 // Special case a nested anonymous union like 255 // struct foo { union { int bar; int baz }; } 256 // by replacing the whole union with its first member. 257 union, ok := m.Type.(*Union) 258 if !ok { 259 return fmt.Errorf("anonymous fields are not supported") 260 261 } 262 263 if len(union.Members) == 0 { 264 return errors.New("empty anonymous union") 265 } 266 267 depth++ 268 if depth > maxResolveDepth { 269 return errNestedTooDeep 270 } 271 272 m := union.Members[0] 273 size, err := Sizeof(m.Type) 274 if err != nil { 275 return err 276 } 277 278 if err := gf.writeStructField(m, depth); err != nil { 279 return err 280 } 281 282 gf.writePadding(union.Size - uint32(size)) 283 return nil 284 285 } 286 287 fmt.Fprintf(&gf.w, "%s ", gf.identifier(m.Name)) 288 289 if err := gf.writeType(m.Type, depth); err != nil { 290 return err 291 } 292 293 gf.w.WriteString("; ") 294 return nil 295 } 296 297 func (gf *GoFormatter) writeDatasecLit(ds *Datasec, depth int) error { 298 gf.w.WriteString("struct { ") 299 300 prevOffset := uint32(0) 301 for i, vsi := range ds.Vars { 302 v, ok := vsi.Type.(*Var) 303 if !ok { 304 return fmt.Errorf("can't format %s as part of data section", vsi.Type) 305 } 306 307 if v.Linkage != GlobalVar { 308 // Ignore static, extern, etc. for now. 309 continue 310 } 311 312 if v.Name == "" { 313 return fmt.Errorf("variable %d: empty name", i) 314 } 315 316 gf.writePadding(vsi.Offset - prevOffset) 317 prevOffset = vsi.Offset + vsi.Size 318 319 fmt.Fprintf(&gf.w, "%s ", gf.identifier(v.Name)) 320 321 if err := gf.writeType(v.Type, depth); err != nil { 322 return fmt.Errorf("variable %d: %w", i, err) 323 } 324 325 gf.w.WriteString("; ") 326 } 327 328 gf.writePadding(ds.Size - prevOffset) 329 gf.w.WriteString("}") 330 return nil 331 } 332 333 func (gf *GoFormatter) writePadding(bytes uint32) { 334 if bytes > 0 { 335 fmt.Fprintf(&gf.w, "_ [%d]byte; ", bytes) 336 } 337 } 338 339 func skipQualifiers(typ Type) Type { 340 result := typ 341 for depth := 0; depth <= maxResolveDepth; depth++ { 342 switch v := (result).(type) { 343 case qualifier: 344 result = v.qualify() 345 default: 346 return result 347 } 348 } 349 return &cycle{typ} 350 }