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