github.com/cilium/ebpf@v0.10.0/btf/marshal.go (about) 1 package btf 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "errors" 7 "fmt" 8 "math" 9 10 "github.com/cilium/ebpf/internal" 11 ) 12 13 type encoderOptions struct { 14 ByteOrder binary.ByteOrder 15 // Remove function linkage information for compatibility with <5.6 kernels. 16 StripFuncLinkage bool 17 } 18 19 // kernelEncoderOptions will generate BTF suitable for the current kernel. 20 var kernelEncoderOptions encoderOptions 21 22 func init() { 23 kernelEncoderOptions = encoderOptions{ 24 ByteOrder: internal.NativeEndian, 25 StripFuncLinkage: haveFuncLinkage() != nil, 26 } 27 } 28 29 // encoder turns Types into raw BTF. 30 type encoder struct { 31 opts encoderOptions 32 33 buf *bytes.Buffer 34 strings *stringTableBuilder 35 allocatedIDs map[Type]TypeID 36 nextID TypeID 37 // Temporary storage for Add. 38 pending internal.Deque[Type] 39 // Temporary storage for deflateType. 40 raw rawType 41 } 42 43 // newEncoder returns a new builder for the given byte order. 44 // 45 // See [KernelEncoderOptions] to build BTF for the current system. 46 func newEncoder(opts encoderOptions, strings *stringTableBuilder) *encoder { 47 enc := &encoder{ 48 opts: opts, 49 buf: bytes.NewBuffer(make([]byte, btfHeaderLen)), 50 } 51 enc.reset(strings) 52 return enc 53 } 54 55 // Reset internal state to be able to reuse the Encoder. 56 func (e *encoder) Reset() { 57 e.reset(nil) 58 } 59 60 func (e *encoder) reset(strings *stringTableBuilder) { 61 if strings == nil { 62 strings = newStringTableBuilder() 63 } 64 65 e.buf.Truncate(btfHeaderLen) 66 e.strings = strings 67 e.allocatedIDs = make(map[Type]TypeID) 68 e.nextID = 1 69 } 70 71 // Add a Type. 72 // 73 // Adding the same Type multiple times is valid and will return a stable ID. 74 // 75 // Calling the method has undefined behaviour if it previously returned an error. 76 func (e *encoder) Add(typ Type) (TypeID, error) { 77 if typ == nil { 78 return 0, errors.New("cannot Add a nil Type") 79 } 80 81 hasID := func(t Type) (skip bool) { 82 _, isVoid := t.(*Void) 83 _, alreadyEncoded := e.allocatedIDs[t] 84 return isVoid || alreadyEncoded 85 } 86 87 e.pending.Reset() 88 89 allocateID := func(typ Type) { 90 e.pending.Push(typ) 91 e.allocatedIDs[typ] = e.nextID 92 e.nextID++ 93 } 94 95 iter := postorderTraversal(typ, hasID) 96 for iter.Next() { 97 if hasID(iter.Type) { 98 // This type is part of a cycle and we've already deflated it. 99 continue 100 } 101 102 // Allocate an ID for the next type. 103 allocateID(iter.Type) 104 105 for !e.pending.Empty() { 106 t := e.pending.Shift() 107 108 // Ensure that all direct descendants have been allocated an ID 109 // before calling deflateType. 110 walkType(t, func(child *Type) { 111 if !hasID(*child) { 112 // t refers to a type which hasn't been allocated an ID 113 // yet, which only happens for circular types. 114 allocateID(*child) 115 } 116 }) 117 118 if err := e.deflateType(t); err != nil { 119 return 0, fmt.Errorf("deflate %s: %w", t, err) 120 } 121 } 122 } 123 124 return e.allocatedIDs[typ], nil 125 } 126 127 // Encode the raw BTF blob. 128 // 129 // The returned slice is valid until the next call to Add. 130 func (e *encoder) Encode() ([]byte, error) { 131 length := e.buf.Len() 132 133 // Truncate the string table on return to allow adding more types. 134 defer e.buf.Truncate(length) 135 136 typeLen := uint32(length - btfHeaderLen) 137 138 // Reserve space for the string table. 139 stringLen := e.strings.Length() 140 e.buf.Grow(stringLen) 141 142 buf := e.buf.Bytes()[:length+stringLen] 143 e.strings.MarshalBuffer(buf[length:]) 144 145 // Fill out the header, and write it out. 146 header := &btfHeader{ 147 Magic: btfMagic, 148 Version: 1, 149 Flags: 0, 150 HdrLen: uint32(btfHeaderLen), 151 TypeOff: 0, 152 TypeLen: typeLen, 153 StringOff: typeLen, 154 StringLen: uint32(stringLen), 155 } 156 157 err := binary.Write(sliceWriter(buf[:btfHeaderLen]), e.opts.ByteOrder, header) 158 if err != nil { 159 return nil, fmt.Errorf("can't write header: %v", err) 160 } 161 162 return buf, nil 163 } 164 165 func (e *encoder) deflateType(typ Type) (err error) { 166 raw := &e.raw 167 *raw = rawType{} 168 raw.NameOff, err = e.strings.Add(typ.TypeName()) 169 if err != nil { 170 return err 171 } 172 173 switch v := typ.(type) { 174 case *Int: 175 raw.SetKind(kindInt) 176 raw.SetSize(v.Size) 177 178 var bi btfInt 179 bi.SetEncoding(v.Encoding) 180 // We need to set bits in addition to size, since btf_type_int_is_regular 181 // otherwise flags this as a bitfield. 182 bi.SetBits(byte(v.Size) * 8) 183 raw.data = bi 184 185 case *Pointer: 186 raw.SetKind(kindPointer) 187 raw.SetType(e.allocatedIDs[v.Target]) 188 189 case *Array: 190 raw.SetKind(kindArray) 191 raw.data = &btfArray{ 192 e.allocatedIDs[v.Type], 193 e.allocatedIDs[v.Index], 194 v.Nelems, 195 } 196 197 case *Struct: 198 raw.SetKind(kindStruct) 199 raw.SetSize(v.Size) 200 raw.data, err = e.convertMembers(&raw.btfType, v.Members) 201 202 case *Union: 203 raw.SetKind(kindUnion) 204 raw.SetSize(v.Size) 205 raw.data, err = e.convertMembers(&raw.btfType, v.Members) 206 207 case *Enum: 208 raw.SetSize(v.size()) 209 raw.SetVlen(len(v.Values)) 210 raw.SetSigned(v.Signed) 211 212 if v.has64BitValues() { 213 raw.SetKind(kindEnum64) 214 raw.data, err = e.deflateEnum64Values(v.Values) 215 } else { 216 raw.SetKind(kindEnum) 217 raw.data, err = e.deflateEnumValues(v.Values) 218 } 219 220 case *Fwd: 221 raw.SetKind(kindForward) 222 raw.SetFwdKind(v.Kind) 223 224 case *Typedef: 225 raw.SetKind(kindTypedef) 226 raw.SetType(e.allocatedIDs[v.Type]) 227 228 case *Volatile: 229 raw.SetKind(kindVolatile) 230 raw.SetType(e.allocatedIDs[v.Type]) 231 232 case *Const: 233 raw.SetKind(kindConst) 234 raw.SetType(e.allocatedIDs[v.Type]) 235 236 case *Restrict: 237 raw.SetKind(kindRestrict) 238 raw.SetType(e.allocatedIDs[v.Type]) 239 240 case *Func: 241 raw.SetKind(kindFunc) 242 raw.SetType(e.allocatedIDs[v.Type]) 243 if !e.opts.StripFuncLinkage { 244 raw.SetLinkage(v.Linkage) 245 } 246 247 case *FuncProto: 248 raw.SetKind(kindFuncProto) 249 raw.SetType(e.allocatedIDs[v.Return]) 250 raw.SetVlen(len(v.Params)) 251 raw.data, err = e.deflateFuncParams(v.Params) 252 253 case *Var: 254 raw.SetKind(kindVar) 255 raw.SetType(e.allocatedIDs[v.Type]) 256 raw.data = btfVariable{uint32(v.Linkage)} 257 258 case *Datasec: 259 raw.SetKind(kindDatasec) 260 raw.SetSize(v.Size) 261 raw.SetVlen(len(v.Vars)) 262 raw.data = e.deflateVarSecinfos(v.Vars) 263 264 case *Float: 265 raw.SetKind(kindFloat) 266 raw.SetSize(v.Size) 267 268 case *declTag: 269 raw.SetKind(kindDeclTag) 270 raw.data = &btfDeclTag{uint32(v.Index)} 271 272 case *typeTag: 273 raw.SetKind(kindTypeTag) 274 raw.NameOff, err = e.strings.Add(v.Value) 275 276 default: 277 return fmt.Errorf("don't know how to deflate %T", v) 278 } 279 280 if err != nil { 281 return err 282 } 283 284 return raw.Marshal(e.buf, e.opts.ByteOrder) 285 } 286 287 func (e *encoder) convertMembers(header *btfType, members []Member) ([]btfMember, error) { 288 bms := make([]btfMember, 0, len(members)) 289 isBitfield := false 290 for _, member := range members { 291 isBitfield = isBitfield || member.BitfieldSize > 0 292 293 offset := member.Offset 294 if isBitfield { 295 offset = member.BitfieldSize<<24 | (member.Offset & 0xffffff) 296 } 297 298 nameOff, err := e.strings.Add(member.Name) 299 if err != nil { 300 return nil, err 301 } 302 303 bms = append(bms, btfMember{ 304 nameOff, 305 e.allocatedIDs[member.Type], 306 uint32(offset), 307 }) 308 } 309 310 header.SetVlen(len(members)) 311 header.SetBitfield(isBitfield) 312 return bms, nil 313 } 314 315 func (e *encoder) deflateEnumValues(values []EnumValue) ([]btfEnum, error) { 316 bes := make([]btfEnum, 0, len(values)) 317 for _, value := range values { 318 nameOff, err := e.strings.Add(value.Name) 319 if err != nil { 320 return nil, err 321 } 322 323 if value.Value > math.MaxUint32 { 324 return nil, fmt.Errorf("value of enum %q exceeds 32 bits", value.Name) 325 } 326 327 bes = append(bes, btfEnum{ 328 nameOff, 329 uint32(value.Value), 330 }) 331 } 332 333 return bes, nil 334 } 335 336 func (e *encoder) deflateEnum64Values(values []EnumValue) ([]btfEnum64, error) { 337 bes := make([]btfEnum64, 0, len(values)) 338 for _, value := range values { 339 nameOff, err := e.strings.Add(value.Name) 340 if err != nil { 341 return nil, err 342 } 343 344 bes = append(bes, btfEnum64{ 345 nameOff, 346 uint32(value.Value), 347 uint32(value.Value >> 32), 348 }) 349 } 350 351 return bes, nil 352 } 353 354 func (e *encoder) deflateFuncParams(params []FuncParam) ([]btfParam, error) { 355 bps := make([]btfParam, 0, len(params)) 356 for _, param := range params { 357 nameOff, err := e.strings.Add(param.Name) 358 if err != nil { 359 return nil, err 360 } 361 362 bps = append(bps, btfParam{ 363 nameOff, 364 e.allocatedIDs[param.Type], 365 }) 366 } 367 return bps, nil 368 } 369 370 func (e *encoder) deflateVarSecinfos(vars []VarSecinfo) []btfVarSecinfo { 371 vsis := make([]btfVarSecinfo, 0, len(vars)) 372 for _, v := range vars { 373 vsis = append(vsis, btfVarSecinfo{ 374 e.allocatedIDs[v.Type], 375 v.Offset, 376 v.Size, 377 }) 378 } 379 return vsis 380 } 381 382 // MarshalMapKV creates a BTF object containing a map key and value. 383 // 384 // The function is intended for the use of the ebpf package and may be removed 385 // at any point in time. 386 func MarshalMapKV(key, value Type) (_ *Handle, keyID, valueID TypeID, _ error) { 387 enc := nativeEncoderPool.Get().(*encoder) 388 defer nativeEncoderPool.Put(enc) 389 390 enc.Reset() 391 392 var err error 393 if key != nil { 394 keyID, err = enc.Add(key) 395 if err != nil { 396 return nil, 0, 0, fmt.Errorf("adding map key to BTF encoder: %w", err) 397 } 398 } 399 400 if value != nil { 401 valueID, err = enc.Add(value) 402 if err != nil { 403 return nil, 0, 0, fmt.Errorf("adding map value to BTF encoder: %w", err) 404 } 405 } 406 407 btf, err := enc.Encode() 408 if err != nil { 409 return nil, 0, 0, fmt.Errorf("marshal BTF: %w", err) 410 } 411 412 handle, err := newHandleFromRawBTF(btf) 413 if err != nil { 414 // Check for 'full' map BTF support, since kernels between 4.18 and 5.2 415 // already support BTF blobs for maps without Var or Datasec just fine. 416 if err := haveMapBTF(); err != nil { 417 return nil, 0, 0, err 418 } 419 } 420 421 return handle, keyID, valueID, err 422 }