• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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