github.com/kubeshark/ebpf@v0.9.2/elf_reader_test.go (about) 1 package ebpf 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "errors" 7 "flag" 8 "fmt" 9 "os" 10 "path/filepath" 11 "strings" 12 "syscall" 13 "testing" 14 15 "github.com/kubeshark/ebpf/btf" 16 "github.com/kubeshark/ebpf/internal" 17 "github.com/kubeshark/ebpf/internal/testutils" 18 "github.com/kubeshark/ebpf/internal/unix" 19 20 "github.com/google/go-cmp/cmp" 21 "github.com/google/go-cmp/cmp/cmpopts" 22 ) 23 24 func TestLoadCollectionSpec(t *testing.T) { 25 cpus, err := internal.PossibleCPUs() 26 if err != nil { 27 t.Fatal(err) 28 } 29 30 coll := &CollectionSpec{ 31 Maps: map[string]*MapSpec{ 32 "hash_map": { 33 Name: "hash_map", 34 Type: Hash, 35 KeySize: 4, 36 ValueSize: 8, 37 MaxEntries: 1, 38 Flags: unix.BPF_F_NO_PREALLOC, 39 }, 40 "hash_map2": { 41 Name: "hash_map2", 42 Type: Hash, 43 KeySize: 4, 44 ValueSize: 8, 45 MaxEntries: 2, 46 }, 47 "array_of_hash_map": { 48 Name: "array_of_hash_map", 49 Type: ArrayOfMaps, 50 KeySize: 4, 51 MaxEntries: 2, 52 }, 53 "perf_event_array": { 54 Name: "perf_event_array", 55 Type: PerfEventArray, 56 MaxEntries: uint32(cpus), 57 }, 58 // Maps prefixed by btf_ are ignored when testing ELFs 59 // that don't have BTF info embedded. (clang<9) 60 "btf_pin": { 61 Name: "btf_pin", 62 Type: Hash, 63 KeySize: 4, 64 ValueSize: 8, 65 MaxEntries: 1, 66 Pinning: PinByName, 67 }, 68 "btf_outer_map": { 69 Name: "btf_outer_map", 70 Type: ArrayOfMaps, 71 KeySize: 4, 72 ValueSize: 4, 73 MaxEntries: 1, 74 InnerMap: &MapSpec{ 75 Name: "btf_outer_map_inner", 76 Type: Hash, 77 KeySize: 4, 78 ValueSize: 4, 79 MaxEntries: 1, 80 }, 81 }, 82 "btf_outer_map_anon": { 83 Name: "btf_outer_map_anon", 84 Type: ArrayOfMaps, 85 KeySize: 4, 86 ValueSize: 4, 87 MaxEntries: 1, 88 InnerMap: &MapSpec{ 89 Name: "btf_outer_map_anon_inner", 90 Type: Hash, 91 KeySize: 4, 92 ValueSize: 4, 93 MaxEntries: 1, 94 }, 95 }, 96 }, 97 Programs: map[string]*ProgramSpec{ 98 "xdp_prog": { 99 Name: "xdp_prog", 100 Type: XDP, 101 SectionName: "xdp", 102 License: "MIT", 103 }, 104 "no_relocation": { 105 Name: "no_relocation", 106 Type: SocketFilter, 107 SectionName: "socket", 108 License: "MIT", 109 }, 110 "asm_relocation": { 111 Name: "asm_relocation", 112 Type: SocketFilter, 113 SectionName: "socket/2", 114 License: "MIT", 115 }, 116 "data_sections": { 117 Name: "data_sections", 118 Type: SocketFilter, 119 SectionName: "socket/3", 120 License: "MIT", 121 }, 122 "global_fn3": { 123 Name: "global_fn3", 124 Type: UnspecifiedProgram, 125 SectionName: "other", 126 License: "MIT", 127 }, 128 "static_fn": { 129 Name: "static_fn", 130 Type: UnspecifiedProgram, 131 SectionName: "static", 132 License: "MIT", 133 }, 134 "anon_const": { 135 Name: "anon_const", 136 Type: SocketFilter, 137 SectionName: "socket/4", 138 License: "MIT", 139 }, 140 }, 141 } 142 143 defaultOpts := cmp.Options{ 144 // Dummy Comparer that works with empty readers to support test cases. 145 cmp.Comparer(func(a, b bytes.Reader) bool { 146 if a.Len() == 0 && b.Len() == 0 { 147 return true 148 } 149 return false 150 }), 151 cmpopts.IgnoreTypes(new(btf.Spec)), 152 cmpopts.IgnoreFields(CollectionSpec{}, "ByteOrder", "Types"), 153 cmpopts.IgnoreFields(ProgramSpec{}, "Instructions", "ByteOrder"), 154 cmpopts.IgnoreFields(MapSpec{}, "Key", "Value"), 155 cmpopts.IgnoreUnexported(ProgramSpec{}), 156 cmpopts.IgnoreMapEntries(func(key string, _ *MapSpec) bool { 157 if key == ".bss" || key == ".data" || strings.HasPrefix(key, ".rodata") { 158 return true 159 } 160 return false 161 }), 162 } 163 164 ignoreBTFOpts := append(defaultOpts, 165 cmpopts.IgnoreMapEntries(func(key string, _ *MapSpec) bool { 166 return strings.HasPrefix(key, "btf_") 167 }), 168 ) 169 170 testutils.Files(t, testutils.Glob(t, "testdata/loader-*.elf"), func(t *testing.T, file string) { 171 have, err := LoadCollectionSpec(file) 172 if err != nil { 173 t.Fatal("Can't parse ELF:", err) 174 } 175 176 opts := defaultOpts 177 if have.Types != nil { 178 err := have.RewriteConstants(map[string]interface{}{ 179 "arg": uint32(1), 180 "arg2": uint32(2), 181 }) 182 if err != nil { 183 t.Fatal("Can't rewrite constant:", err) 184 } 185 186 err = have.RewriteConstants(map[string]interface{}{ 187 "totallyBogus": uint32(1), 188 }) 189 if err == nil { 190 t.Error("Rewriting a bogus constant doesn't fail") 191 } 192 } else { 193 opts = ignoreBTFOpts 194 } 195 196 if diff := cmp.Diff(coll, have, opts...); diff != "" { 197 t.Errorf("MapSpec mismatch (-want +got):\n%s", diff) 198 } 199 200 if have.ByteOrder != internal.NativeEndian { 201 return 202 } 203 204 have.Maps["array_of_hash_map"].InnerMap = have.Maps["hash_map"] 205 coll, err := NewCollectionWithOptions(have, CollectionOptions{ 206 Maps: MapOptions{ 207 PinPath: testutils.TempBPFFS(t), 208 }, 209 Programs: ProgramOptions{ 210 LogLevel: 1, 211 }, 212 }) 213 testutils.SkipIfNotSupported(t, err) 214 if err != nil { 215 t.Fatal(err) 216 } 217 defer coll.Close() 218 219 ret, _, err := coll.Programs["xdp_prog"].Test(make([]byte, 14)) 220 if err != nil { 221 t.Fatal("Can't run program:", err) 222 } 223 224 if ret != 7 { 225 t.Error("Expected return value to be 5, got", ret) 226 } 227 }) 228 } 229 230 func BenchmarkELFLoader(b *testing.B) { 231 b.ReportAllocs() 232 233 for i := 0; i < b.N; i++ { 234 _, _ = LoadCollectionSpec("testdata/loader-el.elf") 235 } 236 } 237 238 func TestDataSections(t *testing.T) { 239 file := fmt.Sprintf("testdata/loader-%s.elf", internal.ClangEndian) 240 coll, err := LoadCollectionSpec(file) 241 if err != nil { 242 t.Fatal(err) 243 } 244 245 t.Log(coll.Programs["data_sections"].Instructions) 246 247 var obj struct { 248 Program *Program `ebpf:"data_sections"` 249 } 250 251 err = coll.LoadAndAssign(&obj, nil) 252 testutils.SkipIfNotSupported(t, err) 253 if err != nil { 254 t.Fatal(err) 255 } 256 defer obj.Program.Close() 257 258 ret, _, err := obj.Program.Test(make([]byte, 14)) 259 if err != nil { 260 t.Fatal(err) 261 } 262 263 if ret != 0 { 264 t.Error("BPF assertion failed on line", ret) 265 } 266 } 267 268 func TestInlineASMConstant(t *testing.T) { 269 file := fmt.Sprintf("testdata/loader-%s.elf", internal.ClangEndian) 270 coll, err := LoadCollectionSpec(file) 271 if err != nil { 272 t.Fatal(err) 273 } 274 275 spec := coll.Programs["asm_relocation"] 276 if spec.Instructions[0].Reference() != "MY_CONST" { 277 t.Fatal("First instruction is not a reference to MY_CONST") 278 } 279 280 // -1 is used by the loader to find unrewritten maps. 281 spec.Instructions[0].Constant = -1 282 283 t.Log(spec.Instructions) 284 285 var obj struct { 286 Program *Program `ebpf:"asm_relocation"` 287 } 288 289 err = coll.LoadAndAssign(&obj, nil) 290 testutils.SkipIfNotSupported(t, err) 291 if err != nil { 292 t.Fatal(err) 293 } 294 obj.Program.Close() 295 } 296 297 func TestCollectionSpecDetach(t *testing.T) { 298 coll := Collection{ 299 Maps: map[string]*Map{ 300 "foo": new(Map), 301 }, 302 Programs: map[string]*Program{ 303 "bar": new(Program), 304 }, 305 } 306 307 foo := coll.DetachMap("foo") 308 if foo == nil { 309 t.Error("Program not returned from DetachMap") 310 } 311 312 if _, ok := coll.Programs["foo"]; ok { 313 t.Error("DetachMap doesn't remove map from Maps") 314 } 315 316 bar := coll.DetachProgram("bar") 317 if bar == nil { 318 t.Fatal("Program not returned from DetachProgram") 319 } 320 321 if _, ok := coll.Programs["bar"]; ok { 322 t.Error("DetachProgram doesn't remove program from Programs") 323 } 324 } 325 326 func TestLoadInvalidMap(t *testing.T) { 327 testutils.Files(t, testutils.Glob(t, "testdata/invalid_map-*.elf"), func(t *testing.T, file string) { 328 cs, err := LoadCollectionSpec(file) 329 if err != nil { 330 t.Fatal("Can't load CollectionSpec", err) 331 } 332 333 ms, ok := cs.Maps["invalid_map"] 334 if !ok { 335 t.Fatal("invalid_map not found in CollectionSpec") 336 } 337 338 m, err := NewMap(ms) 339 t.Log(err) 340 if err == nil { 341 m.Close() 342 t.Fatal("Creating a Map from a MapSpec with non-zero Extra is expected to fail.") 343 } 344 }) 345 } 346 347 func TestLoadInvalidMapMissingSymbol(t *testing.T) { 348 testutils.Files(t, testutils.Glob(t, "testdata/invalid_map_static-el.elf"), func(t *testing.T, file string) { 349 _, err := LoadCollectionSpec(file) 350 t.Log(err) 351 if err == nil { 352 t.Fatal("Loading a map with static qualifier should fail") 353 } 354 }) 355 } 356 357 func TestLoadInitializedBTFMap(t *testing.T) { 358 testutils.Files(t, testutils.Glob(t, "testdata/btf_map_init-*.elf"), func(t *testing.T, file string) { 359 coll, err := LoadCollectionSpec(file) 360 if err != nil { 361 t.Fatal(err) 362 } 363 364 t.Run("prog_array", func(t *testing.T) { 365 m, ok := coll.Maps["prog_array_init"] 366 if !ok { 367 t.Fatal("map prog_array_init not found in program") 368 } 369 370 if len(m.Contents) != 1 { 371 t.Error("expecting exactly 1 item in MapSpec contents") 372 } 373 374 p := m.Contents[0] 375 if cmp.Equal(p.Key, 1) { 376 t.Errorf("expecting MapSpec entry Key to equal 1, got %v", p.Key) 377 } 378 379 if _, ok := p.Value.(string); !ok { 380 t.Errorf("expecting MapSpec entry Value to be a string, got %T", p.Value) 381 } 382 383 if p.Value != "tail_1" { 384 t.Errorf("expected MapSpec entry Value 'tail_1', got: %s", p.Value) 385 } 386 }) 387 388 t.Run("array_of_maps", func(t *testing.T) { 389 m, ok := coll.Maps["outer_map_init"] 390 if !ok { 391 t.Fatal("map outer_map_init not found in program") 392 } 393 394 if len(m.Contents) != 1 { 395 t.Error("expecting exactly 1 item in MapSpec contents") 396 } 397 398 p := m.Contents[0] 399 if cmp.Equal(p.Key, 1) { 400 t.Errorf("expecting MapSpec entry Key to equal 1, got %v", p.Key) 401 } 402 403 if _, ok := p.Value.(string); !ok { 404 t.Errorf("expecting MapSpec entry Value to be a string, got %T", p.Value) 405 } 406 407 if p.Value != "inner_map" { 408 t.Errorf("expected MapSpec entry Value 'inner_map', got: %s", p.Value) 409 } 410 }) 411 }) 412 } 413 414 func TestLoadInvalidInitializedBTFMap(t *testing.T) { 415 testutils.Files(t, testutils.Glob(t, "testdata/invalid_btf_map_init-*.elf"), func(t *testing.T, file string) { 416 _, err := LoadCollectionSpec(file) 417 t.Log(err) 418 if !errors.Is(err, internal.ErrNotSupported) { 419 t.Fatal("Loading an initialized BTF map should be unsupported") 420 } 421 }) 422 } 423 424 func TestStringSection(t *testing.T) { 425 testutils.Files(t, testutils.Glob(t, "testdata/strings-*.elf"), func(t *testing.T, file string) { 426 _, err := LoadCollectionSpec(file) 427 t.Log(err) 428 if !errors.Is(err, ErrNotSupported) { 429 t.Error("References to a string section should be unsupported") 430 } 431 }) 432 } 433 434 func TestLoadRawTracepoint(t *testing.T) { 435 testutils.SkipOnOldKernel(t, "4.17", "BPF_RAW_TRACEPOINT API") 436 437 testutils.Files(t, testutils.Glob(t, "testdata/raw_tracepoint-*.elf"), func(t *testing.T, file string) { 438 spec, err := LoadCollectionSpec(file) 439 if err != nil { 440 t.Fatal("Can't parse ELF:", err) 441 } 442 443 if spec.ByteOrder != internal.NativeEndian { 444 return 445 } 446 447 coll, err := NewCollectionWithOptions(spec, CollectionOptions{ 448 Programs: ProgramOptions{ 449 LogLevel: 1, 450 }, 451 }) 452 testutils.SkipIfNotSupported(t, err) 453 if err != nil { 454 t.Fatal("Can't create collection:", err) 455 } 456 457 coll.Close() 458 }) 459 } 460 461 func TestTailCall(t *testing.T) { 462 testutils.Files(t, testutils.Glob(t, "testdata/btf_map_init-*.elf"), func(t *testing.T, file string) { 463 spec, err := LoadCollectionSpec(file) 464 if err != nil { 465 t.Fatal(err) 466 } 467 468 if spec.ByteOrder != internal.NativeEndian { 469 return 470 } 471 472 var obj struct { 473 TailMain *Program `ebpf:"tail_main"` 474 ProgArray *Map `ebpf:"prog_array_init"` 475 } 476 477 err = spec.LoadAndAssign(&obj, nil) 478 testutils.SkipIfNotSupported(t, err) 479 if err != nil { 480 t.Fatal(err) 481 } 482 defer obj.TailMain.Close() 483 defer obj.ProgArray.Close() 484 485 ret, _, err := obj.TailMain.Test(make([]byte, 14)) 486 testutils.SkipIfNotSupported(t, err) 487 if err != nil { 488 t.Fatal(err) 489 } 490 491 // Expect the tail_1 tail call to be taken, returning value 42. 492 if ret != 42 { 493 t.Fatalf("Expected tail call to return value 42, got %d", ret) 494 } 495 }) 496 } 497 498 func TestSubprogRelocation(t *testing.T) { 499 testutils.SkipOnOldKernel(t, "5.13", "bpf_for_each_map_elem") 500 501 testutils.Files(t, testutils.Glob(t, "testdata/subprog_reloc-*.elf"), func(t *testing.T, file string) { 502 spec, err := LoadCollectionSpec(file) 503 if err != nil { 504 t.Fatal(err) 505 } 506 507 if spec.ByteOrder != internal.NativeEndian { 508 return 509 } 510 511 var obj struct { 512 Main *Program `ebpf:"fp_relocation"` 513 HashMap *Map `ebpf:"hash_map"` 514 } 515 516 err = spec.LoadAndAssign(&obj, nil) 517 testutils.SkipIfNotSupported(t, err) 518 if err != nil { 519 t.Fatal(err) 520 } 521 defer obj.Main.Close() 522 defer obj.HashMap.Close() 523 524 ret, _, err := obj.Main.Test(make([]byte, 14)) 525 testutils.SkipIfNotSupported(t, err) 526 if err != nil { 527 t.Fatal(err) 528 } 529 530 if ret != 42 { 531 t.Fatalf("Expected subprog reloc to return value 42, got %d", ret) 532 } 533 }) 534 } 535 536 func TestUnassignedProgArray(t *testing.T) { 537 testutils.Files(t, testutils.Glob(t, "testdata/btf_map_init-*.elf"), func(t *testing.T, file string) { 538 spec, err := LoadCollectionSpec(file) 539 if err != nil { 540 t.Fatal(err) 541 } 542 543 if spec.ByteOrder != internal.NativeEndian { 544 return 545 } 546 547 // tail_main references a ProgArray that is not being assigned 548 // to this struct. Normally, this would clear all its entries 549 // and make any tail calls into the ProgArray result in a miss. 550 // The library needs to explicitly refuse such operations. 551 var obj struct { 552 TailMain *Program `ebpf:"tail_main"` 553 // ProgArray *Map `ebpf:"prog_array_init"` 554 } 555 556 err = spec.LoadAndAssign(&obj, nil) 557 testutils.SkipIfNotSupported(t, err) 558 if err == nil { 559 obj.TailMain.Close() 560 t.Fatal("Expecting LoadAndAssign to return error") 561 } 562 }) 563 } 564 565 func TestIPRoute2Compat(t *testing.T) { 566 testutils.Files(t, testutils.Glob(t, "testdata/iproute2_map_compat-*.elf"), func(t *testing.T, file string) { 567 spec, err := LoadCollectionSpec(file) 568 if err != nil { 569 t.Fatal("Can't parse ELF:", err) 570 } 571 572 if spec.ByteOrder != internal.NativeEndian { 573 return 574 } 575 576 ms, ok := spec.Maps["hash_map"] 577 if !ok { 578 t.Fatal("Map hash_map not found") 579 } 580 581 var id, pinning, innerID, innerIndex uint32 582 583 if ms.Extra == nil { 584 t.Fatal("missing extra bytes") 585 } 586 587 switch { 588 case binary.Read(ms.Extra, spec.ByteOrder, &id) != nil: 589 t.Fatal("missing id") 590 case binary.Read(ms.Extra, spec.ByteOrder, &pinning) != nil: 591 t.Fatal("missing pinning") 592 case binary.Read(ms.Extra, spec.ByteOrder, &innerID) != nil: 593 t.Fatal("missing inner_id") 594 case binary.Read(ms.Extra, spec.ByteOrder, &innerIndex) != nil: 595 t.Fatal("missing inner_idx") 596 } 597 598 if id != 0 || innerID != 0 || innerIndex != 0 { 599 t.Fatal("expecting id, inner_id and inner_idx to be zero") 600 } 601 602 if pinning != 2 { 603 t.Fatal("expecting pinning field to be 2 (PIN_GLOBAL_NS)") 604 } 605 606 // iproute2 (tc) pins maps in /sys/fs/bpf/tc/globals with PIN_GLOBAL_NS, 607 // which needs to be be configured in this library using MapOptions.PinPath. 608 // For the sake of the test, we use a tempdir on bpffs below. 609 ms.Pinning = PinByName 610 611 coll, err := NewCollectionWithOptions(spec, CollectionOptions{ 612 Maps: MapOptions{ 613 PinPath: testutils.TempBPFFS(t), 614 }, 615 }) 616 testutils.SkipIfNotSupported(t, err) 617 if err != nil { 618 t.Fatal("Can't create collection:", err) 619 } 620 621 coll.Close() 622 }) 623 } 624 625 var ( 626 elfPath = flag.String("elfs", os.Getenv("KERNEL_SELFTESTS"), "`Path` containing libbpf-compatible ELFs (defaults to $KERNEL_SELFTESTS)") 627 elfPattern = flag.String("elf-pattern", "*.o", "Glob `pattern` for object files that should be tested") 628 ) 629 630 func TestLibBPFCompat(t *testing.T) { 631 if *elfPath == "" { 632 // Specify the path to the directory containing the eBPF for 633 // the kernel's selftests if you want to run this test. 634 // As of 5.2 that is tools/testing/selftests/bpf/ 635 t.Skip("No path specified") 636 } 637 638 load := func(t *testing.T, spec *CollectionSpec, opts CollectionOptions, valid bool) { 639 // Disable retrying a program load with the log enabled, it leads 640 // to OOM kills. 641 opts.Programs.LogSize = -1 642 643 for name, p := range spec.Programs { 644 if p.Type != Extension { 645 continue 646 } 647 648 targetProg, targetColl := loadTargetProgram(t, name, opts) 649 defer targetColl.Close() 650 p.AttachTarget = targetProg 651 } 652 653 coll, err := NewCollectionWithOptions(spec, opts) 654 testutils.SkipIfNotSupported(t, err) 655 var errno syscall.Errno 656 if errors.As(err, &errno) { 657 // This error is most likely from a syscall and caused by us not 658 // replicating some fixups done in the selftests or the test 659 // intentionally failing. This is expected, so skip the test 660 // instead of failing. 661 t.Skip("Skipping since the kernel rejected the program:", errno) 662 } 663 if err == nil { 664 coll.Close() 665 } 666 if !valid { 667 if err == nil { 668 t.Fatal("Expected an error during load") 669 } 670 } else if err != nil { 671 t.Fatal("Error during loading:", err) 672 } 673 } 674 675 files := testutils.Glob(t, filepath.Join(*elfPath, *elfPattern), 676 // These files are only used as a source of btf. 677 "btf__core_reloc_*", 678 ) 679 680 testutils.Files(t, files, func(t *testing.T, path string) { 681 file := filepath.Base(path) 682 switch file { 683 case "test_map_in_map.o", "test_map_in_map.linked3.o", 684 "test_select_reuseport_kern.o", "test_select_reuseport_kern.linked3.o": 685 t.Skip("Skipping due to missing InnerMap in map definition") 686 case "test_core_autosize.o": 687 t.Skip("Skipping since the test generates dynamic BTF") 688 case "test_static_linked.linked3.o": 689 t.Skip("Skipping since .text contains 'subprog' twice") 690 case "linked_maps.linked3.o", "linked_funcs.linked3.o": 691 t.Skip("Skipping since weak relocations are not supported") 692 } 693 694 t.Parallel() 695 696 spec, err := LoadCollectionSpec(path) 697 testutils.SkipIfNotSupported(t, err) 698 if err != nil { 699 t.Fatalf("Can't read %s: %s", file, err) 700 } 701 702 switch file { 703 case "test_sk_assign.o": 704 // Test contains a legacy iproute2 bpf_elf_map definition. 705 for _, m := range spec.Maps { 706 if m.Extra == nil || m.Extra.Len() == 0 { 707 t.Fatalf("Expected extra bytes in map %s", m.Name) 708 } 709 m.Extra = nil 710 } 711 } 712 713 var opts CollectionOptions 714 for _, mapSpec := range spec.Maps { 715 if mapSpec.Pinning != PinNone { 716 opts.Maps.PinPath = testutils.TempBPFFS(t) 717 break 718 } 719 } 720 721 coreFiles := sourceOfBTF(t, path) 722 if len(coreFiles) == 0 { 723 // NB: test_core_reloc_kernel.o doesn't have dedicated BTF and 724 // therefore goes via this code path. 725 load(t, spec, opts, true) 726 return 727 } 728 729 for _, coreFile := range coreFiles { 730 name := filepath.Base(coreFile) 731 t.Run(name, func(t *testing.T) { 732 // Some files like btf__core_reloc_arrays___err_too_small.o 733 // trigger an error on purpose. Use the name to infer whether 734 // the test should succeed. 735 var valid bool 736 switch name { 737 case "btf__core_reloc_existence___err_wrong_arr_kind.o", 738 "btf__core_reloc_existence___err_wrong_arr_value_type.o", 739 "btf__core_reloc_existence___err_wrong_int_kind.o", 740 "btf__core_reloc_existence___err_wrong_int_sz.o", 741 "btf__core_reloc_existence___err_wrong_int_type.o", 742 "btf__core_reloc_existence___err_wrong_struct_type.o": 743 // These tests are buggy upstream, see https://lore.kernel.org/bpf/20210420111639.155580-1-lmb@cloudflare.com/ 744 valid = true 745 case "btf__core_reloc_ints___err_wrong_sz_16.o", 746 "btf__core_reloc_ints___err_wrong_sz_32.o", 747 "btf__core_reloc_ints___err_wrong_sz_64.o", 748 "btf__core_reloc_ints___err_wrong_sz_8.o", 749 "btf__core_reloc_arrays___err_wrong_val_type1.o", 750 "btf__core_reloc_arrays___err_wrong_val_type2.o": 751 // These tests are valid according to current libbpf behaviour, 752 // see commit 42765ede5c54ca915de5bfeab83be97207e46f68. 753 valid = true 754 case "btf__core_reloc_type_id___missing_targets.o", 755 "btf__core_reloc_flavors__err_wrong_name.o": 756 valid = false 757 case "btf__core_reloc_ints___err_bitfield.o": 758 // Bitfields are now valid. 759 valid = true 760 default: 761 valid = !strings.Contains(name, "___err_") 762 } 763 764 fh, err := os.Open(coreFile) 765 if err != nil { 766 t.Fatal(err) 767 } 768 defer fh.Close() 769 770 btfSpec, err := btf.LoadSpec(coreFile) 771 if err != nil { 772 t.Fatal(err) 773 } 774 775 opts := opts // copy 776 opts.Programs.KernelTypes = btfSpec 777 load(t, spec, opts, valid) 778 }) 779 } 780 }) 781 } 782 783 func loadTargetProgram(tb testing.TB, name string, opts CollectionOptions) (*Program, *Collection) { 784 file := "test_pkt_access.o" 785 program := "test_pkt_access" 786 switch name { 787 case "new_connect_v4_prog": 788 file = "connect4_prog.o" 789 program = "connect_v4_prog" 790 case "new_do_bind": 791 file = "connect4_prog.o" 792 program = "connect_v4_prog" 793 case "freplace_cls_redirect_test": 794 file = "test_cls_redirect.o" 795 program = "cls_redirect" 796 case "new_handle_kprobe": 797 file = "test_attach_probe.o" 798 program = "handle_kprobe" 799 case "test_pkt_md_access_new": 800 file = "test_pkt_md_access.o" 801 program = "test_pkt_md_access" 802 default: 803 } 804 805 spec, err := LoadCollectionSpec(filepath.Join(*elfPath, file)) 806 if err != nil { 807 tb.Fatalf("Can't read %s: %s", file, err) 808 } 809 810 coll, err := NewCollectionWithOptions(spec, opts) 811 if err != nil { 812 tb.Fatalf("Can't load target: %s", err) 813 } 814 815 return coll.Programs[program], coll 816 } 817 818 func sourceOfBTF(tb testing.TB, path string) []string { 819 const testPrefix = "test_core_reloc_" 820 const btfPrefix = "btf__core_reloc_" 821 822 dir, base := filepath.Split(path) 823 if !strings.HasPrefix(base, testPrefix) { 824 return nil 825 } 826 827 base = strings.TrimSuffix(base[len(testPrefix):], ".o") 828 switch base { 829 case "bitfields_direct", "bitfields_probed": 830 base = "bitfields" 831 } 832 833 return testutils.Glob(tb, filepath.Join(dir, btfPrefix+base+"*.o")) 834 } 835 836 func TestGetProgType(t *testing.T) { 837 type progTypeTestData struct { 838 Pt ProgramType 839 At AttachType 840 Fl uint32 841 To string 842 } 843 844 testcases := map[string]progTypeTestData{ 845 "socket/garbage": { 846 Pt: SocketFilter, 847 At: AttachNone, 848 To: "", 849 }, 850 "kprobe/func": { 851 Pt: Kprobe, 852 At: AttachNone, 853 To: "func", 854 }, 855 "xdp/foo": { 856 Pt: XDP, 857 At: AttachNone, 858 To: "", 859 }, 860 "xdp_devmap/foo": { 861 Pt: XDP, 862 At: AttachXDPDevMap, 863 To: "foo", 864 }, 865 "cgroup_skb/ingress": { 866 Pt: CGroupSKB, 867 At: AttachCGroupInetIngress, 868 To: "", 869 }, 870 "iter/bpf_map": { 871 Pt: Tracing, 872 At: AttachTraceIter, 873 To: "bpf_map", 874 }, 875 "lsm.s/file_ioctl_sleepable": { 876 Pt: LSM, 877 At: AttachLSMMac, 878 To: "file_ioctl_sleepable", 879 Fl: unix.BPF_F_SLEEPABLE, 880 }, 881 "lsm/file_ioctl": { 882 Pt: LSM, 883 At: AttachLSMMac, 884 To: "file_ioctl", 885 }, 886 "sk_skb/stream_verdict/foo": { 887 Pt: SkSKB, 888 At: AttachSkSKBStreamVerdict, 889 To: "", 890 }, 891 "sk_skb/bar": { 892 Pt: SkSKB, 893 At: AttachNone, 894 To: "", 895 }, 896 } 897 898 for section, want := range testcases { 899 pt, at, fl, to := getProgType(section) 900 901 if diff := cmp.Diff(want, progTypeTestData{Pt: pt, At: at, Fl: fl, To: to}); diff != "" { 902 t.Errorf("getProgType mismatch (-want +got):\n%s", diff) 903 } 904 } 905 }