bpf.go 9.4 KB

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