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/cc" 26 27 "github.com/google/blueprint" 28 "github.com/google/blueprint/proptools" 29) 30 31func init() { 32 registerBpfBuildComponents(android.InitRegistrationContext) 33 pctx.Import("android/soong/cc/config") 34 pctx.StaticVariable("relPwd", cc.PwdPrefix()) 35} 36 37var ( 38 pctx = android.NewPackageContext("android/soong/bpf") 39 40 ccRule = pctx.AndroidRemoteStaticRule("ccRule", android.RemoteRuleSupports{Goma: true}, 41 blueprint.RuleParams{ 42 Depfile: "${out}.d", 43 Deps: blueprint.DepsGCC, 44 Command: "$relPwd $ccCmd --target=bpf -c $cFlags -MD -MF ${out}.d -o $out $in", 45 CommandDeps: []string{"$ccCmd"}, 46 }, 47 "ccCmd", "cFlags") 48 49 stripRule = pctx.AndroidStaticRule("stripRule", 50 blueprint.RuleParams{ 51 Command: `$stripCmd --strip-unneeded --remove-section=.rel.BTF ` + 52 `--remove-section=.rel.BTF.ext --remove-section=.BTF.ext $in -o $out`, 53 CommandDeps: []string{"$stripCmd"}, 54 }, 55 "stripCmd") 56) 57 58func registerBpfBuildComponents(ctx android.RegistrationContext) { 59 ctx.RegisterModuleType("bpf_defaults", defaultsFactory) 60 ctx.RegisterModuleType("bpf", BpfFactory) 61} 62 63type BpfInfo struct { 64 SubDir string 65} 66 67var BpfInfoProvider = blueprint.NewProvider[BpfInfo]() 68 69var PrepareForTestWithBpf = android.FixtureRegisterWithContext(registerBpfBuildComponents) 70 71// BpfModule interface is used by the apex package to gather information from a bpf module. 72type BpfModule interface { 73 android.Module 74 75 // Returns the sub install directory if the bpf module is included by apex. 76 SubDir() string 77} 78 79type BpfProperties struct { 80 // source paths to the files. 81 Srcs []string `android:"path"` 82 83 // additional cflags that should be used to build the bpf variant of 84 // the C/C++ module. 85 Cflags []string 86 87 // list of directories relative to the root of the source tree that 88 // will be added to the include paths using -I. 89 // If possible, don't use this. If adding paths from the current 90 // directory, use local_include_dirs. If adding paths from other 91 // modules, use export_include_dirs in that module. 92 Include_dirs []string 93 94 // list of directories relative to the Blueprint file that will be 95 // added to the include path using -I. 96 Local_include_dirs []string 97 // optional subdirectory under which this module is installed into. 98 Sub_dir string 99 100 // if set to true, generate BTF debug info for maps & programs. 101 Btf *bool 102 103 Vendor *bool 104 105 VendorInternal bool `blueprint:"mutated"` 106} 107 108type bpf struct { 109 android.ModuleBase 110 android.DefaultableModuleBase 111 properties BpfProperties 112 113 objs android.Paths 114} 115 116var _ android.ImageInterface = (*bpf)(nil) 117 118func (bpf *bpf) ImageMutatorBegin(ctx android.ImageInterfaceContext) {} 119 120func (bpf *bpf) VendorVariantNeeded(ctx android.ImageInterfaceContext) bool { 121 return proptools.Bool(bpf.properties.Vendor) 122} 123 124func (bpf *bpf) ProductVariantNeeded(ctx android.ImageInterfaceContext) bool { 125 return false 126} 127 128func (bpf *bpf) CoreVariantNeeded(ctx android.ImageInterfaceContext) bool { 129 return !proptools.Bool(bpf.properties.Vendor) 130} 131 132func (bpf *bpf) RamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool { 133 return false 134} 135 136func (bpf *bpf) VendorRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool { 137 return false 138} 139 140func (bpf *bpf) DebugRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool { 141 return false 142} 143 144func (bpf *bpf) RecoveryVariantNeeded(ctx android.ImageInterfaceContext) bool { 145 return false 146} 147 148func (bpf *bpf) ExtraImageVariations(ctx android.ImageInterfaceContext) []string { 149 return nil 150} 151 152func (bpf *bpf) SetImageVariation(ctx android.ImageInterfaceContext, variation string) { 153 bpf.properties.VendorInternal = variation == "vendor" 154} 155 156func (bpf *bpf) GenerateAndroidBuildActions(ctx android.ModuleContext) { 157 cflags := []string{ 158 "-nostdlibinc", 159 160 // Make paths in deps files relative 161 "-no-canonical-prefixes", 162 163 "-O2", 164 "-Wall", 165 "-Werror", 166 "-Wextra", 167 168 "-isystem bionic/libc/include", 169 "-isystem bionic/libc/kernel/uapi", 170 // The architecture doesn't matter here, but asm/types.h is included by linux/types.h. 171 "-isystem bionic/libc/kernel/uapi/asm-arm64", 172 "-isystem bionic/libc/kernel/android/uapi", 173 "-I packages/modules/Connectivity/bpf/headers/include", 174 // TODO(b/149785767): only give access to specific file with AID_* constants 175 "-I system/core/libcutils/include", 176 "-I " + ctx.ModuleDir(), 177 } 178 179 for _, dir := range android.PathsForModuleSrc(ctx, bpf.properties.Local_include_dirs) { 180 cflags = append(cflags, "-I "+dir.String()) 181 } 182 183 for _, dir := range android.PathsForSource(ctx, bpf.properties.Include_dirs) { 184 cflags = append(cflags, "-I "+dir.String()) 185 } 186 187 cflags = append(cflags, bpf.properties.Cflags...) 188 189 if proptools.BoolDefault(bpf.properties.Btf, true) { 190 cflags = append(cflags, "-g") 191 if runtime.GOOS != "darwin" { 192 cflags = append(cflags, "-fdebug-prefix-map=/proc/self/cwd=") 193 } 194 } 195 196 srcs := android.PathsForModuleSrc(ctx, bpf.properties.Srcs) 197 198 for _, src := range srcs { 199 if strings.ContainsRune(filepath.Base(src.String()), '_') { 200 ctx.ModuleErrorf("invalid character '_' in source name") 201 } 202 obj := android.ObjPathWithExt(ctx, "unstripped", src, "o") 203 204 ctx.Build(pctx, android.BuildParams{ 205 Rule: ccRule, 206 Input: src, 207 Output: obj, 208 Args: map[string]string{ 209 "cFlags": strings.Join(cflags, " "), 210 "ccCmd": "${config.ClangBin}/clang", 211 }, 212 }) 213 214 if proptools.BoolDefault(bpf.properties.Btf, true) { 215 objStripped := android.ObjPathWithExt(ctx, "", src, "o") 216 ctx.Build(pctx, android.BuildParams{ 217 Rule: stripRule, 218 Input: obj, 219 Output: objStripped, 220 Args: map[string]string{ 221 "stripCmd": "${config.ClangBin}/llvm-strip", 222 }, 223 }) 224 bpf.objs = append(bpf.objs, objStripped.WithoutRel()) 225 } else { 226 bpf.objs = append(bpf.objs, obj.WithoutRel()) 227 } 228 229 } 230 231 installDir := android.PathForModuleInstall(ctx, "etc", "bpf") 232 if len(bpf.properties.Sub_dir) > 0 { 233 installDir = installDir.Join(ctx, bpf.properties.Sub_dir) 234 } 235 for _, obj := range bpf.objs { 236 ctx.PackageFile(installDir, obj.Base(), obj) 237 } 238 239 android.SetProvider(ctx, BpfInfoProvider, BpfInfo{ 240 SubDir: bpf.SubDir(), 241 }) 242 243 ctx.SetOutputFiles(bpf.objs, "") 244} 245 246func (bpf *bpf) AndroidMk() android.AndroidMkData { 247 return android.AndroidMkData{ 248 Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) { 249 var names []string 250 fmt.Fprintln(w) 251 fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir) 252 fmt.Fprintln(w) 253 var localModulePath string 254 if bpf.properties.VendorInternal { 255 localModulePath = "LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_ETC)/bpf" 256 } else { 257 localModulePath = "LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/bpf" 258 } 259 if len(bpf.properties.Sub_dir) > 0 { 260 localModulePath += "/" + bpf.properties.Sub_dir 261 } 262 for _, obj := range bpf.objs { 263 objName := name + "_" + obj.Base() 264 names = append(names, objName) 265 fmt.Fprintln(w, "include $(CLEAR_VARS)", " # bpf.bpf.obj") 266 fmt.Fprintln(w, "LOCAL_MODULE := ", objName) 267 fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", obj.String()) 268 fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", obj.Base()) 269 fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC") 270 fmt.Fprintln(w, localModulePath) 271 // AconfigUpdateAndroidMkData may have added elements to Extra. Process them here. 272 for _, extra := range data.Extra { 273 extra(w, nil) 274 } 275 fmt.Fprintln(w, "include $(BUILD_PREBUILT)") 276 fmt.Fprintln(w) 277 } 278 fmt.Fprintln(w, "include $(CLEAR_VARS)", " # bpf.bpf") 279 fmt.Fprintln(w, "LOCAL_MODULE := ", name) 280 android.AndroidMkEmitAssignList(w, "LOCAL_REQUIRED_MODULES", names) 281 fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)") 282 }, 283 } 284} 285 286type Defaults struct { 287 android.ModuleBase 288 android.DefaultsModuleBase 289} 290 291func defaultsFactory() android.Module { 292 return DefaultsFactory() 293} 294 295func DefaultsFactory(props ...interface{}) android.Module { 296 module := &Defaults{} 297 298 module.AddProperties(props...) 299 module.AddProperties(&BpfProperties{}) 300 301 android.InitDefaultsModule(module) 302 303 return module 304} 305 306func (bpf *bpf) SubDir() string { 307 return bpf.properties.Sub_dir 308} 309 310func BpfFactory() android.Module { 311 module := &bpf{} 312 313 module.AddProperties(&module.properties) 314 315 android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) 316 android.InitDefaultableModule(module) 317 318 return module 319} 320