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	"strings"
21
22	"android/soong/android"
23	_ "android/soong/cc/config"
24
25	"github.com/google/blueprint"
26)
27
28func init() {
29	registerBpfBuildComponents(android.InitRegistrationContext)
30	pctx.Import("android/soong/cc/config")
31}
32
33var (
34	pctx = android.NewPackageContext("android/soong/bpf")
35
36	ccRule = pctx.AndroidRemoteStaticRule("ccRule", android.RemoteRuleSupports{Goma: true},
37		blueprint.RuleParams{
38			Depfile:     "${out}.d",
39			Deps:        blueprint.DepsGCC,
40			Command:     "$ccCmd --target=bpf -c $cFlags -MD -MF ${out}.d -o $out $in",
41			CommandDeps: []string{"$ccCmd"},
42		},
43		"ccCmd", "cFlags")
44)
45
46func registerBpfBuildComponents(ctx android.RegistrationContext) {
47	ctx.RegisterModuleType("bpf", BpfFactory)
48}
49
50var PrepareForTestWithBpf = android.FixtureRegisterWithContext(registerBpfBuildComponents)
51
52// BpfModule interface is used by the apex package to gather information from a bpf module.
53type BpfModule interface {
54	android.Module
55
56	OutputFiles(tag string) (android.Paths, error)
57}
58
59type BpfProperties struct {
60	Srcs         []string `android:"path"`
61	Cflags       []string
62	Include_dirs []string
63}
64
65type bpf struct {
66	android.ModuleBase
67
68	properties BpfProperties
69
70	objs android.Paths
71}
72
73func (bpf *bpf) GenerateAndroidBuildActions(ctx android.ModuleContext) {
74	cflags := []string{
75		"-nostdlibinc",
76
77		// Make paths in deps files relative
78		"-no-canonical-prefixes",
79
80		"-O2",
81		"-isystem bionic/libc/include",
82		"-isystem bionic/libc/kernel/uapi",
83		// The architecture doesn't matter here, but asm/types.h is included by linux/types.h.
84		"-isystem bionic/libc/kernel/uapi/asm-arm64",
85		"-isystem bionic/libc/kernel/android/uapi",
86		// TODO(b/149785767): only give access to specific file with AID_* constants
87		"-I       system/core/libcutils/include",
88		"-I       system/bpf/progs/include",
89		"-I " + ctx.ModuleDir(),
90	}
91
92	for _, dir := range android.PathsForSource(ctx, bpf.properties.Include_dirs) {
93		cflags = append(cflags, "-I "+dir.String())
94	}
95
96	cflags = append(cflags, bpf.properties.Cflags...)
97
98	srcs := android.PathsForModuleSrc(ctx, bpf.properties.Srcs)
99
100	for _, src := range srcs {
101		obj := android.ObjPathWithExt(ctx, "", src, "o")
102
103		ctx.Build(pctx, android.BuildParams{
104			Rule:   ccRule,
105			Input:  src,
106			Output: obj,
107			Args: map[string]string{
108				"cFlags": strings.Join(cflags, " "),
109				"ccCmd":  "${config.ClangBin}/clang",
110			},
111		})
112
113		bpf.objs = append(bpf.objs, obj.WithoutRel())
114	}
115}
116
117func (bpf *bpf) AndroidMk() android.AndroidMkData {
118	return android.AndroidMkData{
119		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
120			var names []string
121			fmt.Fprintln(w)
122			fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
123			fmt.Fprintln(w)
124			for _, obj := range bpf.objs {
125				objName := name + "_" + obj.Base()
126				names = append(names, objName)
127				fmt.Fprintln(w, "include $(CLEAR_VARS)")
128				fmt.Fprintln(w, "LOCAL_MODULE := ", objName)
129				data.Entries.WriteLicenseVariables(w)
130				fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", obj.String())
131				fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", obj.Base())
132				fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC")
133				fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/bpf")
134				fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
135				fmt.Fprintln(w)
136			}
137			fmt.Fprintln(w, "include $(CLEAR_VARS)")
138			fmt.Fprintln(w, "LOCAL_MODULE := ", name)
139			data.Entries.WriteLicenseVariables(w)
140			fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(names, " "))
141			fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
142		},
143	}
144}
145
146// Implements OutputFileFileProducer interface so that the obj output can be used in the data property
147// of other modules.
148func (bpf *bpf) OutputFiles(tag string) (android.Paths, error) {
149	switch tag {
150	case "":
151		return bpf.objs, nil
152	default:
153		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
154	}
155}
156
157var _ android.OutputFileProducer = (*bpf)(nil)
158
159func BpfFactory() android.Module {
160	module := &bpf{}
161
162	module.AddProperties(&module.properties)
163
164	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
165	return module
166}
167