github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/btf/marshal.go (about) 1 package btf 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "errors" 7 "fmt" 8 "maps" 9 "math" 10 "slices" 11 "sync" 12 13 "github.com/cilium/ebpf/internal" 14 ) 15 16 type MarshalOptions struct { 17 // Target byte order. Defaults to the system's native endianness. 18 Order binary.ByteOrder 19 // Remove function linkage information for compatibility with <5.6 kernels. 20 StripFuncLinkage bool 21 // Replace Enum64 with a placeholder for compatibility with <6.0 kernels. 22 ReplaceEnum64 bool 23 // Prevent the "No type found" error when loading BTF without any types. 24 PreventNoTypeFound bool 25 } 26 27 // KernelMarshalOptions will generate BTF suitable for the current kernel. 28 func KernelMarshalOptions() *MarshalOptions { 29 return &MarshalOptions{ 30 Order: internal.NativeEndian, 31 StripFuncLinkage: haveFuncLinkage() != nil, 32 ReplaceEnum64: haveEnum64() != nil, 33 PreventNoTypeFound: true, // All current kernels require this. 34 } 35 } 36 37 // encoder turns Types into raw BTF. 38 type encoder struct { 39 MarshalOptions 40 41 pending internal.Deque[Type] 42 buf *bytes.Buffer 43 strings *stringTableBuilder 44 ids map[Type]TypeID 45 visited map[Type]struct{} 46 lastID TypeID 47 } 48 49 var bufferPool = sync.Pool{ 50 New: func() any { 51 buf := make([]byte, btfHeaderLen+128) 52 return &buf 53 }, 54 } 55 56 func getByteSlice() *[]byte { 57 return bufferPool.Get().(*[]byte) 58 } 59 60 func putByteSlice(buf *[]byte) { 61 *buf = (*buf)[:0] 62 bufferPool.Put(buf) 63 } 64 65 // Builder turns Types into raw BTF. 66 // 67 // The default value may be used and represents an empty BTF blob. Void is 68 // added implicitly if necessary. 69 type Builder struct { 70 // Explicitly added types. 71 types []Type 72 // IDs for all added types which the user knows about. 73 stableIDs map[Type]TypeID 74 // Explicitly added strings. 75 strings *stringTableBuilder 76 } 77 78 // NewBuilder creates a Builder from a list of types. 79 // 80 // It is more efficient than calling [Add] individually. 81 // 82 // Returns an error if adding any of the types fails. 83 func NewBuilder(types []Type) (*Builder, error) { 84 b := &Builder{ 85 make([]Type, 0, len(types)), 86 make(map[Type]TypeID, len(types)), 87 nil, 88 } 89 90 for _, typ := range types { 91 _, err := b.Add(typ) 92 if err != nil { 93 return nil, fmt.Errorf("add %s: %w", typ, err) 94 } 95 } 96 97 return b, nil 98 } 99 100 // Empty returns true if neither types nor strings have been added. 101 func (b *Builder) Empty() bool { 102 return len(b.types) == 0 && (b.strings == nil || b.strings.Length() == 0) 103 } 104 105 // Add a Type and allocate a stable ID for it. 106 // 107 // Adding the identical Type multiple times is valid and will return the same ID. 108 // 109 // See [Type] for details on identity. 110 func (b *Builder) Add(typ Type) (TypeID, error) { 111 if b.stableIDs == nil { 112 b.stableIDs = make(map[Type]TypeID) 113 } 114 115 if _, ok := typ.(*Void); ok { 116 // Equality is weird for void, since it is a zero sized type. 117 return 0, nil 118 } 119 120 if ds, ok := typ.(*Datasec); ok { 121 if err := datasecResolveWorkaround(b, ds); err != nil { 122 return 0, err 123 } 124 } 125 126 id, ok := b.stableIDs[typ] 127 if ok { 128 return id, nil 129 } 130 131 b.types = append(b.types, typ) 132 133 id = TypeID(len(b.types)) 134 if int(id) != len(b.types) { 135 return 0, fmt.Errorf("no more type IDs") 136 } 137 138 b.stableIDs[typ] = id 139 return id, nil 140 } 141 142 // Marshal encodes all types in the Marshaler into BTF wire format. 143 // 144 // opts may be nil. 145 func (b *Builder) Marshal(buf []byte, opts *MarshalOptions) ([]byte, error) { 146 stb := b.strings 147 if stb == nil { 148 // Assume that most types are named. This makes encoding large BTF like 149 // vmlinux a lot cheaper. 150 stb = newStringTableBuilder(len(b.types)) 151 } else { 152 // Avoid modifying the Builder's string table. 153 stb = b.strings.Copy() 154 } 155 156 if opts == nil { 157 opts = &MarshalOptions{Order: internal.NativeEndian} 158 } 159 160 // Reserve space for the BTF header. 161 buf = slices.Grow(buf, btfHeaderLen)[:btfHeaderLen] 162 163 w := internal.NewBuffer(buf) 164 defer internal.PutBuffer(w) 165 166 e := encoder{ 167 MarshalOptions: *opts, 168 buf: w, 169 strings: stb, 170 lastID: TypeID(len(b.types)), 171 visited: make(map[Type]struct{}, len(b.types)), 172 ids: maps.Clone(b.stableIDs), 173 } 174 175 if e.ids == nil { 176 e.ids = make(map[Type]TypeID) 177 } 178 179 types := b.types 180 if len(types) == 0 && stb.Length() > 0 && opts.PreventNoTypeFound { 181 // We have strings that need to be written out, 182 // but no types (besides the implicit Void). 183 // Kernels as recent as v6.7 refuse to load such BTF 184 // with a "No type found" error in the log. 185 // Fix this by adding a dummy type. 186 types = []Type{&Int{Size: 0}} 187 } 188 189 // Ensure that types are marshaled in the exact order they were Add()ed. 190 // Otherwise the ID returned from Add() won't match. 191 e.pending.Grow(len(types)) 192 for _, typ := range types { 193 e.pending.Push(typ) 194 } 195 196 if err := e.deflatePending(); err != nil { 197 return nil, err 198 } 199 200 length := e.buf.Len() 201 typeLen := uint32(length - btfHeaderLen) 202 203 stringLen := e.strings.Length() 204 buf = e.strings.AppendEncoded(e.buf.Bytes()) 205 206 // Fill out the header, and write it out. 207 header := &btfHeader{ 208 Magic: btfMagic, 209 Version: 1, 210 Flags: 0, 211 HdrLen: uint32(btfHeaderLen), 212 TypeOff: 0, 213 TypeLen: typeLen, 214 StringOff: typeLen, 215 StringLen: uint32(stringLen), 216 } 217 218 err := binary.Write(sliceWriter(buf[:btfHeaderLen]), e.Order, header) 219 if err != nil { 220 return nil, fmt.Errorf("write header: %v", err) 221 } 222 223 return buf, nil 224 } 225 226 // addString adds a string to the resulting BTF. 227 // 228 // Adding the same string multiple times will return the same result. 229 // 230 // Returns an identifier into the string table or an error if the string 231 // contains invalid characters. 232 func (b *Builder) addString(str string) (uint32, error) { 233 if b.strings == nil { 234 b.strings = newStringTableBuilder(0) 235 } 236 237 return b.strings.Add(str) 238 } 239 240 func (e *encoder) allocateIDs(root Type) (err error) { 241 visitInPostorder(root, e.visited, func(typ Type) bool { 242 if _, ok := typ.(*Void); ok { 243 return true 244 } 245 246 if _, ok := e.ids[typ]; ok { 247 return true 248 } 249 250 id := e.lastID + 1 251 if id < e.lastID { 252 err = errors.New("type ID overflow") 253 return false 254 } 255 256 e.pending.Push(typ) 257 e.ids[typ] = id 258 e.lastID = id 259 return true 260 }) 261 return 262 } 263 264 // id returns the ID for the given type or panics with an error. 265 func (e *encoder) id(typ Type) TypeID { 266 if _, ok := typ.(*Void); ok { 267 return 0 268 } 269 270 id, ok := e.ids[typ] 271 if !ok { 272 panic(fmt.Errorf("no ID for type %v", typ)) 273 } 274 275 return id 276 } 277 278 func (e *encoder) deflatePending() error { 279 // Declare root outside of the loop to avoid repeated heap allocations. 280 var root Type 281 282 for !e.pending.Empty() { 283 root = e.pending.Shift() 284 285 // Allocate IDs for all children of typ, including transitive dependencies. 286 if err := e.allocateIDs(root); err != nil { 287 return err 288 } 289 290 if err := e.deflateType(root); err != nil { 291 id := e.ids[root] 292 return fmt.Errorf("deflate %v with ID %d: %w", root, id, err) 293 } 294 } 295 296 return nil 297 } 298 299 func (e *encoder) deflateType(typ Type) (err error) { 300 defer func() { 301 if r := recover(); r != nil { 302 var ok bool 303 err, ok = r.(error) 304 if !ok { 305 panic(r) 306 } 307 } 308 }() 309 310 var raw rawType 311 raw.NameOff, err = e.strings.Add(typ.TypeName()) 312 if err != nil { 313 return err 314 } 315 316 switch v := typ.(type) { 317 case *Void: 318 return errors.New("Void is implicit in BTF wire format") 319 320 case *Int: 321 raw.SetKind(kindInt) 322 raw.SetSize(v.Size) 323 324 var bi btfInt 325 bi.SetEncoding(v.Encoding) 326 // We need to set bits in addition to size, since btf_type_int_is_regular 327 // otherwise flags this as a bitfield. 328 bi.SetBits(byte(v.Size) * 8) 329 raw.data = bi 330 331 case *Pointer: 332 raw.SetKind(kindPointer) 333 raw.SetType(e.id(v.Target)) 334 335 case *Array: 336 raw.SetKind(kindArray) 337 raw.data = &btfArray{ 338 e.id(v.Type), 339 e.id(v.Index), 340 v.Nelems, 341 } 342 343 case *Struct: 344 raw.SetKind(kindStruct) 345 raw.SetSize(v.Size) 346 raw.data, err = e.convertMembers(&raw.btfType, v.Members) 347 348 case *Union: 349 err = e.deflateUnion(&raw, v) 350 351 case *Enum: 352 if v.Size == 8 { 353 err = e.deflateEnum64(&raw, v) 354 } else { 355 err = e.deflateEnum(&raw, v) 356 } 357 358 case *Fwd: 359 raw.SetKind(kindForward) 360 raw.SetFwdKind(v.Kind) 361 362 case *Typedef: 363 raw.SetKind(kindTypedef) 364 raw.SetType(e.id(v.Type)) 365 366 case *Volatile: 367 raw.SetKind(kindVolatile) 368 raw.SetType(e.id(v.Type)) 369 370 case *Const: 371 raw.SetKind(kindConst) 372 raw.SetType(e.id(v.Type)) 373 374 case *Restrict: 375 raw.SetKind(kindRestrict) 376 raw.SetType(e.id(v.Type)) 377 378 case *Func: 379 raw.SetKind(kindFunc) 380 raw.SetType(e.id(v.Type)) 381 if !e.StripFuncLinkage { 382 raw.SetLinkage(v.Linkage) 383 } 384 385 case *FuncProto: 386 raw.SetKind(kindFuncProto) 387 raw.SetType(e.id(v.Return)) 388 raw.SetVlen(len(v.Params)) 389 raw.data, err = e.deflateFuncParams(v.Params) 390 391 case *Var: 392 raw.SetKind(kindVar) 393 raw.SetType(e.id(v.Type)) 394 raw.data = btfVariable{uint32(v.Linkage)} 395 396 case *Datasec: 397 raw.SetKind(kindDatasec) 398 raw.SetSize(v.Size) 399 raw.SetVlen(len(v.Vars)) 400 raw.data = e.deflateVarSecinfos(v.Vars) 401 402 case *Float: 403 raw.SetKind(kindFloat) 404 raw.SetSize(v.Size) 405 406 case *declTag: 407 raw.SetKind(kindDeclTag) 408 raw.SetType(e.id(v.Type)) 409 raw.data = &btfDeclTag{uint32(v.Index)} 410 raw.NameOff, err = e.strings.Add(v.Value) 411 412 case *typeTag: 413 raw.SetKind(kindTypeTag) 414 raw.SetType(e.id(v.Type)) 415 raw.NameOff, err = e.strings.Add(v.Value) 416 417 default: 418 return fmt.Errorf("don't know how to deflate %T", v) 419 } 420 421 if err != nil { 422 return err 423 } 424 425 return raw.Marshal(e.buf, e.Order) 426 } 427 428 func (e *encoder) deflateUnion(raw *rawType, union *Union) (err error) { 429 raw.SetKind(kindUnion) 430 raw.SetSize(union.Size) 431 raw.data, err = e.convertMembers(&raw.btfType, union.Members) 432 return 433 } 434 435 func (e *encoder) convertMembers(header *btfType, members []Member) ([]btfMember, error) { 436 bms := make([]btfMember, 0, len(members)) 437 isBitfield := false 438 for _, member := range members { 439 isBitfield = isBitfield || member.BitfieldSize > 0 440 441 offset := member.Offset 442 if isBitfield { 443 offset = member.BitfieldSize<<24 | (member.Offset & 0xffffff) 444 } 445 446 nameOff, err := e.strings.Add(member.Name) 447 if err != nil { 448 return nil, err 449 } 450 451 bms = append(bms, btfMember{ 452 nameOff, 453 e.id(member.Type), 454 uint32(offset), 455 }) 456 } 457 458 header.SetVlen(len(members)) 459 header.SetBitfield(isBitfield) 460 return bms, nil 461 } 462 463 func (e *encoder) deflateEnum(raw *rawType, enum *Enum) (err error) { 464 raw.SetKind(kindEnum) 465 raw.SetSize(enum.Size) 466 raw.SetVlen(len(enum.Values)) 467 // Signedness appeared together with ENUM64 support. 468 raw.SetSigned(enum.Signed && !e.ReplaceEnum64) 469 raw.data, err = e.deflateEnumValues(enum) 470 return 471 } 472 473 func (e *encoder) deflateEnumValues(enum *Enum) ([]btfEnum, error) { 474 bes := make([]btfEnum, 0, len(enum.Values)) 475 for _, value := range enum.Values { 476 nameOff, err := e.strings.Add(value.Name) 477 if err != nil { 478 return nil, err 479 } 480 481 if enum.Signed { 482 if signedValue := int64(value.Value); signedValue < math.MinInt32 || signedValue > math.MaxInt32 { 483 return nil, fmt.Errorf("value %d of enum %q exceeds 32 bits", signedValue, value.Name) 484 } 485 } else { 486 if value.Value > math.MaxUint32 { 487 return nil, fmt.Errorf("value %d of enum %q exceeds 32 bits", value.Value, value.Name) 488 } 489 } 490 491 bes = append(bes, btfEnum{ 492 nameOff, 493 uint32(value.Value), 494 }) 495 } 496 497 return bes, nil 498 } 499 500 func (e *encoder) deflateEnum64(raw *rawType, enum *Enum) (err error) { 501 if e.ReplaceEnum64 { 502 // Replace the ENUM64 with a union of fields with the correct size. 503 // This matches libbpf behaviour on purpose. 504 placeholder := &Int{ 505 "enum64_placeholder", 506 enum.Size, 507 Unsigned, 508 } 509 if enum.Signed { 510 placeholder.Encoding = Signed 511 } 512 if err := e.allocateIDs(placeholder); err != nil { 513 return fmt.Errorf("add enum64 placeholder: %w", err) 514 } 515 516 members := make([]Member, 0, len(enum.Values)) 517 for _, v := range enum.Values { 518 members = append(members, Member{ 519 Name: v.Name, 520 Type: placeholder, 521 }) 522 } 523 524 return e.deflateUnion(raw, &Union{enum.Name, enum.Size, members}) 525 } 526 527 raw.SetKind(kindEnum64) 528 raw.SetSize(enum.Size) 529 raw.SetVlen(len(enum.Values)) 530 raw.SetSigned(enum.Signed) 531 raw.data, err = e.deflateEnum64Values(enum.Values) 532 return 533 } 534 535 func (e *encoder) deflateEnum64Values(values []EnumValue) ([]btfEnum64, error) { 536 bes := make([]btfEnum64, 0, len(values)) 537 for _, value := range values { 538 nameOff, err := e.strings.Add(value.Name) 539 if err != nil { 540 return nil, err 541 } 542 543 bes = append(bes, btfEnum64{ 544 nameOff, 545 uint32(value.Value), 546 uint32(value.Value >> 32), 547 }) 548 } 549 550 return bes, nil 551 } 552 553 func (e *encoder) deflateFuncParams(params []FuncParam) ([]btfParam, error) { 554 bps := make([]btfParam, 0, len(params)) 555 for _, param := range params { 556 nameOff, err := e.strings.Add(param.Name) 557 if err != nil { 558 return nil, err 559 } 560 561 bps = append(bps, btfParam{ 562 nameOff, 563 e.id(param.Type), 564 }) 565 } 566 return bps, nil 567 } 568 569 func (e *encoder) deflateVarSecinfos(vars []VarSecinfo) []btfVarSecinfo { 570 vsis := make([]btfVarSecinfo, 0, len(vars)) 571 for _, v := range vars { 572 vsis = append(vsis, btfVarSecinfo{ 573 e.id(v.Type), 574 v.Offset, 575 v.Size, 576 }) 577 } 578 return vsis 579 } 580 581 // MarshalMapKV creates a BTF object containing a map key and value. 582 // 583 // The function is intended for the use of the ebpf package and may be removed 584 // at any point in time. 585 func MarshalMapKV(key, value Type) (_ *Handle, keyID, valueID TypeID, err error) { 586 var b Builder 587 588 if key != nil { 589 keyID, err = b.Add(key) 590 if err != nil { 591 return nil, 0, 0, fmt.Errorf("add key type: %w", err) 592 } 593 } 594 595 if value != nil { 596 valueID, err = b.Add(value) 597 if err != nil { 598 return nil, 0, 0, fmt.Errorf("add value type: %w", err) 599 } 600 } 601 602 handle, err := NewHandle(&b) 603 if err != nil { 604 // Check for 'full' map BTF support, since kernels between 4.18 and 5.2 605 // already support BTF blobs for maps without Var or Datasec just fine. 606 if err := haveMapBTF(); err != nil { 607 return nil, 0, 0, err 608 } 609 } 610 return handle, keyID, valueID, err 611 }