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(ctx android.ModuleContext, dependency android.ModuleProxy) 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 := android.OtherModuleProvider(ctx, dependency, LinkableInfoProvider) 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 ccInfo, hasCcInfo := android.OtherModuleProvider(ctx, dependency, CcInfoProvider) 237 if hasCcInfo && ccInfo.LibraryInfo != nil && ccInfo.LibraryInfo.BuildStubs && linkable.CcLibrary { 238 // Discard stubs libs (only CCLibrary variants). Prebuilt libraries should not 239 // be excluded on the basis of they're not CCLibrary()'s. 240 return false 241 } 242 243 // We discarded module stubs libraries above, but the LLNDK prebuilts stubs 244 // libraries must be handled differently - by looking for the stubDecorator. 245 // Discard LLNDK prebuilts stubs as well. 246 if hasCcInfo { 247 if ccInfo.LinkerInfo != nil && ccInfo.LinkerInfo.StubDecoratorInfo != nil { 248 return false 249 } 250 // Discard installable:false libraries because they are expected to be absent 251 // in runtime. 252 if !proptools.BoolDefault(linkable.Installable, true) { 253 return false 254 } 255 } 256 257 // If the same library is present both as source and a prebuilt we must pick 258 // only one to avoid a conflict. Always prefer the source since the prebuilt 259 // probably won't be built with sanitizers enabled. 260 if prebuilt, ok := android.OtherModuleProvider(ctx, dependency, android.PrebuiltModuleInfoProvider); ok && prebuilt.SourceExists { 261 return false 262 } 263 264 return true 265} 266 267func SharedLibraryInstallLocation( 268 libraryBase string, isHost bool, isVendor bool, fuzzDir string, archString string) string { 269 installLocation := "$(PRODUCT_OUT)/data" 270 if isHost { 271 installLocation = "$(HOST_OUT)" 272 } 273 subdir := "lib" 274 if isVendor { 275 subdir = "lib/vendor" 276 } 277 installLocation = filepath.Join( 278 installLocation, fuzzDir, archString, subdir, libraryBase) 279 return installLocation 280} 281 282// Get the device-only shared library symbols install directory. 283func SharedLibrarySymbolsInstallLocation(libraryBase string, isVendor bool, fuzzDir string, archString string) string { 284 subdir := "lib" 285 if isVendor { 286 subdir = "lib/vendor" 287 } 288 return filepath.Join("$(PRODUCT_OUT)/symbols/data/", fuzzDir, archString, subdir, libraryBase) 289} 290 291func (fuzzBin *fuzzBinary) install(ctx ModuleContext, file android.Path) { 292 fuzzBin.fuzzPackagedModule = PackageFuzzModule(ctx, fuzzBin.fuzzPackagedModule) 293 294 installBase := "fuzz" 295 296 // Grab the list of required shared libraries. 297 fuzzBin.sharedLibraries, _ = CollectAllSharedDependencies(ctx) 298 299 // TODO: does not mirror Android linkernamespaces 300 // the logic here has special cases for vendor, but it would need more work to 301 // work in arbitrary partitions, so just surface errors early for a few cases 302 // 303 // Even without these, there are certain situations across linkernamespaces 304 // that this won't support. For instance, you might have: 305 // 306 // my_fuzzer (vendor) -> libbinder_ndk (core) -> libbinder (vendor) 307 // 308 // This dependency chain wouldn't be possible to express in the current 309 // logic because all the deps currently match the variant of the source 310 // module. 311 312 for _, ruleBuilderInstall := range fuzzBin.sharedLibraries { 313 install := ruleBuilderInstall.To 314 fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps, 315 SharedLibraryInstallLocation( 316 install, ctx.Host(), ctx.inVendor(), installBase, ctx.Arch().ArchType.String())) 317 318 // Also add the dependency on the shared library symbols dir. 319 if !ctx.Host() { 320 fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps, 321 SharedLibrarySymbolsInstallLocation(install, ctx.inVendor(), installBase, ctx.Arch().ArchType.String())) 322 } 323 } 324 325 for _, d := range fuzzBin.fuzzPackagedModule.Corpus { 326 fuzzBin.data = append(fuzzBin.data, android.DataPath{SrcPath: d, RelativeInstallPath: "corpus", WithoutRel: true}) 327 } 328 329 for _, d := range fuzzBin.fuzzPackagedModule.Data { 330 fuzzBin.data = append(fuzzBin.data, android.DataPath{SrcPath: d, RelativeInstallPath: "data"}) 331 } 332 333 if d := fuzzBin.fuzzPackagedModule.Dictionary; d != nil { 334 fuzzBin.data = append(fuzzBin.data, android.DataPath{SrcPath: d, WithoutRel: true}) 335 } 336 337 if d := fuzzBin.fuzzPackagedModule.Config; d != nil { 338 fuzzBin.data = append(fuzzBin.data, android.DataPath{SrcPath: d, WithoutRel: true}) 339 } 340 341 fuzzBin.binaryDecorator.baseInstaller.dir = filepath.Join( 342 installBase, ctx.Target().Arch.ArchType.String(), ctx.ModuleName()) 343 fuzzBin.binaryDecorator.baseInstaller.dir64 = filepath.Join( 344 installBase, ctx.Target().Arch.ArchType.String(), ctx.ModuleName()) 345 fuzzBin.binaryDecorator.baseInstaller.installTestData(ctx, fuzzBin.data) 346 fuzzBin.binaryDecorator.baseInstaller.install(ctx, file) 347} 348 349func PackageFuzzModule(ctx android.ModuleContext, fuzzPackagedModule fuzz.FuzzPackagedModule) fuzz.FuzzPackagedModule { 350 fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Corpus) 351 fuzzPackagedModule.Corpus = append(fuzzPackagedModule.Corpus, android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Device_common_corpus)...) 352 353 fuzzPackagedModule.Data = android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Data) 354 fuzzPackagedModule.Data = append(fuzzPackagedModule.Data, android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Device_common_data)...) 355 fuzzPackagedModule.Data = append(fuzzPackagedModule.Data, android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Device_first_data)...) 356 fuzzPackagedModule.Data = append(fuzzPackagedModule.Data, android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Host_common_data)...) 357 358 if fuzzPackagedModule.FuzzProperties.Dictionary != nil { 359 fuzzPackagedModule.Dictionary = android.PathForModuleSrc(ctx, *fuzzPackagedModule.FuzzProperties.Dictionary) 360 if fuzzPackagedModule.Dictionary.Ext() != ".dict" { 361 ctx.PropertyErrorf("dictionary", 362 "Fuzzer dictionary %q does not have '.dict' extension", 363 fuzzPackagedModule.Dictionary.String()) 364 } 365 } 366 367 if fuzzPackagedModule.FuzzProperties.Fuzz_config != nil { 368 configPath := android.PathForModuleOut(ctx, "config").Join(ctx, "config.json") 369 android.WriteFileRule(ctx, configPath, fuzzPackagedModule.FuzzProperties.Fuzz_config.String()) 370 fuzzPackagedModule.Config = configPath 371 } 372 return fuzzPackagedModule 373} 374 375func NewFuzzer(hod android.HostOrDeviceSupported) *Module { 376 module, binary := newBinary(hod) 377 baseInstallerPath := "fuzz" 378 379 binary.baseInstaller = NewBaseInstaller(baseInstallerPath, baseInstallerPath, InstallInData) 380 381 fuzzBin := &fuzzBinary{ 382 binaryDecorator: binary, 383 baseCompiler: NewBaseCompiler(), 384 } 385 module.compiler = fuzzBin 386 module.linker = fuzzBin 387 module.installer = fuzzBin 388 389 module.fuzzer.Properties.FuzzFramework = fuzz.LibFuzzer 390 391 // The fuzzer runtime is not present for darwin host modules, disable cc_fuzz modules when targeting darwin. 392 android.AddLoadHook(module, func(ctx android.LoadHookContext) { 393 394 extraProps := struct { 395 Sanitize struct { 396 Fuzzer *bool 397 } 398 Target struct { 399 Darwin struct { 400 Enabled *bool 401 } 402 Linux_bionic struct { 403 Enabled *bool 404 } 405 } 406 }{} 407 extraProps.Sanitize.Fuzzer = BoolPtr(true) 408 extraProps.Target.Darwin.Enabled = BoolPtr(false) 409 extraProps.Target.Linux_bionic.Enabled = BoolPtr(false) 410 ctx.AppendProperties(&extraProps) 411 412 targetFramework := fuzz.GetFramework(ctx, fuzz.Cc) 413 if !fuzz.IsValidFrameworkForModule(targetFramework, fuzz.Cc, fuzzBin.fuzzPackagedModule.FuzzProperties.Fuzzing_frameworks) { 414 ctx.Module().Disable() 415 return 416 } 417 418 if targetFramework == fuzz.AFL { 419 fuzzBin.baseCompiler.Properties.Srcs.AppendSimpleValue([]string{":aflpp_driver", ":afl-compiler-rt"}) 420 module.fuzzer.Properties.FuzzFramework = fuzz.AFL 421 } 422 }) 423 424 return module 425} 426 427// Responsible for generating GNU Make rules that package fuzz targets into 428// their architecture & target/host specific zip file. 429type ccRustFuzzPackager struct { 430 fuzz.FuzzPackager 431 fuzzPackagingArchModules string 432 fuzzTargetSharedDepsInstallPairs string 433 allFuzzTargetsName string 434 onlyIncludePresubmits bool 435} 436 437func fuzzPackagingFactory() android.Singleton { 438 439 fuzzPackager := &ccRustFuzzPackager{ 440 fuzzPackagingArchModules: "SOONG_FUZZ_PACKAGING_ARCH_MODULES", 441 fuzzTargetSharedDepsInstallPairs: "FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS", 442 allFuzzTargetsName: "ALL_FUZZ_TARGETS", 443 onlyIncludePresubmits: false, 444 } 445 return fuzzPackager 446} 447 448func fuzzPackagingFactoryPresubmit() android.Singleton { 449 450 fuzzPackager := &ccRustFuzzPackager{ 451 fuzzPackagingArchModules: "SOONG_PRESUBMIT_FUZZ_PACKAGING_ARCH_MODULES", 452 fuzzTargetSharedDepsInstallPairs: "PRESUBMIT_FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS", 453 allFuzzTargetsName: "ALL_PRESUBMIT_FUZZ_TARGETS", 454 onlyIncludePresubmits: true, 455 } 456 return fuzzPackager 457} 458 459func (s *ccRustFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { 460 // Map between each architecture + host/device combination, and the files that 461 // need to be packaged (in the tuple of {source file, destination folder in 462 // archive}). 463 archDirs := make(map[fuzz.ArchOs][]fuzz.FileToZip) 464 465 // List of individual fuzz targets, so that 'make fuzz' also installs the targets 466 // to the correct output directories as well. 467 s.FuzzTargets = make(map[string]bool) 468 469 // Map tracking whether each shared library has an install rule to avoid duplicate install rules from 470 // multiple fuzzers that depend on the same shared library. 471 sharedLibraryInstalled := make(map[string]bool) 472 473 ctx.VisitAllModuleProxies(func(module android.ModuleProxy) { 474 ccModule, ok := android.OtherModuleProvider(ctx, module, LinkableInfoProvider) 475 if !ok { 476 return 477 } 478 // Discard non-fuzz targets. 479 fuzzInfo, ok := android.OtherModuleProvider(ctx, module, fuzz.FuzzPackagedModuleInfoProvider) 480 if !ok { 481 return 482 } 483 484 sharedLibsInstallDirPrefix := "lib" 485 if ccModule.InVendor { 486 sharedLibsInstallDirPrefix = "lib/vendor" 487 } 488 489 commonInfo := android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider) 490 isHost := commonInfo.Target.Os.Class == android.Host 491 hostOrTargetString := "target" 492 if commonInfo.Target.HostCross { 493 hostOrTargetString = "host_cross" 494 } else if isHost { 495 hostOrTargetString = "host" 496 } 497 if s.onlyIncludePresubmits == true { 498 hostOrTargetString = "presubmit-" + hostOrTargetString 499 } 500 501 intermediatePath := "fuzz" 502 503 archString := commonInfo.Target.Arch.ArchType.String() 504 archDir := android.PathForIntermediates(ctx, intermediatePath, hostOrTargetString, archString) 505 archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()} 506 507 var files []fuzz.FileToZip 508 builder := android.NewRuleBuilder(pctx, ctx) 509 510 // Package the corpus, data, dict and config into a zipfile. 511 files = s.PackageArtifacts(ctx, module, &fuzzInfo, archDir, builder) 512 513 // Package shared libraries 514 files = append(files, GetSharedLibsToZip(ccModule.FuzzSharedLibraries, isHost, ccModule.InVendor, &s.FuzzPackager, 515 archString, sharedLibsInstallDirPrefix, &sharedLibraryInstalled)...) 516 517 // The executable. 518 files = append(files, fuzz.FileToZip{SourceFilePath: android.OutputFileForModule(ctx, module, "unstripped")}) 519 520 if s.onlyIncludePresubmits == true { 521 if fuzzInfo.FuzzConfig == nil { 522 return 523 } 524 if !fuzzInfo.FuzzConfig.UseForPresubmit { 525 return 526 } 527 } 528 archDirs[archOs], ok = s.BuildZipFile(ctx, module, &fuzzInfo, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs) 529 if !ok { 530 return 531 } 532 }) 533 534 s.CreateFuzzPackage(ctx, archDirs, fuzz.Cc, pctx) 535} 536 537func (s *ccRustFuzzPackager) MakeVars(ctx android.MakeVarsContext) { 538 packages := s.Packages.Strings() 539 sort.Strings(packages) 540 sort.Strings(s.FuzzPackager.SharedLibInstallStrings) 541 // TODO(mitchp): Migrate this to use MakeVarsContext::DistForGoal() when it's 542 // ready to handle phony targets created in Soong. In the meantime, this 543 // exports the phony 'fuzz' target and dependencies on packages to 544 // core/main.mk so that we can use dist-for-goals. 545 546 ctx.Strict(s.fuzzPackagingArchModules, strings.Join(packages, " ")) 547 548 ctx.Strict(s.fuzzTargetSharedDepsInstallPairs, 549 strings.Join(s.FuzzPackager.SharedLibInstallStrings, " ")) 550 551 // Preallocate the slice of fuzz targets to minimise memory allocations. 552 s.PreallocateSlice(ctx, s.allFuzzTargetsName) 553} 554 555// GetSharedLibsToZip finds and marks all the transiently-dependent shared libraries for 556// packaging. 557func GetSharedLibsToZip(sharedLibraries android.RuleBuilderInstalls, isHost bool, inVendor bool, s *fuzz.FuzzPackager, 558 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, isHost, 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 !isHost { 594 symbolsInstallDestination := SharedLibrarySymbolsInstallLocation(install, 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.ModuleProxy) { 609 seen := make(map[string]bool) 610 recursed := make(map[string]bool) 611 deps := []android.ModuleProxy{} 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.VisitDirectDepsProxy(func(dep android.ModuleProxy) { 618 if !isValidSharedDependency(ctx, 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.WalkDepsProxy(func(child, _ android.ModuleProxy) 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_static) 640 if info, ok := android.OtherModuleProvider(ctx, child, LinkableInfoProvider); ok { 641 if info.RustLibraryInterface && !info.Shared { 642 if recursed[ctx.OtherModuleName(child)] { 643 return false 644 } 645 recursed[ctx.OtherModuleName(child)] = true 646 return true 647 } 648 } 649 650 if !isValidSharedDependency(ctx, child) { 651 return false 652 } 653 sharedLibraryInfo, hasSharedLibraryInfo := android.OtherModuleProvider(ctx, child, SharedLibraryInfoProvider) 654 if !hasSharedLibraryInfo { 655 return false 656 } 657 if !seen[ctx.OtherModuleName(child)] { 658 seen[ctx.OtherModuleName(child)] = true 659 deps = append(deps, child) 660 661 installDestination := sharedLibraryInfo.SharedLibrary.Base() 662 ruleBuilderInstall := android.RuleBuilderInstall{android.OutputFileForModule(ctx, child, "unstripped"), installDestination} 663 sharedLibraries = append(sharedLibraries, ruleBuilderInstall) 664 } 665 666 if recursed[ctx.OtherModuleName(child)] { 667 return false 668 } 669 recursed[ctx.OtherModuleName(child)] = true 670 return true 671 }) 672 673 return sharedLibraries, deps 674} 675