populateStructOps translates the user struct bytes into the kernel value struct layout for a struct_ops map and writes the result back to mapSpec.Contents[0].
(m *Map, mapSpec *MapSpec)
| 621 | // populateStructOps translates the user struct bytes into the kernel value struct |
| 622 | // layout for a struct_ops map and writes the result back to mapSpec.Contents[0]. |
| 623 | func (cl *collectionLoader) populateStructOps(m *Map, mapSpec *MapSpec) error { |
| 624 | userType, ok := btf.As[*btf.Struct](mapSpec.Value) |
| 625 | if !ok { |
| 626 | return fmt.Errorf("value should be a *Struct") |
| 627 | } |
| 628 | |
| 629 | userData, err := mapSpec.dataSection() |
| 630 | if err != nil { |
| 631 | return fmt.Errorf("getting data section: %w", err) |
| 632 | } |
| 633 | if len(userData) < int(userType.Size) { |
| 634 | return fmt.Errorf("user data too short: have %d, need at least %d", len(userData), userType.Size) |
| 635 | } |
| 636 | |
| 637 | vType, _, module, err := structOpsFindTarget(userType, cl.types) |
| 638 | if err != nil { |
| 639 | return fmt.Errorf("struct_ops value type %q: %w", userType.Name, err) |
| 640 | } |
| 641 | defer module.Close() |
| 642 | |
| 643 | // Find the inner ops struct embedded in the value struct. |
| 644 | kType, kTypeOff, err := structOpsFindInnerType(vType) |
| 645 | if err != nil { |
| 646 | return err |
| 647 | } |
| 648 | |
| 649 | kernVData := make([]byte, int(vType.Size)) |
| 650 | for _, m := range userType.Members { |
| 651 | i := slices.IndexFunc(kType.Members, func(km btf.Member) bool { |
| 652 | return km.Name == m.Name |
| 653 | }) |
| 654 | |
| 655 | // Allow field to not exist in target as long as the source is zero. |
| 656 | if i == -1 { |
| 657 | mSize, err := btf.Sizeof(m.Type) |
| 658 | if err != nil { |
| 659 | return fmt.Errorf("sizeof(user.%s): %w", m.Name, err) |
| 660 | } |
| 661 | srcOff := int(m.Offset.Bytes()) |
| 662 | if srcOff < 0 || srcOff+mSize > len(userData) { |
| 663 | return fmt.Errorf("member %q: userdata is too small", m.Name) |
| 664 | } |
| 665 | |
| 666 | // let fail if the field in type user type is missing in type kern type |
| 667 | if !structOpsIsMemZeroed(userData[srcOff : srcOff+mSize]) { |
| 668 | return fmt.Errorf("%s doesn't exist in %s, but it has non-zero value", m.Name, kType.Name) |
| 669 | } |
| 670 | |
| 671 | continue |
| 672 | } |
| 673 | |
| 674 | km := kType.Members[i] |
| 675 | |
| 676 | switch btf.UnderlyingType(m.Type).(type) { |
| 677 | case *btf.Pointer: |
| 678 | // If this is a pointer → resolve struct_ops program. |
| 679 | psKey := kType.Name + ":" + m.Name |
| 680 | for k, ps := range cl.coll.Programs { |
no test coverage detected