github.com/cilium/ebpf@v0.16.0/cmd/bpf2go/gen/target.go (about)

     1  package gen
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"go/build/constraint"
     7  	"maps"
     8  	"runtime"
     9  	"slices"
    10  )
    11  
    12  var ErrInvalidTarget = errors.New("unsupported target")
    13  
    14  var targetsByGoArch = map[GoArch]Target{
    15  	"386":      {"bpfel", "x86"},
    16  	"amd64":    {"bpfel", "x86"},
    17  	"arm":      {"bpfel", "arm"},
    18  	"arm64":    {"bpfel", "arm64"},
    19  	"loong64":  {"bpfel", "loongarch"},
    20  	"mips":     {"bpfeb", "mips"},
    21  	"mipsle":   {"bpfel", ""},
    22  	"mips64":   {"bpfeb", ""},
    23  	"mips64le": {"bpfel", ""},
    24  	"ppc64":    {"bpfeb", "powerpc"},
    25  	"ppc64le":  {"bpfel", "powerpc"},
    26  	"riscv64":  {"bpfel", "riscv"},
    27  	"s390x":    {"bpfeb", "s390"},
    28  }
    29  
    30  type Target struct {
    31  	// Clang arch string, used to define the clang -target flag, as per
    32  	// "clang -print-targets".
    33  	clang string
    34  	// Linux arch string, used to define __TARGET_ARCH_xzy macros used by
    35  	// https://github.com/libbpf/libbpf/blob/master/src/bpf_tracing.h
    36  	linux string
    37  }
    38  
    39  // TargetsByGoArch returns all supported targets.
    40  func TargetsByGoArch() map[GoArch]Target {
    41  	return maps.Clone(targetsByGoArch)
    42  }
    43  
    44  // IsGeneric returns true if the target will compile to generic BPF.
    45  func (tgt *Target) IsGeneric() bool {
    46  	return tgt.linux == ""
    47  }
    48  
    49  // Suffix returns a a string suitable for appending to a file name to
    50  // identify the target.
    51  func (tgt *Target) Suffix() string {
    52  	// The output filename must not match any of the following patterns:
    53  	//
    54  	//     *_GOOS
    55  	//     *_GOARCH
    56  	//     *_GOOS_GOARCH
    57  	//
    58  	// Otherwise it is interpreted as a build constraint by the Go toolchain.
    59  	stem := tgt.clang
    60  	if tgt.linux != "" {
    61  		stem = fmt.Sprintf("%s_%s", tgt.linux, tgt.clang)
    62  	}
    63  	return stem
    64  }
    65  
    66  // ObsoleteSuffix returns an obsolete suffix for a subset of targets.
    67  //
    68  // It's used to work around an old bug and should not be used in new code.
    69  func (tgt *Target) ObsoleteSuffix() string {
    70  	if tgt.linux == "" {
    71  		return ""
    72  	}
    73  
    74  	return fmt.Sprintf("%s_%s", tgt.clang, tgt.linux)
    75  }
    76  
    77  // GoArch is a Go arch string.
    78  //
    79  // See https://go.dev/doc/install/source#environment for valid GOARCHes when
    80  // GOOS=linux.
    81  type GoArch string
    82  
    83  type GoArches []GoArch
    84  
    85  // Constraints is satisfied when GOARCH is any of the arches.
    86  func (arches GoArches) Constraint() constraint.Expr {
    87  	var archConstraint constraint.Expr
    88  	for _, goarch := range arches {
    89  		tag := &constraint.TagExpr{Tag: string(goarch)}
    90  		archConstraint = orConstraints(archConstraint, tag)
    91  	}
    92  	return archConstraint
    93  }
    94  
    95  // FindTarget turns a list of identifiers into targets and their respective
    96  // GoArches.
    97  //
    98  // The following are valid identifiers:
    99  //
   100  //   - bpf: compile generic BPF for host endianness
   101  //   - bpfel: compile generic BPF for little endian
   102  //   - bpfeb: compile generic BPF for big endian
   103  //   - native: compile BPF for host target
   104  //   - $GOARCH: compile BPF for $GOARCH target
   105  //
   106  // Generic BPF can run on any target goarch with the correct endianness,
   107  // but doesn't have access to some arch specific tracing functionality.
   108  func FindTarget(id string) (Target, GoArches, error) {
   109  	switch id {
   110  	case "bpf", "bpfel", "bpfeb":
   111  		var goarches []GoArch
   112  		for arch, archTarget := range targetsByGoArch {
   113  			if archTarget.clang == id {
   114  				// Include tags for all goarches that have the same endianness.
   115  				goarches = append(goarches, arch)
   116  			}
   117  		}
   118  		slices.Sort(goarches)
   119  		return Target{id, ""}, goarches, nil
   120  
   121  	case "native":
   122  		id = runtime.GOARCH
   123  		fallthrough
   124  
   125  	default:
   126  		archTarget, ok := targetsByGoArch[GoArch(id)]
   127  		if !ok || archTarget.linux == "" {
   128  			return Target{}, nil, fmt.Errorf("%q: %w", id, ErrInvalidTarget)
   129  		}
   130  
   131  		var goarches []GoArch
   132  		for goarch, lt := range targetsByGoArch {
   133  			if lt == archTarget {
   134  				// Include tags for all goarches that have the same
   135  				// target.
   136  				goarches = append(goarches, goarch)
   137  			}
   138  		}
   139  
   140  		slices.Sort(goarches)
   141  		return archTarget, goarches, nil
   142  	}
   143  }
   144  
   145  func orConstraints(x, y constraint.Expr) constraint.Expr {
   146  	if x == nil {
   147  		return y
   148  	}
   149  
   150  	if y == nil {
   151  		return x
   152  	}
   153  
   154  	return &constraint.OrExpr{X: x, Y: y}
   155  }