github.com/dylandreimerink/gobpfld@v0.6.1-0.20220205171531-e79c330ad608/btf.go (about) 1 package gobpfld 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "errors" 7 "fmt" 8 "io" 9 "math" 10 "math/big" 11 "strconv" 12 "unsafe" 13 14 "github.com/dylandreimerink/gobpfld/bpfsys" 15 "github.com/dylandreimerink/gobpfld/bpftypes" 16 "github.com/dylandreimerink/gobpfld/internal/cstr" 17 "github.com/dylandreimerink/gobpfld/kernelsupport" 18 ) 19 20 // TODO add field to store kernel structure ID's (for map BTFVMLinuxValueTypeID) 21 // TODO Add global registry for BTF objects to translate IDs to FDs 22 // TODO Add fuzzing, we should never get panics only errors, critical for stability of library users. (go 1.18) 23 // TODO (bonus) make code generators for BTF so we can generate C and Go code like bpftool does 24 // TODO (bonus) test against VMLinux (/sys/kernel/btf/vmlinux) 25 // TODO (bonus) implement libbpf compatible CO:RE(Compile Once Run Everywhere). 26 // This works by looking at the BTF of the compiled program to see what it wants to access and rewriting 27 // the program using the VMLinux on the machine at runtime. This would enable users to compile architecture 28 // specific kprobe or uprobe code and run it everywhere. 29 30 // BTF Type and String info 31 type BTF struct { 32 // Parsed type information, the index of the types is equal to their ID's 33 Types []BTFType 34 35 // Parsed Lines information with ELF section relative instruction offsets 36 Lines []BTFLine 37 // Parsed function information with ELF section relative instruction offsets 38 Funcs []BTFFunc 39 40 // A mapping of BTF types indexed on name, used to find the currect types for BPF Maps 41 typesByName map[string]BTFType 42 43 // The parsed BTF header 44 btfHdr *btfHeader 45 // Contains the full, raw BTF header, string and type bytes. 46 // Used to load into the kernel. 47 rawType []byte 48 49 StringsTbl StringTbl 50 51 // The parsed BTF EXT header 52 btfExtHdr *btfExtHeader 53 54 // Indicates if the BTF is already loaded into the kernel 55 loaded bool 56 // The file descriptor of the BTF assigned by the kernel 57 fd bpfsys.BPFfd 58 } 59 60 func NewBTF() *BTF { 61 return &BTF{ 62 typesByName: make(map[string]BTFType), 63 } 64 } 65 66 func (btf *BTF) Fd() (bpfsys.BPFfd, error) { 67 if !btf.loaded { 68 return 0, fmt.Errorf("btf is not loaded") 69 } 70 71 return btf.fd, nil 72 } 73 74 type BTFLoadOpts struct { 75 LogLevel bpftypes.BPFLogLevel 76 LogSize int 77 } 78 79 func (btf *BTF) Load(opts BTFLoadOpts) (string, error) { 80 if btf.loaded { 81 return "", fmt.Errorf("btf is already loaded") 82 } 83 84 if btf.rawType == nil { 85 return "", fmt.Errorf("btf has no raw type info") 86 } 87 88 // Set a default log size if none is specified 89 if opts.LogSize == 0 { 90 opts.LogSize = defaultBPFVerifierLogSize 91 } 92 93 serialized, err := btf.SerializeBTF() 94 if err != nil { 95 return "", fmt.Errorf("btf serialization: %w", err) 96 } 97 98 verifierLogBytes := make([]byte, opts.LogSize) 99 100 attr := bpfsys.BPFAttrBTFLoad{ 101 BTF: uintptr(unsafe.Pointer(&serialized[0])), 102 BTFSize: uint32(len(serialized)), 103 BTFLogBuf: uintptr(unsafe.Pointer(&verifierLogBytes[0])), 104 BTFLogSize: uint32(opts.LogSize), 105 BTFLogLevel: opts.LogLevel, 106 } 107 108 fd, err := bpfsys.BTFLoad(&attr) 109 if err != nil { 110 return cstr.BytesToString(verifierLogBytes), err 111 } 112 113 btf.fd = fd 114 btf.loaded = true 115 116 return cstr.BytesToString(verifierLogBytes), nil 117 } 118 119 // ErrMissingBTFData is returned when a datastructure indicates that there should be additional bytes but 120 // the given bytes slice doesn't contain any. 121 var ErrMissingBTFData = errors.New("missing indicated bytes in slice") 122 123 // ParseBTF parses BTF type and string data. 124 func (btf *BTF) ParseBTF(btfBytes []byte) error { 125 btf.rawType = btfBytes 126 headerOffset := uint32(0) 127 128 var err error 129 btf.btfHdr, headerOffset, err = parseBTFHeader(btfBytes) 130 if err != nil { 131 return fmt.Errorf("parse header: %w", err) 132 } 133 134 btfLen := len(btfBytes) 135 if btfLen < int(headerOffset+btf.btfHdr.StringOffset+btf.btfHdr.StringLength) { 136 return fmt.Errorf("byte sequence shorten than indicated string offset + length") 137 } 138 139 stringsStart := headerOffset + btf.btfHdr.StringOffset 140 stringsEnd := headerOffset + btf.btfHdr.StringOffset + btf.btfHdr.StringLength 141 btf.StringsTbl = StringTblFromBlob(btfBytes[stringsStart:stringsEnd]) 142 143 if btfLen < int(headerOffset+btf.btfHdr.TypeOffset+btf.btfHdr.TypeLength) { 144 return fmt.Errorf("byte sequence shorten than indicated type offset + length") 145 } 146 147 typesStart := headerOffset + btf.btfHdr.TypeOffset 148 typesEnd := headerOffset + btf.btfHdr.TypeOffset + btf.btfHdr.TypeLength 149 btfTypes := btfBytes[typesStart:typesEnd] 150 151 var readError error 152 off := 0 153 read32 := func() uint32 { 154 defer func() { 155 off = off + 4 156 }() 157 158 // return a 0, instread of panicing 159 if off+4 > len(btfTypes) { 160 readError = ErrMissingBTFData 161 return 0 162 } 163 164 v := btf.btfHdr.byteOrder.Uint32(btfTypes[off : off+4]) 165 return v 166 } 167 168 // Type ID 0 is reserved for void, this initial item will make it so that the index in this slice 169 // is equal to the Type IDs used by other types. 170 btf.Types = append(btf.Types, &BTFVoidType{}) 171 172 for off < len(btfTypes) { 173 ct := (btfType{ 174 NameOffset: read32(), 175 Info: read32(), 176 SizeType: read32(), 177 }).ToCommonType(&btf.StringsTbl) 178 179 // The current amount of elements is equal to the index of the next element. 180 ct.TypeID = len(btf.Types) 181 182 var btfType BTFType 183 switch ct.Kind { 184 case BTF_KIND_INT: 185 ct.Size = ct.sizeType 186 typeData := read32() 187 btfType = &BTFIntType{ 188 commonType: ct, 189 Encoding: BTFIntEncoding((typeData & 0x0f000000) >> 24), 190 Offset: uint8((typeData & 0x00ff0000) >> 16), 191 Bits: uint8(typeData & 0x000000ff), 192 } 193 194 case BTF_KIND_PTR: 195 btfType = &BTFPtrType{ 196 commonType: ct, 197 } 198 199 case BTF_KIND_ARRAY: 200 arr := &BTFArrayType{ 201 commonType: ct, 202 } 203 arr.typeID = read32() 204 arr.indexTypeID = read32() 205 arr.NumElements = read32() 206 207 btfType = arr 208 209 case BTF_KIND_STRUCT, BTF_KIND_UNION: 210 ct.Size = ct.sizeType 211 members := make([]BTFMember, ct.VLen) 212 for i := 0; i < int(ct.VLen); i++ { 213 members[i].Name = btf.StringsTbl.GetStringAtOffset(int(read32())) 214 members[i].typeID = read32() 215 216 // https://elixir.bootlin.com/linux/v5.15.3/source/include/uapi/linux/btf.h#L132 217 offset := read32() 218 if ct.KindFlag == 1 { 219 // If the kind_flag is set, the btf_member.offset contains both member bitfield size and bit offset. 220 members[i].BitfieldSize = offset >> 24 221 members[i].BitOffset = offset & 0xffffff 222 } else { 223 // If the type info kind_flag is not set, the offset contains only bit offset of the member. 224 members[i].BitOffset = offset 225 } 226 } 227 228 if ct.Kind == BTF_KIND_STRUCT { 229 btfType = &BTFStructType{ 230 commonType: ct, 231 Members: members, 232 } 233 break 234 } 235 236 btfType = &BTFUnionType{ 237 commonType: ct, 238 Members: members, 239 } 240 case BTF_KIND_ENUM: 241 ct.Size = ct.sizeType 242 options := make([]BTFEnumOption, ct.VLen) 243 for i := 0; i < int(ct.VLen); i++ { 244 options[i].Name = btf.StringsTbl.GetStringAtOffset(int(read32())) 245 options[i].Value = int32(read32()) 246 } 247 248 btfType = &BTFEnumType{ 249 commonType: ct, 250 Options: options, 251 } 252 253 case BTF_KIND_FWD: 254 btfType = &BTFForwardType{ 255 commonType: ct, 256 } 257 258 case BTF_KIND_TYPEDEF: 259 btfType = &BTFTypeDefType{ 260 commonType: ct, 261 } 262 263 case BTF_KIND_VOLATILE: 264 btfType = &BTFVolatileType{ 265 commonType: ct, 266 } 267 268 case BTF_KIND_CONST: 269 btfType = &BTFConstType{ 270 commonType: ct, 271 } 272 273 case BTF_KIND_RESTRICT: 274 btfType = &BTFRestrictType{ 275 commonType: ct, 276 } 277 278 case BTF_KIND_FUNC: 279 btfType = &BTFFuncType{ 280 commonType: ct, 281 } 282 283 case BTF_KIND_FUNC_PROTO: 284 params := make([]BTFFuncProtoParam, ct.VLen) 285 for i := 0; i < int(ct.VLen); i++ { 286 params[i].Name = btf.StringsTbl.GetStringAtOffset(int(read32())) 287 params[i].typeID = read32() 288 } 289 290 btfType = &BTFFuncProtoType{ 291 commonType: ct, 292 Params: params, 293 } 294 295 case BTF_KIND_VAR: 296 btfType = &BTFVarType{ 297 commonType: ct, 298 Linkage: read32(), 299 } 300 301 case BTF_KIND_DATASEC: 302 // The offset of the SizeType uint32 of common type 303 ctSizeTypeOff := off - 4 304 305 variables := make([]BTFDataSecVariable, ct.VLen) 306 for i := 0; i < int(ct.VLen); i++ { 307 variables[i].typeID = read32() 308 variables[i].offsetOffset = int(typesStart) + off 309 variables[i].Offset = read32() 310 variables[i].Size = read32() 311 } 312 313 dataSec := &BTFDataSecType{ 314 commonType: ct, 315 Variables: variables, 316 sizeOffset: int(typesStart) + ctSizeTypeOff, 317 } 318 btfType = dataSec 319 320 case BTF_KIND_FLOAT: 321 ct.Size = ct.sizeType 322 btfType = &BTFFloatType{ 323 commonType: ct, 324 } 325 326 case BTF_KIND_DECL_TAG: 327 btfType = &BTFDeclTagType{ 328 commonType: ct, 329 ComponentIdx: read32(), 330 } 331 332 default: 333 return fmt.Errorf("unknown BTF kind: %d", ct.Kind) 334 } 335 336 btf.Types = append(btf.Types, btfType) 337 338 if ct.Name != "" { 339 btf.typesByName[ct.Name] = btfType 340 } 341 } 342 if readError != nil { 343 return readError 344 } 345 346 // Range over all types and resolve type references 347 for _, btfType := range btf.Types { 348 switch t := btfType.(type) { 349 case *BTFPtrType: 350 t.Type = btf.Types[t.sizeType] 351 352 case *BTFArrayType: 353 t.Type = btf.Types[t.typeID] 354 t.IndexType = btf.Types[t.indexTypeID] 355 356 case *BTFStructType: 357 for i, member := range t.Members { 358 t.Members[i].Type = btf.Types[member.typeID] 359 } 360 361 case *BTFUnionType: 362 for i, member := range t.Members { 363 t.Members[i].Type = btf.Types[member.typeID] 364 } 365 366 case *BTFTypeDefType: 367 t.Type = btf.Types[t.sizeType] 368 369 case *BTFVolatileType: 370 t.Type = btf.Types[t.sizeType] 371 372 case *BTFConstType: 373 t.Type = btf.Types[t.sizeType] 374 375 case *BTFRestrictType: 376 t.Type = btf.Types[t.sizeType] 377 378 case *BTFFuncType: 379 t.Type = btf.Types[t.sizeType] 380 381 case *BTFFuncProtoType: 382 t.Type = btf.Types[t.sizeType] 383 for i, param := range t.Params { 384 t.Params[i].Type = btf.Types[param.typeID] 385 } 386 387 case *BTFVarType: 388 t.Type = btf.Types[t.sizeType] 389 390 case *BTFDataSecType: 391 for i, variable := range t.Variables { 392 t.Variables[i].Type = btf.Types[variable.typeID] 393 } 394 395 case *BTFDeclTagType: 396 t.Type = btf.Types[t.sizeType] 397 } 398 } 399 400 // Loop over all types again, this time to verify them 401 // for _, btfType := range btf.Types { 402 // TODO implement verification for all types. 403 // TODO call verification 404 // } 405 406 return nil 407 } 408 409 // ParseBTFExt parses 410 func (btf *BTF) ParseBTFExt(btfBytes []byte) error { 411 var err error 412 headerOffset := uint32(0) 413 414 btf.btfExtHdr, headerOffset, err = parseBTFExtHeader(btfBytes) 415 if err != nil { 416 return fmt.Errorf("parse header: %w", err) 417 } 418 419 funcsStart := headerOffset + btf.btfExtHdr.FuncOffset 420 funcsEnd := headerOffset + btf.btfExtHdr.FuncOffset + btf.btfExtHdr.FuncLength 421 funcs := btfBytes[funcsStart:funcsEnd] 422 423 var readError error 424 off := 0 425 read32 := func() uint32 { 426 defer func() { 427 off = off + 4 428 }() 429 430 // return a 0, instread of panicing 431 if off+4 > len(funcs) { 432 readError = ErrMissingBTFData 433 return 0 434 } 435 436 v := btf.btfExtHdr.byteOrder.Uint32(funcs[off : off+4]) 437 return v 438 } 439 440 funcRecordSize := read32() 441 for off < len(funcs) { 442 sectionOffset := read32() 443 sectionName := btf.StringsTbl.GetStringAtOffset(int(sectionOffset)) 444 numInfo := read32() 445 for i := 0; i < int(numInfo); i++ { 446 if funcRecordSize < 8 { 447 panic("func record smaller than min expected size") 448 } 449 450 f := BTFFunc{ 451 Section: sectionName, 452 SectionOffset: sectionOffset, 453 } 454 f.InstructionOffset = btf.btfExtHdr.byteOrder.Uint32(funcs[off : off+4]) 455 f.TypeID = btf.btfExtHdr.byteOrder.Uint32(funcs[off+4 : off+8]) 456 f.Type = btf.Types[f.TypeID] 457 btf.Funcs = append(btf.Funcs, f) 458 459 // Increment by funcRecordSize, since newer version of BTF might start using larger records. 460 // This makes the code forward compatible 461 off += int(funcRecordSize) 462 } 463 } 464 if readError != nil { 465 return err 466 } 467 468 linesStart := headerOffset + btf.btfExtHdr.LineOffset 469 linesEnd := headerOffset + btf.btfExtHdr.LineOffset + btf.btfExtHdr.LineLength 470 lines := btfBytes[linesStart:linesEnd] 471 472 off = 0 473 read32 = func() uint32 { 474 defer func() { 475 off = off + 4 476 }() 477 478 // return a 0, instread of panicing 479 if off+4 > len(lines) { 480 readError = ErrMissingBTFData 481 return 0 482 } 483 484 v := btf.btfExtHdr.byteOrder.Uint32(lines[off : off+4]) 485 return v 486 } 487 488 lineRecordSize := read32() 489 for off < len(lines) { 490 sectionOffset := read32() 491 sectionName := btf.StringsTbl.GetStringAtOffset(int(sectionOffset)) 492 numInfo := read32() 493 for i := 0; i < int(numInfo); i++ { 494 if lineRecordSize < 16 { 495 panic("line record smaller than min expected size") 496 } 497 498 l := BTFLine{ 499 Section: sectionName, 500 SectionOffset: sectionOffset, 501 } 502 l.InstructionOffset = btf.btfExtHdr.byteOrder.Uint32(lines[off : off+4]) 503 l.FileNameOffset = btf.btfExtHdr.byteOrder.Uint32(lines[off+4 : off+8]) 504 l.FileName = btf.StringsTbl.GetStringAtOffset(int(l.FileNameOffset)) 505 l.LineOffset = btf.btfExtHdr.byteOrder.Uint32(lines[off+8 : off+12]) 506 l.Line = btf.StringsTbl.GetStringAtOffset(int(l.LineOffset)) 507 col := btf.btfExtHdr.byteOrder.Uint32(lines[off+12 : off+16]) 508 l.LineNumber = col >> 10 509 l.ColumnNumber = col & 0x3FF 510 btf.Lines = append(btf.Lines, l) 511 512 // Increment by lineRecordSize, since newer version of BTF might start using larger records. 513 // This makes the code forward compatible 514 off += int(lineRecordSize) 515 } 516 } 517 if readError != nil { 518 return err 519 } 520 521 return nil 522 } 523 524 // SerializeBTF takes the contents BTF.Types and serializes it into a byte slice which can be loaded into the kernel 525 func (btf *BTF) SerializeBTF() ([]byte, error) { 526 var buf bytes.Buffer 527 528 const hdrLen = 6 * 4 529 530 // Empty header, patched later 531 buf.Write(make([]byte, hdrLen)) 532 533 btf.StringsTbl.Serialize() 534 535 for _, t := range btf.Types[1:] { 536 b, err := t.Serialize(&btf.StringsTbl, btf.btfHdr.byteOrder) 537 if err != nil { 538 return nil, err 539 } 540 buf.Write(b) 541 } 542 543 typeOff := uint32(0) 544 typeLen := uint32(buf.Len() - hdrLen) 545 strOff := typeLen 546 strLen := uint32(len(btf.StringsTbl.btfStringBlob)) 547 548 buf.Write(btf.StringsTbl.btfStringBlob) 549 550 bytes := buf.Bytes() 551 552 btf.btfHdr.byteOrder.PutUint16(bytes[0:2], btfMagic) 553 // TODO hard code version/flags or get them from the exported fields in BTF 554 bytes[2] = btf.btfHdr.Version 555 bytes[3] = btf.btfHdr.Flags 556 btf.btfHdr.byteOrder.PutUint32(bytes[4:8], hdrLen) 557 558 btf.btfHdr.byteOrder.PutUint32(bytes[8:12], typeOff) 559 btf.btfHdr.byteOrder.PutUint32(bytes[12:16], typeLen) 560 btf.btfHdr.byteOrder.PutUint32(bytes[16:20], strOff) 561 btf.btfHdr.byteOrder.PutUint32(bytes[20:24], strLen) 562 563 return bytes, nil 564 } 565 566 type StringTbl struct { 567 Strings []string 568 offsets map[string]int 569 btfStringBlob []byte 570 } 571 572 func StringTblFromBlob(blob []byte) StringTbl { 573 tbl := StringTbl{ 574 offsets: make(map[string]int), 575 btfStringBlob: blob, 576 } 577 578 off := 0 579 for _, s := range bytes.Split(blob, []byte{0}) { 580 name := string(s) 581 tbl.Strings = append(tbl.Strings, name) 582 tbl.offsets[name] = off 583 off += len(s) + 1 584 } 585 // Dirty fix, since we use split, the last element will register as "" 586 // This will reset the map entry so an empty string will always give offset 0 587 tbl.offsets[""] = 0 588 tbl.Strings = tbl.Strings[:len(tbl.Strings)-1] 589 590 return tbl 591 } 592 593 func (st *StringTbl) Serialize() { 594 st.offsets = make(map[string]int, len(st.Strings)) 595 var buf bytes.Buffer 596 for _, s := range st.Strings { 597 st.offsets[s] = buf.Len() 598 buf.WriteString(s) 599 buf.WriteByte(0) 600 } 601 st.btfStringBlob = buf.Bytes() 602 } 603 604 func (st *StringTbl) GetStringAtOffset(offset int) string { 605 // TODO implement stricter parsing and throw errors instead of returning empty strings. 606 // NOTE current code relies on the fact that offset == 0 will return a "" which is still valid. 607 // only throw errors on offsets outside of the `strings` bounds 608 var name string 609 if offset < len(st.btfStringBlob) { 610 idx := bytes.IndexByte(st.btfStringBlob[offset:], 0x00) 611 if idx == -1 { 612 name = string(st.btfStringBlob[offset:]) 613 } else { 614 name = string(st.btfStringBlob[offset : offset+idx]) 615 } 616 } 617 return name 618 } 619 620 func (st *StringTbl) StrToOffset(str string) int { 621 return st.offsets[str] 622 } 623 624 // BTFFunc the go version of bpf_func_info. Which is used to link a instruction offset to a function type. 625 // https://elixir.bootlin.com/linux/v5.15.3/source/include/uapi/linux/bpf.h#L6165 626 type BTFFunc struct { 627 // The ELF section in which the function is defined 628 Section string 629 // Offset in the strings table to the name of the section 630 SectionOffset uint32 631 // Offset from the start of the ELF section to the function 632 InstructionOffset uint32 633 // The resolved Type of the Function 634 Type BTFType 635 // The TypeID, used to resolve Type 636 TypeID uint32 637 } 638 639 func (bf BTFFunc) ToKernel() BTFKernelFunc { 640 return BTFKernelFunc{ 641 InstructionOffset: bf.InstructionOffset, 642 TypeID: bf.TypeID, 643 } 644 } 645 646 // BTFKernelFuncSize size of BTFKernelFunc in bytes 647 var BTFKernelFuncSize = int(unsafe.Sizeof(BTFKernelFunc{})) 648 649 // BTFKernelFunc is the version of the BTFFunc struct the way the kernel want to see it. 650 type BTFKernelFunc struct { 651 InstructionOffset uint32 652 TypeID uint32 653 } 654 655 // BTFLine the go version of bpf_line_info. Which maps an instruction to a source code. 656 // https://elixir.bootlin.com/linux/v5.15.3/source/include/uapi/linux/bpf.h#L6173 657 type BTFLine struct { 658 // The ELF section in which the line is defined 659 Section string 660 // The offset into the strings table for the section name 661 SectionOffset uint32 662 // Offset from the start of the ELF section to the function 663 InstructionOffset uint32 664 // The name and path of the source file 665 FileName string 666 // The offset into the strings table for the file name 667 FileNameOffset uint32 668 // The full line of source code 669 Line string 670 // The offset into the strings table for the line. 671 LineOffset uint32 672 // The line number within the file 673 LineNumber uint32 674 // The column number within Line of the instruction 675 ColumnNumber uint32 676 } 677 678 func (bl BTFLine) ToKernel() BTFKernelLine { 679 return BTFKernelLine{ 680 InstructionOffset: bl.InstructionOffset, 681 FileNameOffset: bl.FileNameOffset, 682 LineOffset: bl.LineOffset, 683 LineCol: (bl.LineNumber << 10) & bl.ColumnNumber, 684 } 685 } 686 687 // BTFKernelLineSize size of BTFKernelLine in bytes 688 var BTFKernelLineSize = int(unsafe.Sizeof(BTFKernelLine{})) 689 690 // BTFKernelLine is the version of the BTFLine struct the way the kernel want to see it. 691 type BTFKernelLine struct { 692 InstructionOffset uint32 693 FileNameOffset uint32 694 LineOffset uint32 695 LineCol uint32 696 } 697 698 // BTFMap is a struct which describes a BPF map 699 type BTFMap struct { 700 Key BTFType 701 Value BTFType 702 } 703 704 // BTFType is a BTF type, each Kind has its own corresponding BTFType. 705 type BTFType interface { 706 // Returns the TypeID of the type, which is determined by the position of the type within the encoded 707 // BTF bytes sequence. 708 GetID() int 709 GetKind() BTFKind 710 GetName() string 711 // Serialize to BTF binary representation 712 Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) 713 } 714 715 type BTFValueFormater interface { 716 // Format a byteslice of data to something human-readable using the BTF type information. 717 // The resulting output is written to `w``, if `pretty` is true the output is pretty printed(with whitespace). 718 // The func returns the remaining bytes and/or an error. 719 FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) 720 } 721 722 var _ BTFValueFormater = (*BTFIntType)(nil) 723 724 // BTFIntType is the type of KIND_INT, it represents a integer type. 725 type BTFIntType struct { 726 commonType 727 // Extra information, mainly useful for pretty printing 728 Encoding BTFIntEncoding 729 // specifies the starting bit offset to calculate values for this int 730 Offset uint8 731 // The number of actual bits held by this int type 732 Bits uint8 733 } 734 735 func (t *BTFIntType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) { 736 commonBytes := (commonType{ 737 Name: t.Name, 738 KindFlag: 0, 739 Kind: BTF_KIND_INT, 740 VLen: 0, 741 sizeType: t.Size, 742 }.ToBTFType(strTbl).ToBytes(order)) 743 744 // TODO validate t.Encoding, t.Offset, t.Bits 745 746 typeBytes := uint32sToBytes(order, uint32(t.Encoding)<<24|uint32(t.Offset)<<16|uint32(t.Bits)) 747 748 return append(commonBytes, typeBytes...), nil 749 } 750 751 func (t *BTFIntType) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) { 752 bytes := (t.Bits / 8) 753 if bytes == 0 { 754 bytes = 1 755 } 756 757 if len(b) < int(bytes) { 758 return nil, fmt.Errorf("'%s' not enough bytes, want '%d' got '%d'", t.Name, bytes, len(b)) 759 } 760 761 if t.Offset != 0 { 762 return nil, fmt.Errorf("'%s' non-0 offset int formatting not implemented", t.Name) 763 } 764 765 switch t.Bits { 766 case 128: 767 var i big.Int 768 _, err := fmt.Fprint(w, i.SetBytes(b[:bytes]).Text(10)) 769 if err != nil { 770 return nil, fmt.Errorf("'%s' error writing bigint: %w", t.Name, err) 771 } 772 773 switch t.Encoding { 774 case 0: 775 _, err := fmt.Fprint(w, i) 776 if err != nil { 777 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 778 } 779 780 case INT_SIGNED: 781 return nil, fmt.Errorf("'%s' signed printing of 128 bit number not implemented", t.Name) 782 case INT_CHAR: 783 _, err := fmt.Fprintf(w, "%032x", i.Bytes()) 784 if err != nil { 785 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 786 } 787 788 case INT_BOOL: 789 _, err := fmt.Fprint(w, i.Sign() > 0) 790 if err != nil { 791 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 792 } 793 794 default: 795 return nil, fmt.Errorf("'%s' unsupported encoding '%d'", t.Name, t.Encoding) 796 } 797 798 case 64: 799 i := binary.LittleEndian.Uint64(b[:bytes]) 800 801 switch t.Encoding { 802 case 0: 803 _, err := fmt.Fprint(w, i) 804 if err != nil { 805 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 806 } 807 808 case INT_SIGNED: 809 _, err := fmt.Fprint(w, int64(i)) 810 if err != nil { 811 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 812 } 813 814 case INT_CHAR: 815 _, err := fmt.Fprintf(w, "%016x", i) 816 if err != nil { 817 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 818 } 819 820 case INT_BOOL: 821 _, err := fmt.Fprint(w, i > 0) 822 if err != nil { 823 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 824 } 825 826 default: 827 return nil, fmt.Errorf("'%s' unsupported encoding '%d'", t.Name, t.Encoding) 828 } 829 830 case 32: 831 i := binary.LittleEndian.Uint32(b[:bytes]) 832 833 switch t.Encoding { 834 case 0: 835 _, err := fmt.Fprint(w, i) 836 if err != nil { 837 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 838 } 839 840 case INT_SIGNED: 841 _, err := fmt.Fprint(w, int32(i)) 842 if err != nil { 843 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 844 } 845 846 case INT_CHAR: 847 _, err := fmt.Fprintf(w, "%08x", i) 848 if err != nil { 849 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 850 } 851 852 case INT_BOOL: 853 _, err := fmt.Fprint(w, i > 0) 854 if err != nil { 855 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 856 } 857 858 default: 859 return nil, fmt.Errorf("'%s' unsupported encoding '%d'", t.Name, t.Encoding) 860 } 861 862 case 16: 863 i := binary.LittleEndian.Uint16(b[:bytes]) 864 865 switch t.Encoding { 866 case 0: 867 _, err := fmt.Fprint(w, i) 868 if err != nil { 869 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 870 } 871 872 case INT_SIGNED: 873 _, err := fmt.Fprint(w, int16(i)) 874 if err != nil { 875 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 876 } 877 878 case INT_CHAR: 879 _, err := fmt.Fprintf(w, "%04x", i) 880 if err != nil { 881 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 882 } 883 884 case INT_BOOL: 885 _, err := fmt.Fprint(w, i > 0) 886 if err != nil { 887 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 888 } 889 890 default: 891 return nil, fmt.Errorf("'%s' unsupported encoding '%d'", t.Name, t.Encoding) 892 } 893 894 case 8: 895 switch t.Encoding { 896 case 0: 897 _, err := fmt.Fprint(w, b[0]) 898 if err != nil { 899 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 900 } 901 902 case INT_SIGNED: 903 _, err := fmt.Fprint(w, int8(b[0])) 904 if err != nil { 905 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 906 } 907 908 case INT_CHAR: 909 _, err := fmt.Fprintf(w, "%02x", b[0]) 910 if err != nil { 911 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 912 } 913 914 case INT_BOOL: 915 _, err := fmt.Fprint(w, b[0] > 0) 916 if err != nil { 917 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 918 } 919 920 default: 921 return nil, fmt.Errorf("'%s' unsupported encoding '%d'", t.Name, t.Encoding) 922 } 923 924 case 1: 925 i := b[0] & 1 926 switch t.Encoding { 927 case 0, INT_SIGNED: 928 _, err := fmt.Fprint(w, i) 929 if err != nil { 930 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 931 } 932 933 case INT_CHAR: 934 _, err := fmt.Fprintf(w, "%02x", b[0]) 935 if err != nil { 936 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 937 } 938 939 case INT_BOOL: 940 _, err := fmt.Fprint(w, b[0] > 0) 941 if err != nil { 942 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 943 } 944 945 default: 946 return nil, fmt.Errorf("'%s' unsupported encoding '%d'", t.Name, t.Encoding) 947 } 948 default: 949 return nil, fmt.Errorf("'%s' int bitsize '%d' formatting not implemented", t.Name, t.Bits) 950 } 951 952 return b[bytes:], nil 953 } 954 955 // BTFIntEncoding is used to indicate what the integer encodes, used to determine how to pretty print an integer. 956 type BTFIntEncoding uint8 957 958 const ( 959 // INT_SIGNED the int should be printed at a signed integer 960 INT_SIGNED BTFIntEncoding = 1 << iota 961 // INT_CHAR the int should be printed as hex encoded 962 INT_CHAR 963 // INT_BOOL the int should be printed as a boolean 964 INT_BOOL 965 ) 966 967 var btfIntEncToStr = map[BTFIntEncoding]string{ 968 0: "(none)", 969 INT_SIGNED: "Signed", 970 INT_CHAR: "Char", 971 INT_BOOL: "Bool", 972 } 973 974 func (ie BTFIntEncoding) String() string { 975 return fmt.Sprintf("%s (%d)", btfIntEncToStr[ie], ie) 976 } 977 978 var _ BTFValueFormater = (*BTFPtrType)(nil) 979 980 // BTFPtrType is the type for KIND_PTR, which represents a pointer type which points to some other type. 981 type BTFPtrType struct { 982 commonType 983 } 984 985 func (t *BTFPtrType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) { 986 return (commonType{ 987 Name: "", 988 KindFlag: 0, 989 Kind: BTF_KIND_PTR, 990 VLen: 0, 991 sizeType: uint32(t.Type.GetID()), 992 }.ToBTFType(strTbl).ToBytes(order)), nil 993 } 994 995 func (t *BTFPtrType) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) { 996 _, err := fmt.Fprint(w, "*") 997 if err != nil { 998 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 999 } 1000 1001 if bfmt, ok := t.Type.(BTFValueFormater); ok { 1002 return bfmt.FormatValue(b, w, pretty) 1003 } 1004 1005 return nil, fmt.Errorf("'%s' ptr to unformatable type '%T'", t.Name, t.Type) 1006 } 1007 1008 var _ BTFValueFormater = (*BTFArrayType)(nil) 1009 1010 // BTFArrayType is the type for KIND_ARR, which represents a array 1011 type BTFArrayType struct { 1012 commonType 1013 // The type of the array values 1014 Type BTFType 1015 typeID uint32 1016 // The type of the array index 1017 IndexType BTFType 1018 indexTypeID uint32 1019 // The number of elements in the array 1020 NumElements uint32 1021 } 1022 1023 func (t *BTFArrayType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) { 1024 commonBytes := (commonType{ 1025 Name: "", 1026 KindFlag: 0, 1027 Kind: BTF_KIND_ARRAY, 1028 VLen: 0, 1029 sizeType: 0, 1030 }.ToBTFType(strTbl).ToBytes(order)) 1031 1032 // TODO Perform lookup of t.Type and t.IndexType, since structs created without parting ELF can't set the 1033 // non-exported values. 1034 1035 return append(commonBytes, uint32sToBytes(order, t.typeID, t.indexTypeID, t.NumElements)...), nil 1036 } 1037 1038 func (t *BTFArrayType) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) { 1039 var err error 1040 if pretty { 1041 _, err = fmt.Fprint(w, "[\n ") 1042 } else { 1043 _, err = fmt.Fprint(w, "[") 1044 } 1045 if err != nil { 1046 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 1047 } 1048 1049 bfmt, ok := t.Type.(BTFValueFormater) 1050 if !ok { 1051 return nil, fmt.Errorf("'%s' array contains nonformattable type '%T'", t.Name, t.Type) 1052 } 1053 1054 for i := 0; i < int(t.NumElements); i++ { 1055 b, err = bfmt.FormatValue(b, w, pretty) 1056 if err != nil { 1057 return nil, fmt.Errorf("'%s'[%d]: %w", t.Name, i, err) 1058 } 1059 if i+1 != int(t.NumElements) || pretty { 1060 if pretty { 1061 if i+1 == int(t.NumElements) { 1062 _, err = fmt.Fprint(w, ",\n") 1063 } else { 1064 _, err = fmt.Fprint(w, ",\n ") 1065 } 1066 } else { 1067 _, err = fmt.Fprint(w, ", ") 1068 } 1069 if err != nil { 1070 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 1071 } 1072 } 1073 } 1074 1075 _, err = fmt.Fprint(w, "]") 1076 if err != nil { 1077 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 1078 } 1079 1080 return b, nil 1081 } 1082 1083 var _ BTFValueFormater = (*BTFStructType)(nil) 1084 1085 // BTFStructType is the type for KIND_STRUCT, which represents a structure. 1086 type BTFStructType struct { 1087 commonType 1088 // The individual members / fields of the struct. 1089 Members []BTFMember 1090 } 1091 1092 func (t *BTFStructType) Verify() error { 1093 for i, member := range t.Members { 1094 // Recursively follow type definitions to find the actual int type, or not 1095 // TODO move to separate functionality so it can be reused for union as well 1096 asInt := func() (*BTFIntType, bool) { 1097 curType := member.Type 1098 for { 1099 switch ct := curType.(type) { 1100 case *BTFIntType: 1101 return ct, true 1102 case *BTFTypeDefType: 1103 curType = ct.Type 1104 continue 1105 default: 1106 return nil, false 1107 } 1108 } 1109 } 1110 // Recursively follow type definitions to find the actual enum type, or not 1111 // TODO move to separate functionality so it can be reused for union as well 1112 asEnum := func() (*BTFEnumType, bool) { 1113 curType := member.Type 1114 for { 1115 switch ct := curType.(type) { 1116 case *BTFEnumType: 1117 return ct, true 1118 case *BTFTypeDefType: 1119 curType = ct.Type 1120 continue 1121 default: 1122 return nil, false 1123 } 1124 } 1125 } 1126 if t.KindFlag == 1 { 1127 // If the kind_flag is set, 1128 1129 // In this case, if the base type is an int type, it must be a regular int type: 1130 mt, ok := asInt() 1131 if !ok { 1132 // TODO make nice error message, instead of panicing 1133 panic("invalid member type") 1134 } 1135 1136 // BTF_INT_OFFSET() must be 0. 1137 if mt.Offset != 0 { 1138 // TODO make nice error message, instead of panicing 1139 panic("invalid int offset in struct member") 1140 } 1141 1142 // BTF_INT_BITS() must be equal to {1,2,4,8,16} * 8 1143 switch mt.Bits { 1144 case 1 * 8, 2 * 8, 4 * 8, 8 * 8, 16 * 8: 1145 default: 1146 // TODO make nice error message, instead of panicing 1147 panic("invalid bits in int struct member") 1148 } 1149 1150 } else { 1151 // If the type info kind_flag is not set, 1152 1153 // the base type of the bitfield can only be int or enum type. If the bitfield size is 32, 1154 // the base type can be either int or enum type. 1155 if member.BitfieldSize == 32 { 1156 _, ok := asInt() 1157 if !ok { 1158 _, ok = asEnum() 1159 if !ok { 1160 // TODO make nice error message, instead of panicing 1161 panic("invalid struct member type, must be int or enum with 32 bitfield") 1162 } 1163 } 1164 } else { 1165 // If the bitfield size is not 32, 1166 // the base type must be int, and int type BTF_INT_BITS() encodes the bitfield size. 1167 1168 // Recursively figure out if actual type is an int. 1169 mt, ok := asInt() 1170 if !ok { 1171 // TODO Move these checks to a 3rd iteration, since to verify this we need to be able to 1172 // follow type declarations. Currently it fails the 1173 panic("invalid struct member type, must be int for non-32 bitfield") 1174 } 1175 1176 t.Members[i].BitfieldSize = uint32(mt.Bits) 1177 } 1178 } 1179 } 1180 1181 return nil 1182 } 1183 1184 func (t *BTFStructType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) { 1185 var buf bytes.Buffer 1186 1187 const sizeOfMember = 4 1188 buf.Write((commonType{ 1189 Name: t.Name, 1190 KindFlag: t.KindFlag, 1191 Kind: BTF_KIND_STRUCT, 1192 VLen: uint16(len(t.Members)), 1193 sizeType: t.sizeType, 1194 }.ToBTFType(strTbl).ToBytes(order))) 1195 1196 for _, member := range t.Members { 1197 var offset uint32 1198 if t.KindFlag == 1 { 1199 offset = member.BitfieldSize<<24 | (member.BitOffset & 0xffffff) 1200 } else { 1201 offset = member.BitOffset 1202 } 1203 1204 buf.Write(uint32sToBytes( 1205 order, 1206 uint32(strTbl.StrToOffset(member.Name)), 1207 member.typeID, // TODO resolve from member.Type instead of relying on internal type 1208 offset, 1209 )) 1210 } 1211 1212 return buf.Bytes(), nil 1213 } 1214 1215 func (t *BTFStructType) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) { 1216 var err error 1217 if pretty { 1218 _, err = fmt.Fprint(w, "{\n ") 1219 } else { 1220 _, err = fmt.Fprint(w, "{") 1221 } 1222 if err != nil { 1223 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 1224 } 1225 1226 for _, m := range t.Members { 1227 _, err = fmt.Fprint(w, m.Name, ": ") 1228 if err != nil { 1229 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 1230 } 1231 1232 bfmt, ok := m.Type.(BTFValueFormater) 1233 if !ok { 1234 return nil, fmt.Errorf( 1235 "'%s' struct contains nonformattable field '%s' of type '%T'", 1236 t.Name, 1237 m.Name, 1238 m.Type, 1239 ) 1240 } 1241 1242 b, err = bfmt.FormatValue(b, w, pretty) 1243 if err != nil { 1244 return nil, fmt.Errorf("'%s'[%s]: %w", t.Name, m.Name, err) 1245 } 1246 1247 if m != t.Members[len(t.Members)-1] || pretty { 1248 if pretty { 1249 if m == t.Members[len(t.Members)-1] { 1250 _, err = fmt.Fprint(w, ",\n") 1251 } else { 1252 _, err = fmt.Fprint(w, ",\n ") 1253 } 1254 } else { 1255 _, err = fmt.Fprint(w, ", ") 1256 } 1257 if err != nil { 1258 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 1259 } 1260 } 1261 } 1262 1263 _, err = fmt.Fprint(w, "}") 1264 if err != nil { 1265 return nil, fmt.Errorf("'%s' write error: %w", t.Name, err) 1266 } 1267 1268 return b, nil 1269 } 1270 1271 var _ BTFValueFormater = (*BTFUnionType)(nil) 1272 1273 // BTFUnionType is the type for KIND_UNION, which represents a union, where all members occupy the same memory. 1274 type BTFUnionType struct { 1275 commonType 1276 // The individual members / fields of the union. 1277 Members []BTFMember 1278 } 1279 1280 func (t *BTFUnionType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) { 1281 var buf bytes.Buffer 1282 1283 const sizeOfMember = 4 1284 buf.Write((commonType{ 1285 Name: t.Name, 1286 KindFlag: t.KindFlag, 1287 Kind: BTF_KIND_UNION, 1288 VLen: uint16(len(t.Members)), 1289 sizeType: t.sizeType, 1290 }.ToBTFType(strTbl).ToBytes(order))) 1291 1292 for _, member := range t.Members { 1293 var offset uint32 1294 if t.KindFlag == 1 { 1295 offset = member.BitfieldSize<<24 | (member.BitOffset & 0xffffff) 1296 } else { 1297 offset = member.BitOffset 1298 } 1299 1300 buf.Write(uint32sToBytes( 1301 order, 1302 uint32(strTbl.StrToOffset(member.Name)), 1303 member.typeID, // TODO resolve from member.Type instead of relying on internal type 1304 offset, 1305 )) 1306 } 1307 1308 return buf.Bytes(), nil 1309 } 1310 1311 func (t *BTFUnionType) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) { 1312 return nil, errors.New("not yet implemented") 1313 } 1314 1315 var _ BTFValueFormater = (*BTFMember)(nil) 1316 1317 // BTFMember is a member of a struct or union. 1318 type BTFMember struct { 1319 // Name of the member/field 1320 Name string 1321 // Type of the member/field 1322 Type BTFType 1323 typeID uint32 1324 BitfieldSize uint32 1325 BitOffset uint32 1326 } 1327 1328 func (t *BTFMember) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) { 1329 return nil, errors.New("not yet implemented") 1330 } 1331 1332 var _ BTFValueFormater = (*BTFEnumType)(nil) 1333 1334 type BTFEnumType struct { 1335 commonType 1336 Options []BTFEnumOption 1337 } 1338 1339 func (t *BTFEnumType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) { 1340 var buf bytes.Buffer 1341 buf.Write((commonType{ 1342 Name: t.Name, 1343 KindFlag: 0, 1344 Kind: BTF_KIND_ENUM, 1345 VLen: uint16(len(t.Options)), 1346 sizeType: 4, 1347 }.ToBTFType(strTbl).ToBytes(order))) 1348 1349 for _, option := range t.Options { 1350 buf.Write(uint32sToBytes( 1351 order, 1352 uint32(strTbl.StrToOffset(option.Name)), 1353 uint32(option.Value), 1354 )) 1355 } 1356 1357 return buf.Bytes(), nil 1358 } 1359 1360 func (t *BTFEnumType) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) { 1361 return nil, errors.New("not yet implemented") 1362 } 1363 1364 type BTFEnumOption struct { 1365 Name string 1366 Value int32 1367 } 1368 1369 var _ BTFValueFormater = (*BTFForwardType)(nil) 1370 1371 type BTFForwardType struct { 1372 commonType 1373 } 1374 1375 func (t *BTFForwardType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) { 1376 return (commonType{ 1377 Name: t.Name, 1378 KindFlag: t.KindFlag, 1379 Kind: BTF_KIND_FWD, 1380 VLen: 0, 1381 sizeType: 0, 1382 }.ToBTFType(strTbl).ToBytes(order)), nil 1383 } 1384 1385 func (t *BTFForwardType) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) { 1386 return nil, errors.New("not yet implemented") 1387 } 1388 1389 var _ BTFValueFormater = (*BTFTypeDefType)(nil) 1390 1391 type BTFTypeDefType struct { 1392 commonType 1393 } 1394 1395 func (t *BTFTypeDefType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) { 1396 return (commonType{ 1397 Name: t.Name, 1398 KindFlag: 0, 1399 Kind: BTF_KIND_TYPEDEF, 1400 VLen: 0, 1401 sizeType: uint32(t.Type.GetID()), // TODO resolve ID based on index in BTF.Types 1402 }.ToBTFType(strTbl).ToBytes(order)), nil 1403 } 1404 1405 func (t *BTFTypeDefType) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) { 1406 if bfmt, ok := t.Type.(BTFValueFormater); ok { 1407 return bfmt.FormatValue(b, w, pretty) 1408 } 1409 1410 return nil, fmt.Errorf("'%s' typedef to unformatable type '%T'", t.Name, t.Type) 1411 } 1412 1413 var _ BTFValueFormater = (*BTFVolatileType)(nil) 1414 1415 type BTFVolatileType struct { 1416 commonType 1417 } 1418 1419 func (t *BTFVolatileType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) { 1420 return (commonType{ 1421 Name: "", 1422 KindFlag: 0, 1423 Kind: BTF_KIND_VOLATILE, 1424 VLen: 0, 1425 sizeType: uint32(t.Type.GetID()), // TODO resolve ID based on index in BTF.Types 1426 }.ToBTFType(strTbl).ToBytes(order)), nil 1427 } 1428 1429 func (t *BTFVolatileType) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) { 1430 // Volatile is a modifier, doesn't change anything to the value formatting of the underlaying type 1431 if bfmt, ok := t.Type.(BTFValueFormater); ok { 1432 return bfmt.FormatValue(b, w, pretty) 1433 } 1434 1435 return nil, fmt.Errorf("'%s' volatile type to unformatable type '%T'", t.Name, t.Type) 1436 } 1437 1438 var _ BTFValueFormater = (*BTFConstType)(nil) 1439 1440 type BTFConstType struct { 1441 commonType 1442 } 1443 1444 func (t *BTFConstType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) { 1445 return (commonType{ 1446 Name: "", 1447 KindFlag: 0, 1448 Kind: BTF_KIND_CONST, 1449 VLen: 0, 1450 sizeType: uint32(t.Type.GetID()), // TODO resolve ID based on index in BTF.Types 1451 }.ToBTFType(strTbl).ToBytes(order)), nil 1452 } 1453 1454 func (t *BTFConstType) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) { 1455 // Const is a modifier, doesn't change anything to the value formatting of the underlaying type 1456 if bfmt, ok := t.Type.(BTFValueFormater); ok { 1457 return bfmt.FormatValue(b, w, pretty) 1458 } 1459 1460 return nil, fmt.Errorf("'%s' const type to unformatable type '%T'", t.Name, t.Type) 1461 } 1462 1463 var _ BTFValueFormater = (*BTFRestrictType)(nil) 1464 1465 type BTFRestrictType struct { 1466 commonType 1467 } 1468 1469 func (t *BTFRestrictType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) { 1470 return (commonType{ 1471 Name: "", 1472 KindFlag: 0, 1473 Kind: BTF_KIND_RESTRICT, 1474 VLen: 0, 1475 sizeType: uint32(t.Type.GetID()), // TODO resolve ID based on index in BTF.Types 1476 }.ToBTFType(strTbl).ToBytes(order)), nil 1477 } 1478 1479 func (t *BTFRestrictType) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) { 1480 // Restrict is a modifier, doesn't change anything to the value formatting of the underlaying type 1481 if bfmt, ok := t.Type.(BTFValueFormater); ok { 1482 return bfmt.FormatValue(b, w, pretty) 1483 } 1484 1485 return nil, fmt.Errorf("'%s' restrict type to unformatable type '%T'", t.Name, t.Type) 1486 } 1487 1488 // A BTFFuncType defines not a type, but a subprogram (function) whose signature is defined by type. 1489 // The subprogram is thus an instance of that type. 1490 // The KIND_FUNC may in turn be referenced by a func_info in the 4.2 .BTF.ext section (ELF) or in the arguments 1491 // to 3.3 BPF_PROG_LOAD (ABI). 1492 type BTFFuncType struct { 1493 commonType 1494 } 1495 1496 func (t *BTFFuncType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) { 1497 vlen := uint16(0) 1498 if kernelsupport.CurrentFeatures.Misc.Has(kernelsupport.KFeatBTFFuncScope) { 1499 vlen = t.VLen 1500 } 1501 1502 return (commonType{ 1503 Name: t.Name, 1504 KindFlag: 0, 1505 Kind: BTF_KIND_FUNC, 1506 VLen: vlen, 1507 sizeType: uint32(t.Type.GetID()), // TODO resolve ID based on index in BTF.Types 1508 }.ToBTFType(strTbl).ToBytes(order)), nil 1509 } 1510 1511 type BTFFuncProtoType struct { 1512 commonType 1513 Params []BTFFuncProtoParam 1514 } 1515 1516 func (t *BTFFuncProtoType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) { 1517 var buf bytes.Buffer 1518 1519 buf.Write((commonType{ 1520 Name: t.Name, 1521 KindFlag: t.KindFlag, 1522 Kind: BTF_KIND_FUNC_PROTO, 1523 VLen: uint16(len(t.Params)), 1524 sizeType: uint32(t.Type.GetID()), 1525 }.ToBTFType(strTbl).ToBytes(order))) 1526 1527 for _, param := range t.Params { 1528 buf.Write(uint32sToBytes( 1529 order, 1530 uint32(strTbl.StrToOffset(param.Name)), 1531 )) 1532 1533 if param.Type == nil { 1534 buf.Write(uint32sToBytes( 1535 order, 1536 0, 1537 )) 1538 } else { 1539 buf.Write(uint32sToBytes( 1540 order, 1541 uint32(param.Type.GetID()), 1542 )) 1543 } 1544 } 1545 1546 return buf.Bytes(), nil 1547 } 1548 1549 type BTFFuncProtoParam struct { 1550 Name string 1551 Type BTFType 1552 typeID uint32 1553 } 1554 1555 type BTFVarType struct { 1556 commonType 1557 Linkage uint32 1558 } 1559 1560 func (t *BTFVarType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) { 1561 commonBytes := (commonType{ 1562 Name: t.Name, 1563 KindFlag: 0, 1564 Kind: BTF_KIND_VAR, 1565 VLen: 0, 1566 sizeType: uint32(t.Type.GetID()), 1567 }.ToBTFType(strTbl).ToBytes(order)) 1568 1569 return append(commonBytes, uint32sToBytes(order, t.Linkage)...), nil 1570 } 1571 1572 func (t *BTFVarType) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) { 1573 if bfmt, ok := t.Type.(BTFValueFormater); ok { 1574 return bfmt.FormatValue(b, w, pretty) 1575 } 1576 1577 return nil, fmt.Errorf("'%s' variable to unformatable type '%T'", t.Name, t.Type) 1578 } 1579 1580 type BTFDataSecType struct { 1581 commonType 1582 Variables []BTFDataSecVariable 1583 1584 // Offset from the start of the types byte slice to the SizeType field 1585 sizeOffset int 1586 } 1587 1588 func (t *BTFDataSecType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) { 1589 var buf bytes.Buffer 1590 1591 buf.Write((commonType{ 1592 Name: t.Name, 1593 KindFlag: 0, 1594 Kind: BTF_KIND_DATASEC, 1595 VLen: uint16(len(t.Variables)), 1596 sizeType: t.Size, 1597 }.ToBTFType(strTbl).ToBytes(order))) 1598 1599 for _, v := range t.Variables { 1600 buf.Write(uint32sToBytes( 1601 order, 1602 uint32(v.Type.GetID()), 1603 v.Offset, 1604 v.Size, 1605 )) 1606 } 1607 1608 return buf.Bytes(), nil 1609 } 1610 1611 type BTFDataSecVariable struct { 1612 Type BTFType 1613 typeID uint32 1614 Offset uint32 1615 Size uint32 1616 1617 // Offset from the start of the types byte slice to the Offset field 1618 offsetOffset int 1619 } 1620 1621 var _ BTFValueFormater = (*BTFFloatType)(nil) 1622 1623 type BTFFloatType struct { 1624 commonType 1625 } 1626 1627 func (t *BTFFloatType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) { 1628 return (commonType{ 1629 Name: t.Name, 1630 KindFlag: 0, 1631 Kind: BTF_KIND_FLOAT, 1632 VLen: 0, 1633 sizeType: t.Size, 1634 }.ToBTFType(strTbl).ToBytes(order)), nil 1635 } 1636 1637 func (t *BTFFloatType) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) { 1638 if len(b) < int(t.Size) { 1639 return nil, fmt.Errorf("%s not enough bytes to decode float of size '%d'", t.Name, t.Size) 1640 } 1641 1642 switch t.Size { 1643 case 2: 1644 // Go doesn't have native 16 bit floating point numbers, maybe use https://pkg.go.dev/github.com/x448/float16? 1645 // Then again, how common is this? 1646 return nil, fmt.Errorf("%s ieee754 binary16 floating point not supported", t.Name) 1647 1648 case 4: 1649 bits := binary.LittleEndian.Uint32(b[:4]) 1650 float := math.Float32frombits(bits) 1651 _, err := fmt.Fprint(w, strconv.FormatFloat(float64(float), 'g', -1, 32)) 1652 if err != nil { 1653 return nil, fmt.Errorf("%s write error: %w", t.Name, err) 1654 } 1655 1656 return b[4:], nil 1657 1658 case 8: 1659 bits := binary.LittleEndian.Uint32(b[:8]) 1660 float := math.Float32frombits(bits) 1661 _, err := fmt.Fprint(w, strconv.FormatFloat(float64(float), 'g', -1, 64)) 1662 if err != nil { 1663 return nil, fmt.Errorf("%s write error: %w", t.Name, err) 1664 } 1665 1666 return b[8:], nil 1667 1668 case 16: 1669 // Go doesn't have native 128 bit floating point numbers, can we use big.Int here? 1670 // Then again, how common is this? 1671 return nil, fmt.Errorf("%s ieee754 binary128 floating point not supported", t.Name) 1672 } 1673 1674 return nil, fmt.Errorf("%s '%d'-byte floating point number not supported", t.Name, t.Size) 1675 } 1676 1677 // BTFDeclTagType The name_off encodes btf_decl_tag attribute string. 1678 // The type should be struct, union, func, var or typedef. 1679 // For var or typedef type, btf_decl_tag.component_idx must be -1. 1680 // For the other three types, if the btf_decl_tag attribute is applied to the struct, 1681 // union or func itself, btf_decl_tag.component_idx must be -1. 1682 // Otherwise, the attribute is applied to a struct/union member or a func argument, 1683 // and btf_decl_tag.component_idx should be a valid index (starting from 0) pointing to a member or an argument. 1684 type BTFDeclTagType struct { 1685 commonType 1686 ComponentIdx uint32 1687 } 1688 1689 func (t *BTFDeclTagType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) { 1690 commonBytes := (commonType{ 1691 Name: t.Name, 1692 KindFlag: 0, 1693 Kind: BTF_KIND_DECL_TAG, 1694 VLen: 0, 1695 sizeType: uint32(t.Type.GetID()), 1696 }.ToBTFType(strTbl).ToBytes(order)) 1697 1698 return append(commonBytes, uint32sToBytes(order, t.ComponentIdx)...), nil 1699 } 1700 1701 // BTFVoidType is not an actual type in BTF, it is used as type ID 0. 1702 type BTFVoidType struct{} 1703 1704 func (vt *BTFVoidType) GetID() int { 1705 return 0 1706 } 1707 1708 func (vt *BTFVoidType) GetKind() BTFKind { 1709 return BTF_KIND_UNKN 1710 } 1711 1712 func (vt *BTFVoidType) GetName() string { 1713 return "" 1714 } 1715 1716 func (vt *BTFVoidType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) { 1717 return nil, nil 1718 } 1719 1720 // BTFKind is an enum indicating what kind of type is indicated 1721 type BTFKind uint8 1722 1723 const ( 1724 // BTF_KIND_UNKN Unknown 1725 BTF_KIND_UNKN BTFKind = iota 1726 // BTF_KIND_INT Integer 1727 BTF_KIND_INT 1728 // BTF_KIND_PTR Pointer 1729 BTF_KIND_PTR 1730 // BTF_KIND_ARRAY Array 1731 BTF_KIND_ARRAY 1732 // BTF_KIND_STRUCT Struct 1733 BTF_KIND_STRUCT 1734 // BTF_KIND_UNION Union 1735 BTF_KIND_UNION 1736 // BTF_KIND_ENUM Enumeration 1737 BTF_KIND_ENUM 1738 // BTF_KIND_FWD Forward 1739 BTF_KIND_FWD 1740 // BTF_KIND_TYPEDEF Typedef 1741 BTF_KIND_TYPEDEF 1742 // BTF_KIND_VOLATILE Volatile 1743 BTF_KIND_VOLATILE 1744 // BTF_KIND_CONST Const 1745 BTF_KIND_CONST 1746 // BTF_KIND_RESTRICT Restrict 1747 BTF_KIND_RESTRICT 1748 // BTF_KIND_FUNC Function 1749 BTF_KIND_FUNC 1750 // BTF_KIND_FUNC_PROTO Function Proto 1751 BTF_KIND_FUNC_PROTO 1752 // BTF_KIND_VAR Variable 1753 BTF_KIND_VAR 1754 // BTF_KIND_DATASEC Section 1755 BTF_KIND_DATASEC 1756 // BTF_KIND_FLOAT Floating point 1757 BTF_KIND_FLOAT 1758 // BTF_KIND_DECL_TAG Decl Tag 1759 BTF_KIND_DECL_TAG 1760 1761 // Not an actual value, must always be last in const block 1762 //nolint:deadcode,varcheck // used in unit test 1763 btfKindMax 1764 ) 1765 1766 var btfKindToStr = map[BTFKind]string{ 1767 BTF_KIND_UNKN: "Unknown", 1768 BTF_KIND_INT: "Integer", 1769 BTF_KIND_PTR: "Pointer", 1770 BTF_KIND_ARRAY: "Array", 1771 BTF_KIND_STRUCT: "Struct", 1772 BTF_KIND_UNION: "Union", 1773 BTF_KIND_ENUM: "Enumeration", 1774 BTF_KIND_FWD: "Forward", 1775 BTF_KIND_TYPEDEF: "Typedef", 1776 BTF_KIND_VOLATILE: "Volatile", 1777 BTF_KIND_CONST: "Const", 1778 BTF_KIND_RESTRICT: "Restrict", 1779 BTF_KIND_FUNC: "Function", 1780 BTF_KIND_FUNC_PROTO: "Proto function", 1781 BTF_KIND_VAR: "Variable", 1782 BTF_KIND_DATASEC: "Data section", 1783 BTF_KIND_FLOAT: "Floating point", 1784 BTF_KIND_DECL_TAG: "Decl tag", 1785 } 1786 1787 func (bk BTFKind) String() string { 1788 return btfKindToStr[bk] 1789 } 1790 1791 // The length of the Magic, Version, Flags, and HeaderLength fields 1792 const commonLength = 8 1793 1794 // commonHeader is shared between the .BTF header and .BTF.ext header 1795 type commonHeader struct { 1796 // Magic is always 0xeB9F, can be used to tell if the data is little or bigendian 1797 Magic uint16 1798 byteOrder binary.ByteOrder 1799 // BTF version number 1800 Version uint8 1801 // Flags is unused (AFAIK) 1802 Flags uint8 1803 // HeaderLength is the size of this struct. Here for forwards/backwards compatibility since the size of this 1804 // header may change in the future. 1805 HeaderLength uint32 1806 } 1807 1808 // Magic number of BTF 1809 // https://elixir.bootlin.com/linux/v5.15.3/source/include/uapi/linux/btf.h#L8 1810 const btfMagic = 0xEB9F 1811 1812 func parseCommonHeader(btf []byte) (commonHeader, uint32, error) { 1813 btfLen := len(btf) 1814 if btfLen < 8 { 1815 return commonHeader{}, 0, errors.New("not enough bytes to parse BTF header") 1816 } 1817 1818 hdr := commonHeader{ 1819 byteOrder: binary.LittleEndian, 1820 } 1821 off := 0 1822 1823 read8 := func() uint8 { 1824 v := btf[off] 1825 off = off + 1 1826 return v 1827 } 1828 read32 := func() uint32 { 1829 v := hdr.byteOrder.Uint32(btf[off : off+4]) 1830 off = off + 4 1831 return v 1832 } 1833 1834 magic := hdr.byteOrder.Uint16(btf[off : off+2]) 1835 // If the read magic number doesn't match, switch encoding 1836 if magic != btfMagic { 1837 hdr.byteOrder = binary.BigEndian 1838 1839 // Read it again, if it still doesn't match the data is not right 1840 magic = hdr.byteOrder.Uint16(btf[off : off+2]) 1841 if magic != btfMagic { 1842 return commonHeader{}, 0, errors.New("byte sequence doesn't contain valid BTF magic number") 1843 } 1844 } 1845 off += 2 1846 1847 // Set outside init, since the code is order dependant, and I don't know if struct init happens in defined order. 1848 hdr.Version = read8() 1849 hdr.Flags = read8() 1850 hdr.HeaderLength = read32() 1851 1852 return hdr, commonLength, nil 1853 } 1854 1855 // btfHeader is the header of the ELF .BTF section 1856 type btfHeader struct { 1857 commonHeader 1858 1859 // The offset from the end of this header to the start of the type info 1860 TypeOffset uint32 1861 // The amount of bytes of type info there is 1862 TypeLength uint32 1863 // The offset for the end of this header to the start fo the strings 1864 StringOffset uint32 1865 // The length of the strings 1866 StringLength uint32 1867 } 1868 1869 // parseBTFHeader parses the .BTF header of an ELF file, it returns the header, and the amount of bytes read. 1870 // Or it resturn only an error. 1871 func parseBTFHeader(btf []byte) (*btfHeader, uint32, error) { 1872 var err error 1873 hdr := btfHeader{} 1874 off := uint32(0) 1875 1876 hdr.commonHeader, off, err = parseCommonHeader(btf) 1877 if err != nil { 1878 return nil, off, fmt.Errorf("parse common header: %w", err) 1879 } 1880 1881 btfLen := len(btf) 1882 if btfLen < int(hdr.HeaderLength)-commonLength { 1883 return nil, off, errors.New("byte sequence smaller than indicated header size") 1884 } 1885 1886 read32 := func() uint32 { 1887 v := hdr.byteOrder.Uint32(btf[off : off+4]) 1888 off = off + 4 1889 return v 1890 } 1891 1892 hdr.TypeOffset = read32() 1893 hdr.TypeLength = read32() 1894 hdr.StringOffset = read32() 1895 hdr.StringLength = read32() 1896 1897 // Return slice of indicated length, in case it is longer than the struct we know 1898 return &hdr, hdr.HeaderLength, nil 1899 } 1900 1901 // btfExtHeader is the header of the ELF .BTF.ext section 1902 type btfExtHeader struct { 1903 commonHeader 1904 1905 // The offset from the end of this header to the start of the func info 1906 FuncOffset uint32 1907 // The amount of bytes of func info there is 1908 FuncLength uint32 1909 // The offset for the end of this header to the start fo the lines 1910 LineOffset uint32 1911 // The length of the lines 1912 LineLength uint32 1913 } 1914 1915 // parseBTFExtHeader parses the .BTF.ext header of an ELF File, it return the header and the amount of bytes read, 1916 // or and error 1917 func parseBTFExtHeader(btf []byte) (*btfExtHeader, uint32, error) { 1918 var err error 1919 hdr := btfExtHeader{} 1920 off := uint32(0) 1921 1922 hdr.commonHeader, off, err = parseCommonHeader(btf) 1923 if err != nil { 1924 return nil, off, fmt.Errorf("parse common header: %w", err) 1925 } 1926 1927 btfLen := len(btf) 1928 if btfLen < int(hdr.HeaderLength)-commonLength { 1929 return nil, off, errors.New("byte sequence smaller than indicated header size") 1930 } 1931 1932 read32 := func() uint32 { 1933 v := hdr.byteOrder.Uint32(btf[off : off+4]) 1934 off = off + 4 1935 return v 1936 } 1937 1938 hdr.FuncOffset = read32() 1939 hdr.FuncLength = read32() 1940 hdr.LineOffset = read32() 1941 hdr.LineLength = read32() 1942 1943 // Return slice of indicated length, in case it is longer than the struct we know 1944 return &hdr, hdr.HeaderLength, nil 1945 } 1946 1947 // btfType is the type as you would find it on disk 1948 type btfType struct { 1949 NameOffset uint32 1950 1951 /* "info" bits arrangement 1952 * bits 0-15: vlen (e.g. # of struct's members) 1953 * bits 16-23: unused 1954 * bits 24-28: kind (e.g. int, ptr, array...etc) 1955 * bits 29-30: unused 1956 * bit 31: kind_flag, currently used by 1957 * struct, union and fwd 1958 */ 1959 Info uint32 1960 1961 // SizeType is a union of "size" and "type" 1962 // "size" is used by INT, ENUM, STRUCT and UNION. 1963 // "size" tells the size of the type it is describing. 1964 // 1965 // "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT, 1966 // FUNC, FUNC_PROTO and DECL_TAG. 1967 // "type" is a type_id referring to another type. 1968 // 1969 SizeType uint32 1970 } 1971 1972 func (bt btfType) ToCommonType(strTbl *StringTbl) commonType { 1973 // TODO add links to clarify shifts and masks 1974 return commonType{ 1975 Name: strTbl.GetStringAtOffset(int(bt.NameOffset)), 1976 VLen: uint16((bt.Info) & 0xffff), 1977 Kind: BTFKind(((bt.Info) >> 24) & 0x1f), 1978 KindFlag: uint8(bt.Info >> 31), 1979 sizeType: bt.SizeType, 1980 } 1981 } 1982 1983 func (bt btfType) ToBytes(order binary.ByteOrder) []byte { 1984 ret := make([]byte, 12) 1985 order.PutUint32(ret[0:4], bt.NameOffset) 1986 order.PutUint32(ret[4:8], bt.Info) 1987 order.PutUint32(ret[8:12], bt.SizeType) 1988 return ret 1989 } 1990 1991 type commonType struct { 1992 Name string 1993 VLen uint16 1994 Kind BTFKind 1995 KindFlag uint8 1996 Type BTFType 1997 Size uint32 1998 sizeType uint32 1999 TypeID int 2000 } 2001 2002 func (ct *commonType) GetKind() BTFKind { 2003 return ct.Kind 2004 } 2005 2006 func (ct *commonType) GetID() int { 2007 return ct.TypeID 2008 } 2009 2010 func (ct *commonType) GetName() string { 2011 return ct.Name 2012 } 2013 2014 func (ct commonType) ToBTFType(strTbl *StringTbl) btfType { 2015 bt := btfType{ 2016 NameOffset: uint32(strTbl.StrToOffset(ct.Name)), 2017 Info: (uint32(ct.KindFlag&0b00000001) << 31) | 2018 (uint32(ct.Kind&0x1f) << 24) | 2019 uint32(ct.VLen), 2020 SizeType: ct.sizeType, 2021 } 2022 return bt 2023 } 2024 2025 func uint32sToBytes(bo binary.ByteOrder, ints ...uint32) []byte { 2026 b := make([]byte, 4*len(ints)) 2027 for i := 0; i < len(ints); i++ { 2028 bo.PutUint32(b[i*4:(i+1)*4], ints[i]) 2029 } 2030 return b 2031 }