1// Copyright 2020 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 rust 16 17import ( 18 "path/filepath" 19 "sort" 20 "strings" 21 22 "android/soong/android" 23 "android/soong/cc" 24 "android/soong/fuzz" 25 "android/soong/rust/config" 26) 27 28func init() { 29 android.RegisterModuleType("rust_fuzz", RustFuzzFactory) 30 android.RegisterSingletonType("rust_fuzz_packaging", rustFuzzPackagingFactory) 31} 32 33type fuzzDecorator struct { 34 *binaryDecorator 35 36 fuzzPackagedModule fuzz.FuzzPackagedModule 37} 38 39var _ compiler = (*fuzzDecorator)(nil) 40 41// rust_binary produces a binary that is runnable on a device. 42func RustFuzzFactory() android.Module { 43 module, _ := NewRustFuzz(android.HostAndDeviceSupported) 44 return module.Init() 45} 46 47func NewRustFuzz(hod android.HostOrDeviceSupported) (*Module, *fuzzDecorator) { 48 module, binary := NewRustBinary(hod) 49 fuzz := &fuzzDecorator{ 50 binaryDecorator: binary, 51 } 52 53 // Change the defaults for the binaryDecorator's baseCompiler 54 fuzz.binaryDecorator.baseCompiler.dir = "fuzz" 55 fuzz.binaryDecorator.baseCompiler.dir64 = "fuzz" 56 fuzz.binaryDecorator.baseCompiler.location = InstallInData 57 module.sanitize.SetSanitizer(cc.Fuzzer, true) 58 module.compiler = fuzz 59 return module, fuzz 60} 61 62func (fuzzer *fuzzDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { 63 flags = fuzzer.binaryDecorator.compilerFlags(ctx, flags) 64 65 // `../lib` for installed fuzz targets (both host and device), and `./lib` for fuzz target packages. 66 flags.LinkFlags = append(flags.LinkFlags, `-Wl,-rpath,\$$ORIGIN/../lib`) 67 flags.LinkFlags = append(flags.LinkFlags, `-Wl,-rpath,\$$ORIGIN/lib`) 68 69 return flags 70} 71 72func (fuzzer *fuzzDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps { 73 if libFuzzerRuntimeLibrary := config.LibFuzzerRuntimeLibrary(ctx.toolchain()); libFuzzerRuntimeLibrary != "" { 74 deps.StaticLibs = append(deps.StaticLibs, libFuzzerRuntimeLibrary) 75 } 76 deps.SharedLibs = append(deps.SharedLibs, "libc++") 77 deps.Rlibs = append(deps.Rlibs, "liblibfuzzer_sys") 78 79 deps = fuzzer.binaryDecorator.compilerDeps(ctx, deps) 80 81 return deps 82} 83 84func (fuzzer *fuzzDecorator) compilerProps() []interface{} { 85 return append(fuzzer.binaryDecorator.compilerProps(), 86 &fuzzer.fuzzPackagedModule.FuzzProperties) 87} 88 89func (fuzzer *fuzzDecorator) stdLinkage(ctx *depsContext) RustLinkage { 90 return RlibLinkage 91} 92 93func (fuzzer *fuzzDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep { 94 return rlibAutoDep 95} 96 97// Responsible for generating GNU Make rules that package fuzz targets into 98// their architecture & target/host specific zip file. 99type rustFuzzPackager struct { 100 fuzz.FuzzPackager 101} 102 103func rustFuzzPackagingFactory() android.Singleton { 104 return &rustFuzzPackager{} 105} 106 107func (s *rustFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { 108 // Map between each architecture + host/device combination. 109 archDirs := make(map[fuzz.ArchOs][]fuzz.FileToZip) 110 111 // List of individual fuzz targets. 112 s.FuzzTargets = make(map[string]bool) 113 114 // Map tracking whether each shared library has an install rule to avoid duplicate install rules from 115 // multiple fuzzers that depend on the same shared library. 116 sharedLibraryInstalled := make(map[string]bool) 117 118 ctx.VisitAllModules(func(module android.Module) { 119 // Discard non-fuzz targets. 120 rustModule, ok := module.(*Module) 121 if !ok { 122 return 123 } 124 125 if ok := fuzz.IsValid(rustModule.FuzzModule); !ok || rustModule.Properties.PreventInstall { 126 return 127 } 128 129 fuzzModule, ok := rustModule.compiler.(*fuzzDecorator) 130 if !ok { 131 return 132 } 133 134 hostOrTargetString := "target" 135 if rustModule.Host() { 136 hostOrTargetString = "host" 137 } 138 139 archString := rustModule.Arch().ArchType.String() 140 archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString) 141 archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()} 142 143 var files []fuzz.FileToZip 144 builder := android.NewRuleBuilder(pctx, ctx) 145 146 // Package the artifacts (data, corpus, config and dictionary into a zipfile. 147 files = s.PackageArtifacts(ctx, module, fuzzModule.fuzzPackagedModule, archDir, builder) 148 149 // The executable. 150 files = append(files, fuzz.FileToZip{rustModule.UnstrippedOutputFile(), ""}) 151 152 // Grab the list of required shared libraries. 153 sharedLibraries := fuzz.CollectAllSharedDependencies(ctx, module, cc.UnstrippedOutputFile, cc.IsValidSharedDependency) 154 155 // Package shared libraries 156 files = append(files, cc.GetSharedLibsToZip(sharedLibraries, rustModule, &s.FuzzPackager, archString, &sharedLibraryInstalled)...) 157 158 archDirs[archOs], ok = s.BuildZipFile(ctx, module, fuzzModule.fuzzPackagedModule, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs) 159 if !ok { 160 return 161 } 162 163 }) 164 s.CreateFuzzPackage(ctx, archDirs, fuzz.Rust, pctx) 165} 166 167func (s *rustFuzzPackager) MakeVars(ctx android.MakeVarsContext) { 168 packages := s.Packages.Strings() 169 sort.Strings(packages) 170 171 ctx.Strict("SOONG_RUST_FUZZ_PACKAGING_ARCH_MODULES", strings.Join(packages, " ")) 172 173 // Preallocate the slice of fuzz targets to minimize memory allocations. 174 s.PreallocateSlice(ctx, "ALL_RUST_FUZZ_TARGETS") 175} 176 177func (fuzz *fuzzDecorator) install(ctx ModuleContext) { 178 fuzz.binaryDecorator.baseCompiler.dir = filepath.Join( 179 "fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName()) 180 fuzz.binaryDecorator.baseCompiler.dir64 = filepath.Join( 181 "fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName()) 182 fuzz.binaryDecorator.baseCompiler.install(ctx) 183 184 if fuzz.fuzzPackagedModule.FuzzProperties.Corpus != nil { 185 fuzz.fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, fuzz.fuzzPackagedModule.FuzzProperties.Corpus) 186 } 187 if fuzz.fuzzPackagedModule.FuzzProperties.Data != nil { 188 fuzz.fuzzPackagedModule.Data = android.PathsForModuleSrc(ctx, fuzz.fuzzPackagedModule.FuzzProperties.Data) 189 } 190 if fuzz.fuzzPackagedModule.FuzzProperties.Dictionary != nil { 191 fuzz.fuzzPackagedModule.Dictionary = android.PathForModuleSrc(ctx, *fuzz.fuzzPackagedModule.FuzzProperties.Dictionary) 192 } 193} 194