1// Copyright (C) 2018 The Android Open Source Project 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package bpf 16 17import ( 18 "fmt" 19 "io" 20 "path/filepath" 21 "runtime" 22 "strings" 23 24 "android/soong/android" 25 "android/soong/bazel" 26 "android/soong/bazel/cquery" 27 "android/soong/cc" 28 29 "github.com/google/blueprint" 30 "github.com/google/blueprint/proptools" 31) 32 33func init() { 34 registerBpfBuildComponents(android.InitRegistrationContext) 35 pctx.Import("android/soong/cc/config") 36 pctx.StaticVariable("relPwd", cc.PwdPrefix()) 37} 38 39var ( 40 pctx = android.NewPackageContext("android/soong/bpf") 41 42 ccRule = pctx.AndroidRemoteStaticRule("ccRule", android.RemoteRuleSupports{Goma: true}, 43 blueprint.RuleParams{ 44 Depfile: "${out}.d", 45 Deps: blueprint.DepsGCC, 46 Command: "$relPwd $ccCmd --target=bpf -c $cFlags -MD -MF ${out}.d -o $out $in", 47 CommandDeps: []string{"$ccCmd"}, 48 }, 49 "ccCmd", "cFlags") 50 51 stripRule = pctx.AndroidStaticRule("stripRule", 52 blueprint.RuleParams{ 53 Command: `$stripCmd --strip-unneeded --remove-section=.rel.BTF ` + 54 `--remove-section=.rel.BTF.ext --remove-section=.BTF.ext $in -o $out`, 55 CommandDeps: []string{"$stripCmd"}, 56 }, 57 "stripCmd") 58) 59 60func registerBpfBuildComponents(ctx android.RegistrationContext) { 61 ctx.RegisterModuleType("bpf", BpfFactory) 62} 63 64var PrepareForTestWithBpf = android.FixtureRegisterWithContext(registerBpfBuildComponents) 65 66// BpfModule interface is used by the apex package to gather information from a bpf module. 67type BpfModule interface { 68 android.Module 69 70 OutputFiles(tag string) (android.Paths, error) 71 72 // Returns the sub install directory if the bpf module is included by apex. 73 SubDir() string 74} 75 76type BpfProperties struct { 77 // source paths to the files. 78 Srcs []string `android:"path"` 79 80 // additional cflags that should be used to build the bpf variant of 81 // the C/C++ module. 82 Cflags []string 83 84 // directories (relative to the root of the source tree) that will 85 // be added to the include paths using -I. 86 Include_dirs []string 87 88 // optional subdirectory under which this module is installed into. 89 Sub_dir string 90 91 // if set to true, generate BTF debug info for maps & programs. 92 Btf *bool 93 94 Vendor *bool 95 96 VendorInternal bool `blueprint:"mutated"` 97} 98 99type bpf struct { 100 android.ModuleBase 101 android.BazelModuleBase 102 103 properties BpfProperties 104 105 objs android.Paths 106} 107 108var _ android.ImageInterface = (*bpf)(nil) 109 110func (bpf *bpf) ImageMutatorBegin(ctx android.BaseModuleContext) {} 111 112func (bpf *bpf) CoreVariantNeeded(ctx android.BaseModuleContext) bool { 113 return !proptools.Bool(bpf.properties.Vendor) 114} 115 116func (bpf *bpf) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool { 117 return false 118} 119 120func (bpf *bpf) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { 121 return false 122} 123 124func (bpf *bpf) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { 125 return false 126} 127 128func (bpf *bpf) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool { 129 return false 130} 131 132func (bpf *bpf) ExtraImageVariations(ctx android.BaseModuleContext) []string { 133 if proptools.Bool(bpf.properties.Vendor) { 134 return []string{"vendor"} 135 } 136 return nil 137} 138 139func (bpf *bpf) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) { 140 bpf.properties.VendorInternal = variation == "vendor" 141} 142 143func (bpf *bpf) GenerateAndroidBuildActions(ctx android.ModuleContext) { 144 cflags := []string{ 145 "-nostdlibinc", 146 147 // Make paths in deps files relative 148 "-no-canonical-prefixes", 149 150 "-O2", 151 "-isystem bionic/libc/include", 152 "-isystem bionic/libc/kernel/uapi", 153 // The architecture doesn't matter here, but asm/types.h is included by linux/types.h. 154 "-isystem bionic/libc/kernel/uapi/asm-arm64", 155 "-isystem bionic/libc/kernel/android/uapi", 156 "-I frameworks/libs/net/common/native/bpf_headers/include/bpf", 157 // TODO(b/149785767): only give access to specific file with AID_* constants 158 "-I system/core/libcutils/include", 159 "-I " + ctx.ModuleDir(), 160 } 161 162 for _, dir := range android.PathsForSource(ctx, bpf.properties.Include_dirs) { 163 cflags = append(cflags, "-I "+dir.String()) 164 } 165 166 cflags = append(cflags, bpf.properties.Cflags...) 167 168 if proptools.Bool(bpf.properties.Btf) { 169 cflags = append(cflags, "-g") 170 if runtime.GOOS != "darwin" { 171 cflags = append(cflags, "-fdebug-prefix-map=/proc/self/cwd=") 172 } 173 } 174 175 srcs := android.PathsForModuleSrc(ctx, bpf.properties.Srcs) 176 177 for _, src := range srcs { 178 if strings.ContainsRune(filepath.Base(src.String()), '_') { 179 ctx.ModuleErrorf("invalid character '_' in source name") 180 } 181 obj := android.ObjPathWithExt(ctx, "unstripped", src, "o") 182 183 ctx.Build(pctx, android.BuildParams{ 184 Rule: ccRule, 185 Input: src, 186 Output: obj, 187 Args: map[string]string{ 188 "cFlags": strings.Join(cflags, " "), 189 "ccCmd": "${config.ClangBin}/clang", 190 }, 191 }) 192 193 if proptools.Bool(bpf.properties.Btf) { 194 objStripped := android.ObjPathWithExt(ctx, "", src, "o") 195 ctx.Build(pctx, android.BuildParams{ 196 Rule: stripRule, 197 Input: obj, 198 Output: objStripped, 199 Args: map[string]string{ 200 "stripCmd": "${config.ClangBin}/llvm-strip", 201 }, 202 }) 203 bpf.objs = append(bpf.objs, objStripped.WithoutRel()) 204 } else { 205 bpf.objs = append(bpf.objs, obj.WithoutRel()) 206 } 207 208 } 209} 210 211func (bpf *bpf) AndroidMk() android.AndroidMkData { 212 return android.AndroidMkData{ 213 Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) { 214 var names []string 215 fmt.Fprintln(w) 216 fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir) 217 fmt.Fprintln(w) 218 var localModulePath string 219 if bpf.properties.VendorInternal { 220 localModulePath = "LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_ETC)/bpf" 221 } else { 222 localModulePath = "LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/bpf" 223 } 224 if len(bpf.properties.Sub_dir) > 0 { 225 localModulePath += "/" + bpf.properties.Sub_dir 226 } 227 for _, obj := range bpf.objs { 228 objName := name + "_" + obj.Base() 229 names = append(names, objName) 230 fmt.Fprintln(w, "include $(CLEAR_VARS)", " # bpf.bpf.obj") 231 fmt.Fprintln(w, "LOCAL_MODULE := ", objName) 232 data.Entries.WriteLicenseVariables(w) 233 fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", obj.String()) 234 fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", obj.Base()) 235 fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC") 236 fmt.Fprintln(w, localModulePath) 237 fmt.Fprintln(w, "include $(BUILD_PREBUILT)") 238 fmt.Fprintln(w) 239 } 240 fmt.Fprintln(w, "include $(CLEAR_VARS)", " # bpf.bpf") 241 fmt.Fprintln(w, "LOCAL_MODULE := ", name) 242 data.Entries.WriteLicenseVariables(w) 243 android.AndroidMkEmitAssignList(w, "LOCAL_REQUIRED_MODULES", names) 244 fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)") 245 }, 246 } 247} 248 249var _ android.MixedBuildBuildable = (*bpf)(nil) 250 251func (bpf *bpf) IsMixedBuildSupported(ctx android.BaseModuleContext) bool { 252 return true 253} 254 255func (bpf *bpf) QueueBazelCall(ctx android.BaseModuleContext) { 256 bazelCtx := ctx.Config().BazelContext 257 bazelCtx.QueueBazelRequest( 258 bpf.GetBazelLabel(ctx, bpf), 259 cquery.GetOutputFiles, 260 android.GetConfigKey(ctx)) 261} 262 263func (bpf *bpf) ProcessBazelQueryResponse(ctx android.ModuleContext) { 264 bazelCtx := ctx.Config().BazelContext 265 objPaths, err := bazelCtx.GetOutputFiles(bpf.GetBazelLabel(ctx, bpf), android.GetConfigKey(ctx)) 266 if err != nil { 267 ctx.ModuleErrorf(err.Error()) 268 return 269 } 270 271 bazelOuts := android.Paths{} 272 for _, p := range objPaths { 273 bazelOuts = append(bazelOuts, android.PathForBazelOut(ctx, p)) 274 } 275 bpf.objs = bazelOuts 276} 277 278// Implements OutputFileFileProducer interface so that the obj output can be used in the data property 279// of other modules. 280func (bpf *bpf) OutputFiles(tag string) (android.Paths, error) { 281 switch tag { 282 case "": 283 return bpf.objs, nil 284 default: 285 return nil, fmt.Errorf("unsupported module reference tag %q", tag) 286 } 287} 288 289func (bpf *bpf) SubDir() string { 290 return bpf.properties.Sub_dir 291} 292 293var _ android.OutputFileProducer = (*bpf)(nil) 294 295func BpfFactory() android.Module { 296 module := &bpf{} 297 298 module.AddProperties(&module.properties) 299 300 android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) 301 android.InitBazelModule(module) 302 return module 303} 304 305type bazelBpfAttributes struct { 306 Srcs bazel.LabelListAttribute 307 Copts bazel.StringListAttribute 308 Absolute_includes bazel.StringListAttribute 309 Btf *bool 310 // TODO(b/249528391): Add support for sub_dir 311} 312 313// bpf bp2build converter 314func (b *bpf) ConvertWithBp2build(ctx android.TopDownMutatorContext) { 315 if ctx.ModuleType() != "bpf" { 316 return 317 } 318 319 srcs := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, b.properties.Srcs)) 320 copts := bazel.MakeStringListAttribute(b.properties.Cflags) 321 absolute_includes := bazel.MakeStringListAttribute(b.properties.Include_dirs) 322 btf := b.properties.Btf 323 324 attrs := bazelBpfAttributes{ 325 Srcs: srcs, 326 Copts: copts, 327 Absolute_includes: absolute_includes, 328 Btf: btf, 329 } 330 props := bazel.BazelTargetModuleProperties{ 331 Rule_class: "bpf", 332 Bzl_load_location: "//build/bazel/rules/bpf:bpf.bzl", 333 } 334 335 ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: b.Name()}, &attrs) 336} 337