1// Copyright 2016 Google Inc. All rights reserved. 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 cc 16 17import ( 18 "path/filepath" 19 "sort" 20 "strings" 21 22 "github.com/google/blueprint/proptools" 23 24 "android/soong/android" 25 "android/soong/cc/config" 26 "android/soong/fuzz" 27) 28 29func init() { 30 android.RegisterModuleType("cc_fuzz", LibFuzzFactory) 31 android.RegisterParallelSingletonType("cc_fuzz_packaging", fuzzPackagingFactory) 32 android.RegisterParallelSingletonType("cc_fuzz_presubmit_packaging", fuzzPackagingFactoryPresubmit) 33} 34 35type FuzzProperties struct { 36 FuzzFramework fuzz.Framework `blueprint:"mutated"` 37} 38 39type fuzzer struct { 40 Properties FuzzProperties 41} 42 43func (fuzzer *fuzzer) flags(ctx ModuleContext, flags Flags) Flags { 44 if fuzzer.Properties.FuzzFramework == fuzz.AFL { 45 flags.Local.CFlags = append(flags.Local.CFlags, []string{ 46 "-fsanitize-coverage=trace-pc-guard", 47 "-Wno-unused-result", 48 "-Wno-unused-parameter", 49 "-Wno-unused-function", 50 }...) 51 } 52 53 return flags 54} 55 56func (fuzzer *fuzzer) props() []interface{} { 57 return []interface{}{&fuzzer.Properties} 58} 59 60// fuzzTransitionMutator creates variants to propagate the FuzzFramework value down to dependencies. 61type fuzzTransitionMutator struct{} 62 63func (f *fuzzTransitionMutator) Split(ctx android.BaseModuleContext) []string { 64 return []string{""} 65} 66 67func (f *fuzzTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { 68 m, ok := ctx.Module().(*Module) 69 if !ok { 70 return "" 71 } 72 73 if m.fuzzer == nil { 74 return "" 75 } 76 77 if m.sanitize == nil { 78 return "" 79 } 80 81 isFuzzerPointer := m.sanitize.getSanitizerBoolPtr(Fuzzer) 82 if isFuzzerPointer == nil || !*isFuzzerPointer { 83 return "" 84 } 85 86 if m.fuzzer.Properties.FuzzFramework != "" { 87 return m.fuzzer.Properties.FuzzFramework.Variant() 88 } 89 90 return sourceVariation 91} 92 93func (f *fuzzTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string { 94 m, ok := ctx.Module().(*Module) 95 if !ok { 96 return "" 97 } 98 99 if m.fuzzer == nil { 100 return "" 101 } 102 103 if m.sanitize == nil { 104 return "" 105 } 106 107 isFuzzerPointer := m.sanitize.getSanitizerBoolPtr(Fuzzer) 108 if isFuzzerPointer == nil || !*isFuzzerPointer { 109 return "" 110 } 111 112 return incomingVariation 113} 114 115func (f *fuzzTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) { 116 m, ok := ctx.Module().(*Module) 117 if !ok { 118 return 119 } 120 121 if m.fuzzer == nil { 122 return 123 } 124 125 if variation != "" { 126 m.fuzzer.Properties.FuzzFramework = fuzz.FrameworkFromVariant(variation) 127 m.SetHideFromMake() 128 m.SetPreventInstall() 129 } 130} 131 132// cc_fuzz creates a host/device fuzzer binary. Host binaries can be found at 133// $ANDROID_HOST_OUT/fuzz/, and device binaries can be found at /data/fuzz on 134// your device, or $ANDROID_PRODUCT_OUT/data/fuzz in your build tree. 135func LibFuzzFactory() android.Module { 136 module := NewFuzzer(android.HostAndDeviceSupported) 137 module.testModule = true 138 return module.Init() 139} 140 141type fuzzBinary struct { 142 *binaryDecorator 143 *baseCompiler 144 fuzzPackagedModule fuzz.FuzzPackagedModule 145 installedSharedDeps []string 146 sharedLibraries android.RuleBuilderInstalls 147 data []android.DataPath 148} 149 150func (fuzz *fuzzBinary) fuzzBinary() bool { 151 return true 152} 153 154func (fuzz *fuzzBinary) linkerProps() []interface{} { 155 props := fuzz.binaryDecorator.linkerProps() 156 props = append(props, &fuzz.fuzzPackagedModule.FuzzProperties) 157 158 return props 159} 160 161func (fuzz *fuzzBinary) linkerInit(ctx BaseModuleContext) { 162 fuzz.binaryDecorator.linkerInit(ctx) 163} 164 165func (fuzzBin *fuzzBinary) linkerDeps(ctx DepsContext, deps Deps) Deps { 166 if ctx.Config().Getenv("FUZZ_FRAMEWORK") == "AFL" { 167 deps.HeaderLibs = append(deps.HeaderLibs, "libafl_headers") 168 } else { 169 deps.StaticLibs = append(deps.StaticLibs, config.LibFuzzerRuntimeLibrary()) 170 // Fuzzers built with HWASAN should use the interceptors for better 171 // mutation based on signals in strcmp, memcpy, etc. This is only needed for 172 // fuzz targets, not generic HWASAN-ified binaries or libraries. 173 if module, ok := ctx.Module().(*Module); ok { 174 if module.IsSanitizerEnabled(Hwasan) { 175 deps.StaticLibs = append(deps.StaticLibs, config.LibFuzzerRuntimeInterceptors()) 176 } 177 } 178 } 179 180 deps = fuzzBin.binaryDecorator.linkerDeps(ctx, deps) 181 return deps 182} 183 184func (fuzz *fuzzBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags { 185 subdir := "lib" 186 if ctx.inVendor() { 187 subdir = "lib/vendor" 188 } 189 190 flags = fuzz.binaryDecorator.linkerFlags(ctx, flags) 191 // RunPaths on devices isn't instantiated by the base linker. `../lib` for 192 // installed fuzz targets (both host and device), and `./lib` for fuzz 193 // target packages. 194 flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/`+subdir) 195 196 // When running on device, fuzz targets with vendor: true set will be in 197 // fuzzer_name/vendor/fuzzer_name (note the extra 'vendor' and thus need to 198 // link with libraries in ../../lib/. Non-vendor binaries only need to look 199 // one level up, in ../lib/. 200 if ctx.inVendor() { 201 flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/../../`+subdir) 202 } else { 203 flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/../`+subdir) 204 } 205 206 return flags 207} 208 209func (fuzz *fuzzBinary) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) { 210 fuzz.binaryDecorator.moduleInfoJSON(ctx, moduleInfoJSON) 211 moduleInfoJSON.Class = []string{"EXECUTABLES"} 212} 213 214// IsValidSharedDependency takes a module and determines if it is a unique shared library 215// that should be installed in the fuzz target output directories. This function 216// returns true, unless: 217// - The module is not an installable shared library, or 218// - The module is a header or stub, or 219// - The module is a prebuilt and its source is available, or 220// - The module is a versioned member of an SDK snapshot. 221func IsValidSharedDependency(dependency android.Module) bool { 222 // TODO(b/144090547): We should be parsing these modules using 223 // ModuleDependencyTag instead of the current brute-force checking. 224 225 linkable, ok := dependency.(LinkableInterface) 226 if !ok || !linkable.CcLibraryInterface() { 227 // Discard non-linkables. 228 return false 229 } 230 231 if !linkable.Shared() { 232 // Discard static libs. 233 return false 234 } 235 236 if lib := moduleLibraryInterface(dependency); lib != nil && lib.buildStubs() && linkable.CcLibrary() { 237 // Discard stubs libs (only CCLibrary variants). Prebuilt libraries should not 238 // be excluded on the basis of they're not CCLibrary()'s. 239 return false 240 } 241 242 // We discarded module stubs libraries above, but the LLNDK prebuilts stubs 243 // libraries must be handled differently - by looking for the stubDecorator. 244 // Discard LLNDK prebuilts stubs as well. 245 if ccLibrary, isCcLibrary := dependency.(*Module); isCcLibrary { 246 if _, isLLndkStubLibrary := ccLibrary.linker.(*stubDecorator); isLLndkStubLibrary { 247 return false 248 } 249 // Discard installable:false libraries because they are expected to be absent 250 // in runtime. 251 if !proptools.BoolDefault(ccLibrary.Installable(), true) { 252 return false 253 } 254 } 255 256 // If the same library is present both as source and a prebuilt we must pick 257 // only one to avoid a conflict. Always prefer the source since the prebuilt 258 // probably won't be built with sanitizers enabled. 259 if prebuilt := android.GetEmbeddedPrebuilt(dependency); prebuilt != nil && prebuilt.SourceExists() { 260 return false 261 } 262 263 return true 264} 265 266func SharedLibraryInstallLocation( 267 libraryBase string, isHost bool, isVendor bool, fuzzDir string, archString string) string { 268 installLocation := "$(PRODUCT_OUT)/data" 269 if isHost { 270 installLocation = "$(HOST_OUT)" 271 } 272 subdir := "lib" 273 if isVendor { 274 subdir = "lib/vendor" 275 } 276 installLocation = filepath.Join( 277 installLocation, fuzzDir, archString, subdir, libraryBase) 278 return installLocation 279} 280 281// Get the device-only shared library symbols install directory. 282func SharedLibrarySymbolsInstallLocation(libraryBase string, isVendor bool, fuzzDir string, archString string) string { 283 subdir := "lib" 284 if isVendor { 285 subdir = "lib/vendor" 286 } 287 return filepath.Join("$(PRODUCT_OUT)/symbols/data/", fuzzDir, archString, subdir, libraryBase) 288} 289 290func (fuzzBin *fuzzBinary) install(ctx ModuleContext, file android.Path) { 291 fuzzBin.fuzzPackagedModule = PackageFuzzModule(ctx, fuzzBin.fuzzPackagedModule, pctx) 292 293 installBase := "fuzz" 294 295 // Grab the list of required shared libraries. 296 fuzzBin.sharedLibraries, _ = CollectAllSharedDependencies(ctx) 297 298 // TODO: does not mirror Android linkernamespaces 299 // the logic here has special cases for vendor, but it would need more work to 300 // work in arbitrary partitions, so just surface errors early for a few cases 301 // 302 // Even without these, there are certain situations across linkernamespaces 303 // that this won't support. For instance, you might have: 304 // 305 // my_fuzzer (vendor) -> libbinder_ndk (core) -> libbinder (vendor) 306 // 307 // This dependency chain wouldn't be possible to express in the current 308 // logic because all the deps currently match the variant of the source 309 // module. 310 311 for _, ruleBuilderInstall := range fuzzBin.sharedLibraries { 312 install := ruleBuilderInstall.To 313 fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps, 314 SharedLibraryInstallLocation( 315 install, ctx.Host(), ctx.inVendor(), installBase, ctx.Arch().ArchType.String())) 316 317 // Also add the dependency on the shared library symbols dir. 318 if !ctx.Host() { 319 fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps, 320 SharedLibrarySymbolsInstallLocation(install, ctx.inVendor(), installBase, ctx.Arch().ArchType.String())) 321 } 322 } 323 324 for _, d := range fuzzBin.fuzzPackagedModule.Corpus { 325 fuzzBin.data = append(fuzzBin.data, android.DataPath{SrcPath: d, RelativeInstallPath: "corpus", WithoutRel: true}) 326 } 327 328 for _, d := range fuzzBin.fuzzPackagedModule.Data { 329 fuzzBin.data = append(fuzzBin.data, android.DataPath{SrcPath: d, RelativeInstallPath: "data"}) 330 } 331 332 if d := fuzzBin.fuzzPackagedModule.Dictionary; d != nil { 333 fuzzBin.data = append(fuzzBin.data, android.DataPath{SrcPath: d, WithoutRel: true}) 334 } 335 336 if d := fuzzBin.fuzzPackagedModule.Config; d != nil { 337 fuzzBin.data = append(fuzzBin.data, android.DataPath{SrcPath: d, WithoutRel: true}) 338 } 339 340 fuzzBin.binaryDecorator.baseInstaller.dir = filepath.Join( 341 installBase, ctx.Target().Arch.ArchType.String(), ctx.ModuleName()) 342 fuzzBin.binaryDecorator.baseInstaller.dir64 = filepath.Join( 343 installBase, ctx.Target().Arch.ArchType.String(), ctx.ModuleName()) 344 fuzzBin.binaryDecorator.baseInstaller.installTestData(ctx, fuzzBin.data) 345 fuzzBin.binaryDecorator.baseInstaller.install(ctx, file) 346} 347 348func PackageFuzzModule(ctx android.ModuleContext, fuzzPackagedModule fuzz.FuzzPackagedModule, pctx android.PackageContext) fuzz.FuzzPackagedModule { 349 fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Corpus) 350 fuzzPackagedModule.Corpus = append(fuzzPackagedModule.Corpus, android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Device_common_corpus)...) 351 352 fuzzPackagedModule.Data = android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Data) 353 354 if fuzzPackagedModule.FuzzProperties.Dictionary != nil { 355 fuzzPackagedModule.Dictionary = android.PathForModuleSrc(ctx, *fuzzPackagedModule.FuzzProperties.Dictionary) 356 if fuzzPackagedModule.Dictionary.Ext() != ".dict" { 357 ctx.PropertyErrorf("dictionary", 358 "Fuzzer dictionary %q does not have '.dict' extension", 359 fuzzPackagedModule.Dictionary.String()) 360 } 361 } 362 363 if fuzzPackagedModule.FuzzProperties.Fuzz_config != nil { 364 configPath := android.PathForModuleOut(ctx, "config").Join(ctx, "config.json") 365 android.WriteFileRule(ctx, configPath, fuzzPackagedModule.FuzzProperties.Fuzz_config.String()) 366 fuzzPackagedModule.Config = configPath 367 } 368 return fuzzPackagedModule 369} 370 371func NewFuzzer(hod android.HostOrDeviceSupported) *Module { 372 module, binary := newBinary(hod) 373 baseInstallerPath := "fuzz" 374 375 binary.baseInstaller = NewBaseInstaller(baseInstallerPath, baseInstallerPath, InstallInData) 376 377 fuzzBin := &fuzzBinary{ 378 binaryDecorator: binary, 379 baseCompiler: NewBaseCompiler(), 380 } 381 module.compiler = fuzzBin 382 module.linker = fuzzBin 383 module.installer = fuzzBin 384 385 module.fuzzer.Properties.FuzzFramework = fuzz.LibFuzzer 386 387 // The fuzzer runtime is not present for darwin host modules, disable cc_fuzz modules when targeting darwin. 388 android.AddLoadHook(module, func(ctx android.LoadHookContext) { 389 390 extraProps := struct { 391 Sanitize struct { 392 Fuzzer *bool 393 } 394 Target struct { 395 Darwin struct { 396 Enabled *bool 397 } 398 Linux_bionic struct { 399 Enabled *bool 400 } 401 } 402 }{} 403 extraProps.Sanitize.Fuzzer = BoolPtr(true) 404 extraProps.Target.Darwin.Enabled = BoolPtr(false) 405 extraProps.Target.Linux_bionic.Enabled = BoolPtr(false) 406 ctx.AppendProperties(&extraProps) 407 408 targetFramework := fuzz.GetFramework(ctx, fuzz.Cc) 409 if !fuzz.IsValidFrameworkForModule(targetFramework, fuzz.Cc, fuzzBin.fuzzPackagedModule.FuzzProperties.Fuzzing_frameworks) { 410 ctx.Module().Disable() 411 return 412 } 413 414 if targetFramework == fuzz.AFL { 415 fuzzBin.baseCompiler.Properties.Srcs.AppendSimpleValue([]string{":aflpp_driver", ":afl-compiler-rt"}) 416 module.fuzzer.Properties.FuzzFramework = fuzz.AFL 417 } 418 }) 419 420 return module 421} 422 423// Responsible for generating GNU Make rules that package fuzz targets into 424// their architecture & target/host specific zip file. 425type ccRustFuzzPackager struct { 426 fuzz.FuzzPackager 427 fuzzPackagingArchModules string 428 fuzzTargetSharedDepsInstallPairs string 429 allFuzzTargetsName string 430 onlyIncludePresubmits bool 431} 432 433func fuzzPackagingFactory() android.Singleton { 434 435 fuzzPackager := &ccRustFuzzPackager{ 436 fuzzPackagingArchModules: "SOONG_FUZZ_PACKAGING_ARCH_MODULES", 437 fuzzTargetSharedDepsInstallPairs: "FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS", 438 allFuzzTargetsName: "ALL_FUZZ_TARGETS", 439 onlyIncludePresubmits: false, 440 } 441 return fuzzPackager 442} 443 444func fuzzPackagingFactoryPresubmit() android.Singleton { 445 446 fuzzPackager := &ccRustFuzzPackager{ 447 fuzzPackagingArchModules: "SOONG_PRESUBMIT_FUZZ_PACKAGING_ARCH_MODULES", 448 fuzzTargetSharedDepsInstallPairs: "PRESUBMIT_FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS", 449 allFuzzTargetsName: "ALL_PRESUBMIT_FUZZ_TARGETS", 450 onlyIncludePresubmits: true, 451 } 452 return fuzzPackager 453} 454 455func (s *ccRustFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { 456 // Map between each architecture + host/device combination, and the files that 457 // need to be packaged (in the tuple of {source file, destination folder in 458 // archive}). 459 archDirs := make(map[fuzz.ArchOs][]fuzz.FileToZip) 460 461 // List of individual fuzz targets, so that 'make fuzz' also installs the targets 462 // to the correct output directories as well. 463 s.FuzzTargets = make(map[string]bool) 464 465 // Map tracking whether each shared library has an install rule to avoid duplicate install rules from 466 // multiple fuzzers that depend on the same shared library. 467 sharedLibraryInstalled := make(map[string]bool) 468 469 ctx.VisitAllModules(func(module android.Module) { 470 ccModule, ok := module.(LinkableInterface) 471 if !ok || ccModule.PreventInstall() { 472 return 473 } 474 // Discard non-fuzz targets. 475 if ok := fuzz.IsValid(ctx, ccModule.FuzzModuleStruct()); !ok { 476 return 477 } 478 479 sharedLibsInstallDirPrefix := "lib" 480 if ccModule.InVendor() { 481 sharedLibsInstallDirPrefix = "lib/vendor" 482 } 483 484 if !ccModule.IsFuzzModule() { 485 return 486 } 487 488 hostOrTargetString := "target" 489 if ccModule.Target().HostCross { 490 hostOrTargetString = "host_cross" 491 } else if ccModule.Host() { 492 hostOrTargetString = "host" 493 } 494 if s.onlyIncludePresubmits == true { 495 hostOrTargetString = "presubmit-" + hostOrTargetString 496 } 497 498 fpm := fuzz.FuzzPackagedModule{} 499 if ok { 500 fpm = ccModule.FuzzPackagedModule() 501 } 502 503 intermediatePath := "fuzz" 504 505 archString := ccModule.Target().Arch.ArchType.String() 506 archDir := android.PathForIntermediates(ctx, intermediatePath, hostOrTargetString, archString) 507 archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()} 508 509 var files []fuzz.FileToZip 510 builder := android.NewRuleBuilder(pctx, ctx) 511 512 // Package the corpus, data, dict and config into a zipfile. 513 files = s.PackageArtifacts(ctx, module, fpm, archDir, builder) 514 515 // Package shared libraries 516 files = append(files, GetSharedLibsToZip(ccModule.FuzzSharedLibraries(), ccModule, &s.FuzzPackager, archString, sharedLibsInstallDirPrefix, &sharedLibraryInstalled)...) 517 518 // The executable. 519 files = append(files, fuzz.FileToZip{SourceFilePath: android.OutputFileForModule(ctx, ccModule, "unstripped")}) 520 521 if s.onlyIncludePresubmits == true { 522 if fpm.FuzzProperties.Fuzz_config == nil { 523 return 524 } 525 if !BoolDefault(fpm.FuzzProperties.Fuzz_config.Use_for_presubmit, false) { 526 return 527 } 528 } 529 archDirs[archOs], ok = s.BuildZipFile(ctx, module, fpm, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs) 530 if !ok { 531 return 532 } 533 }) 534 535 s.CreateFuzzPackage(ctx, archDirs, fuzz.Cc, pctx) 536} 537 538func (s *ccRustFuzzPackager) MakeVars(ctx android.MakeVarsContext) { 539 packages := s.Packages.Strings() 540 sort.Strings(packages) 541 sort.Strings(s.FuzzPackager.SharedLibInstallStrings) 542 // TODO(mitchp): Migrate this to use MakeVarsContext::DistForGoal() when it's 543 // ready to handle phony targets created in Soong. In the meantime, this 544 // exports the phony 'fuzz' target and dependencies on packages to 545 // core/main.mk so that we can use dist-for-goals. 546 547 ctx.Strict(s.fuzzPackagingArchModules, strings.Join(packages, " ")) 548 549 ctx.Strict(s.fuzzTargetSharedDepsInstallPairs, 550 strings.Join(s.FuzzPackager.SharedLibInstallStrings, " ")) 551 552 // Preallocate the slice of fuzz targets to minimise memory allocations. 553 s.PreallocateSlice(ctx, s.allFuzzTargetsName) 554} 555 556// GetSharedLibsToZip finds and marks all the transiently-dependent shared libraries for 557// packaging. 558func GetSharedLibsToZip(sharedLibraries android.RuleBuilderInstalls, module LinkableInterface, s *fuzz.FuzzPackager, archString string, destinationPathPrefix string, sharedLibraryInstalled *map[string]bool) []fuzz.FileToZip { 559 var files []fuzz.FileToZip 560 561 fuzzDir := "fuzz" 562 563 for _, ruleBuilderInstall := range sharedLibraries { 564 library := ruleBuilderInstall.From 565 install := ruleBuilderInstall.To 566 files = append(files, fuzz.FileToZip{ 567 SourceFilePath: library, 568 DestinationPathPrefix: destinationPathPrefix, 569 DestinationPath: install, 570 }) 571 572 // For each architecture-specific shared library dependency, we need to 573 // install it to the output directory. Setup the install destination here, 574 // which will be used by $(copy-many-files) in the Make backend. 575 installDestination := SharedLibraryInstallLocation( 576 install, module.Host(), module.InVendor(), fuzzDir, archString) 577 if (*sharedLibraryInstalled)[installDestination] { 578 continue 579 } 580 (*sharedLibraryInstalled)[installDestination] = true 581 582 // Escape all the variables, as the install destination here will be called 583 // via. $(eval) in Make. 584 installDestination = strings.ReplaceAll( 585 installDestination, "$", "$$") 586 s.SharedLibInstallStrings = append(s.SharedLibInstallStrings, 587 library.String()+":"+installDestination) 588 589 // Ensure that on device, the library is also reinstalled to the /symbols/ 590 // dir. Symbolized DSO's are always installed to the device when fuzzing, but 591 // we want symbolization tools (like `stack`) to be able to find the symbols 592 // in $ANDROID_PRODUCT_OUT/symbols automagically. 593 if !module.Host() { 594 symbolsInstallDestination := SharedLibrarySymbolsInstallLocation(install, module.InVendor(), fuzzDir, archString) 595 symbolsInstallDestination = strings.ReplaceAll(symbolsInstallDestination, "$", "$$") 596 s.SharedLibInstallStrings = append(s.SharedLibInstallStrings, 597 library.String()+":"+symbolsInstallDestination) 598 } 599 } 600 return files 601} 602 603// CollectAllSharedDependencies search over the provided module's dependencies using 604// VisitDirectDeps and WalkDeps to enumerate all shared library dependencies. 605// VisitDirectDeps is used first to avoid incorrectly using the core libraries (sanitizer 606// runtimes, libc, libdl, etc.) from a dependency. This may cause issues when dependencies 607// have explicit sanitizer tags, as we may get a dependency on an unsanitized libc, etc. 608func CollectAllSharedDependencies(ctx android.ModuleContext) (android.RuleBuilderInstalls, []android.Module) { 609 seen := make(map[string]bool) 610 recursed := make(map[string]bool) 611 deps := []android.Module{} 612 613 var sharedLibraries android.RuleBuilderInstalls 614 615 // Enumerate the first level of dependencies, as we discard all non-library 616 // modules in the BFS loop below. 617 ctx.VisitDirectDeps(func(dep android.Module) { 618 if !IsValidSharedDependency(dep) { 619 return 620 } 621 sharedLibraryInfo, hasSharedLibraryInfo := android.OtherModuleProvider(ctx, dep, SharedLibraryInfoProvider) 622 if !hasSharedLibraryInfo { 623 return 624 } 625 if seen[ctx.OtherModuleName(dep)] { 626 return 627 } 628 seen[ctx.OtherModuleName(dep)] = true 629 deps = append(deps, dep) 630 631 installDestination := sharedLibraryInfo.SharedLibrary.Base() 632 ruleBuilderInstall := android.RuleBuilderInstall{android.OutputFileForModule(ctx, dep, "unstripped"), installDestination} 633 sharedLibraries = append(sharedLibraries, ruleBuilderInstall) 634 }) 635 636 ctx.WalkDeps(func(child, parent android.Module) bool { 637 638 // If this is a Rust module which is not rust_ffi_shared, we still want to bundle any transitive 639 // shared dependencies (even for rust_ffi_rlib or rust_ffi_static) 640 if rustmod, ok := child.(LinkableInterface); ok && rustmod.RustLibraryInterface() && !rustmod.Shared() { 641 if recursed[ctx.OtherModuleName(child)] { 642 return false 643 } 644 recursed[ctx.OtherModuleName(child)] = true 645 return true 646 } 647 648 if !IsValidSharedDependency(child) { 649 return false 650 } 651 sharedLibraryInfo, hasSharedLibraryInfo := android.OtherModuleProvider(ctx, child, SharedLibraryInfoProvider) 652 if !hasSharedLibraryInfo { 653 return false 654 } 655 if !seen[ctx.OtherModuleName(child)] { 656 seen[ctx.OtherModuleName(child)] = true 657 deps = append(deps, child) 658 659 installDestination := sharedLibraryInfo.SharedLibrary.Base() 660 ruleBuilderInstall := android.RuleBuilderInstall{android.OutputFileForModule(ctx, child, "unstripped"), installDestination} 661 sharedLibraries = append(sharedLibraries, ruleBuilderInstall) 662 } 663 664 if recursed[ctx.OtherModuleName(child)] { 665 return false 666 } 667 recursed[ctx.OtherModuleName(child)] = true 668 return true 669 }) 670 671 return sharedLibraries, deps 672} 673