blob: aa9038ae273c6fe75210b3b21fc7f08c915570e0 [file] [log] [blame]
Mitch Phillipsda9a4632019-07-15 09:34:09 -07001// 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 (
Kris Alderf979ee32019-10-22 10:52:01 -070018 "encoding/json"
Mitch Phillips4de896e2019-08-28 16:04:36 -070019 "path/filepath"
Mitch Phillipse1ee1a12019-10-17 19:20:41 -070020 "sort"
Mitch Phillipsa0a5e192019-09-27 14:00:06 -070021 "strings"
Mitch Phillips4de896e2019-08-28 16:04:36 -070022
Mitch Phillipsda9a4632019-07-15 09:34:09 -070023 "android/soong/android"
24 "android/soong/cc/config"
25)
26
Kris Alderf979ee32019-10-22 10:52:01 -070027type FuzzConfig struct {
28 // Email address of people to CC on bugs or contact about this fuzz target.
29 Cc []string `json:"cc,omitempty"`
hamzeh3478a0d2019-12-16 16:25:50 -080030 // Specify whether to enable continuous fuzzing on devices. Defaults to true.
31 Fuzz_on_haiku_device *bool `json:"fuzz_on_haiku_device,omitempty"`
32 // Specify whether to enable continuous fuzzing on host. Defaults to true.
33 Fuzz_on_haiku_host *bool `json:"fuzz_on_haiku_host,omitempty"`
Kris Alderf979ee32019-10-22 10:52:01 -070034 // Component in Google's bug tracking system that bugs should be filed to.
35 Componentid *int64 `json:"componentid,omitempty"`
36 // Hotlists in Google's bug tracking system that bugs should be marked with.
37 Hotlists []string `json:"hotlists,omitempty"`
Kris Aldere051d0d2020-04-28 18:32:23 +000038 // Specify whether this fuzz target was submitted by a researcher. Defaults
39 // to false.
40 Researcher_submitted *bool `json:"researcher_submitted,omitempty"`
Kris Alder2598c9b2020-09-29 22:09:36 +000041 // Specify who should be acknowledged for CVEs in the Android Security
42 // Bulletin.
43 Acknowledgement []string `json:"acknowledgement,omitempty"`
Kris Alderc81f59f2021-01-07 20:57:23 +000044 // Additional options to be passed to libfuzzer when run in Haiku.
45 Libfuzzer_options []string `json:"libfuzzer_options,omitempty"`
46 // Additional options to be passed to HWASAN when running on-device in Haiku.
47 Hwasan_options []string `json:"hwasan_options,omitempty"`
48 // Additional options to be passed to HWASAN when running on host in Haiku.
49 Asan_options []string `json:"asan_options,omitempty"`
Kris Alderf979ee32019-10-22 10:52:01 -070050}
51
52func (f *FuzzConfig) String() string {
53 b, err := json.Marshal(f)
54 if err != nil {
55 panic(err)
56 }
57
58 return string(b)
59}
60
Mitch Phillips4e4ab8a2019-09-13 17:32:50 -070061type FuzzProperties struct {
62 // Optional list of seed files to be installed to the fuzz target's output
63 // directory.
64 Corpus []string `android:"path"`
Tri Voad172d82019-11-27 13:45:45 -080065 // Optional list of data files to be installed to the fuzz target's output
66 // directory. Directory structure relative to the module is preserved.
67 Data []string `android:"path"`
Mitch Phillips4e4ab8a2019-09-13 17:32:50 -070068 // Optional dictionary to be installed to the fuzz target's output directory.
69 Dictionary *string `android:"path"`
Kris Alderf979ee32019-10-22 10:52:01 -070070 // Config for running the target on fuzzing infrastructure.
71 Fuzz_config *FuzzConfig
Mitch Phillips4e4ab8a2019-09-13 17:32:50 -070072}
73
Mitch Phillipsda9a4632019-07-15 09:34:09 -070074func init() {
75 android.RegisterModuleType("cc_fuzz", FuzzFactory)
Mitch Phillipsd3254b42019-09-24 13:03:28 -070076 android.RegisterSingletonType("cc_fuzz_packaging", fuzzPackagingFactory)
Mitch Phillipsda9a4632019-07-15 09:34:09 -070077}
78
79// cc_fuzz creates a host/device fuzzer binary. Host binaries can be found at
80// $ANDROID_HOST_OUT/fuzz/, and device binaries can be found at /data/fuzz on
81// your device, or $ANDROID_PRODUCT_OUT/data/fuzz in your build tree.
82func FuzzFactory() android.Module {
83 module := NewFuzz(android.HostAndDeviceSupported)
84 return module.Init()
85}
86
87func NewFuzzInstaller() *baseInstaller {
88 return NewBaseInstaller("fuzz", "fuzz", InstallInData)
89}
90
91type fuzzBinary struct {
92 *binaryDecorator
93 *baseCompiler
Mitch Phillips4e4ab8a2019-09-13 17:32:50 -070094
Mitch Phillips8a2bc0b2019-10-17 15:04:01 -070095 Properties FuzzProperties
96 dictionary android.Path
97 corpus android.Paths
98 corpusIntermediateDir android.Path
Kris Alderf979ee32019-10-22 10:52:01 -070099 config android.Path
Tri Voad172d82019-11-27 13:45:45 -0800100 data android.Paths
101 dataIntermediateDir android.Path
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700102 installedSharedDeps []string
Mitch Phillipsda9a4632019-07-15 09:34:09 -0700103}
104
105func (fuzz *fuzzBinary) linkerProps() []interface{} {
106 props := fuzz.binaryDecorator.linkerProps()
Mitch Phillips4e4ab8a2019-09-13 17:32:50 -0700107 props = append(props, &fuzz.Properties)
Mitch Phillipsda9a4632019-07-15 09:34:09 -0700108 return props
109}
110
111func (fuzz *fuzzBinary) linkerInit(ctx BaseModuleContext) {
Mitch Phillipsda9a4632019-07-15 09:34:09 -0700112 fuzz.binaryDecorator.linkerInit(ctx)
113}
114
115func (fuzz *fuzzBinary) linkerDeps(ctx DepsContext, deps Deps) Deps {
116 deps.StaticLibs = append(deps.StaticLibs,
117 config.LibFuzzerRuntimeLibrary(ctx.toolchain()))
118 deps = fuzz.binaryDecorator.linkerDeps(ctx, deps)
119 return deps
120}
121
122func (fuzz *fuzzBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags {
123 flags = fuzz.binaryDecorator.linkerFlags(ctx, flags)
Mitch Phillips1f7f54f2019-11-14 14:50:47 -0800124 // RunPaths on devices isn't instantiated by the base linker. `../lib` for
125 // installed fuzz targets (both host and device), and `./lib` for fuzz
126 // target packages.
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700127 flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/../lib`)
Mitch Phillips1f7f54f2019-11-14 14:50:47 -0800128 flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/lib`)
Mitch Phillipsda9a4632019-07-15 09:34:09 -0700129 return flags
130}
131
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700132// This function performs a breadth-first search over the provided module's
133// dependencies using `visitDirectDeps` to enumerate all shared library
134// dependencies. We require breadth-first expansion, as otherwise we may
135// incorrectly use the core libraries (sanitizer runtimes, libc, libdl, etc.)
136// from a dependency. This may cause issues when dependencies have explicit
137// sanitizer tags, as we may get a dependency on an unsanitized libc, etc.
Colin Crossdc809f92019-11-20 15:58:32 -0800138func collectAllSharedDependencies(ctx android.SingletonContext, module android.Module) android.Paths {
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700139 var fringe []android.Module
140
Mitch Phillipsc0b442f2020-04-27 16:44:58 -0700141 seen := make(map[string]bool)
Colin Crossdc809f92019-11-20 15:58:32 -0800142
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700143 // Enumerate the first level of dependencies, as we discard all non-library
144 // modules in the BFS loop below.
145 ctx.VisitDirectDeps(module, func(dep android.Module) {
Colin Crossdc809f92019-11-20 15:58:32 -0800146 if isValidSharedDependency(dep) {
Mitch Phillipsf50bddb2019-11-12 14:03:31 -0800147 fringe = append(fringe, dep)
148 }
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700149 })
150
Colin Crossdc809f92019-11-20 15:58:32 -0800151 var sharedLibraries android.Paths
152
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700153 for i := 0; i < len(fringe); i++ {
154 module := fringe[i]
Mitch Phillipsc0b442f2020-04-27 16:44:58 -0700155 if seen[module.Name()] {
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700156 continue
157 }
Mitch Phillipsc0b442f2020-04-27 16:44:58 -0700158 seen[module.Name()] = true
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700159
160 ccModule := module.(*Module)
Colin Crossdc809f92019-11-20 15:58:32 -0800161 sharedLibraries = append(sharedLibraries, ccModule.UnstrippedOutputFile())
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700162 ctx.VisitDirectDeps(module, func(dep android.Module) {
Mitch Phillipsc0b442f2020-04-27 16:44:58 -0700163 if isValidSharedDependency(dep) && !seen[dep.Name()] {
Mitch Phillipsf50bddb2019-11-12 14:03:31 -0800164 fringe = append(fringe, dep)
165 }
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700166 })
167 }
Colin Crossdc809f92019-11-20 15:58:32 -0800168
169 return sharedLibraries
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700170}
171
172// This function takes a module and determines if it is a unique shared library
173// that should be installed in the fuzz target output directories. This function
174// returns true, unless:
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700175// - The module is not a shared library, or
Martin Stjernholm02460ab2020-10-06 02:36:43 +0100176// - The module is a header, stub, or vendor-linked library, or
177// - The module is a prebuilt and its source is available, or
178// - The module is a versioned member of an SDK snapshot.
Colin Crossdc809f92019-11-20 15:58:32 -0800179func isValidSharedDependency(dependency android.Module) bool {
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700180 // TODO(b/144090547): We should be parsing these modules using
181 // ModuleDependencyTag instead of the current brute-force checking.
182
Colin Cross31076b32020-10-23 17:22:06 -0700183 linkable, ok := dependency.(LinkableInterface)
184 if !ok || !linkable.CcLibraryInterface() {
185 // Discard non-linkables.
186 return false
187 }
188
189 if !linkable.Shared() {
190 // Discard static libs.
191 return false
192 }
193
194 if linkable.UseVndk() {
195 // Discard vendor linked libraries.
196 return false
197 }
198
199 if lib := moduleLibraryInterface(dependency); lib != nil && lib.buildStubs() && linkable.CcLibrary() {
Mitch Phillipsf50bddb2019-11-12 14:03:31 -0800200 // Discard stubs libs (only CCLibrary variants). Prebuilt libraries should not
201 // be excluded on the basis of they're not CCLibrary()'s.
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700202 return false
203 }
204
Mitch Phillipsf50bddb2019-11-12 14:03:31 -0800205 // We discarded module stubs libraries above, but the LLNDK prebuilts stubs
206 // libraries must be handled differently - by looking for the stubDecorator.
207 // Discard LLNDK prebuilts stubs as well.
208 if ccLibrary, isCcLibrary := dependency.(*Module); isCcLibrary {
209 if _, isLLndkStubLibrary := ccLibrary.linker.(*stubDecorator); isLLndkStubLibrary {
210 return false
211 }
212 }
213
Martin Stjernholm02460ab2020-10-06 02:36:43 +0100214 // If the same library is present both as source and a prebuilt we must pick
215 // only one to avoid a conflict. Always prefer the source since the prebuilt
216 // probably won't be built with sanitizers enabled.
217 if prebuilt, ok := dependency.(android.PrebuiltInterface); ok &&
218 prebuilt.Prebuilt() != nil && prebuilt.Prebuilt().SourceExists() {
219 return false
220 }
221
222 // Discard versioned members of SDK snapshots, because they will conflict with
223 // unversioned ones.
224 if sdkMember, ok := dependency.(android.SdkAware); ok && !sdkMember.ContainingSdk().Unversioned() {
225 return false
226 }
227
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700228 return true
229}
230
231func sharedLibraryInstallLocation(
232 libraryPath android.Path, isHost bool, archString string) string {
233 installLocation := "$(PRODUCT_OUT)/data"
234 if isHost {
235 installLocation = "$(HOST_OUT)"
236 }
237 installLocation = filepath.Join(
238 installLocation, "fuzz", archString, "lib", libraryPath.Base())
239 return installLocation
240}
241
Mitch Phillips0bf97132020-03-06 09:38:12 -0800242// Get the device-only shared library symbols install directory.
243func sharedLibrarySymbolsInstallLocation(libraryPath android.Path, archString string) string {
244 return filepath.Join("$(PRODUCT_OUT)/symbols/data/fuzz/", archString, "/lib/", libraryPath.Base())
245}
246
Mitch Phillipsda9a4632019-07-15 09:34:09 -0700247func (fuzz *fuzzBinary) install(ctx ModuleContext, file android.Path) {
Mitch Phillips4e4ab8a2019-09-13 17:32:50 -0700248 fuzz.binaryDecorator.baseInstaller.dir = filepath.Join(
249 "fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
250 fuzz.binaryDecorator.baseInstaller.dir64 = filepath.Join(
251 "fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
Mitch Phillipsda9a4632019-07-15 09:34:09 -0700252 fuzz.binaryDecorator.baseInstaller.install(ctx, file)
Mitch Phillips4e4ab8a2019-09-13 17:32:50 -0700253
254 fuzz.corpus = android.PathsForModuleSrc(ctx, fuzz.Properties.Corpus)
Colin Crossf1a035e2020-11-16 17:32:30 -0800255 builder := android.NewRuleBuilder(pctx, ctx)
Mitch Phillips8a2bc0b2019-10-17 15:04:01 -0700256 intermediateDir := android.PathForModuleOut(ctx, "corpus")
257 for _, entry := range fuzz.corpus {
258 builder.Command().Text("cp").
259 Input(entry).
260 Output(intermediateDir.Join(ctx, entry.Base()))
261 }
Colin Crossf1a035e2020-11-16 17:32:30 -0800262 builder.Build("copy_corpus", "copy corpus")
Mitch Phillips8a2bc0b2019-10-17 15:04:01 -0700263 fuzz.corpusIntermediateDir = intermediateDir
264
Tri Voad172d82019-11-27 13:45:45 -0800265 fuzz.data = android.PathsForModuleSrc(ctx, fuzz.Properties.Data)
Colin Crossf1a035e2020-11-16 17:32:30 -0800266 builder = android.NewRuleBuilder(pctx, ctx)
Tri Voad172d82019-11-27 13:45:45 -0800267 intermediateDir = android.PathForModuleOut(ctx, "data")
268 for _, entry := range fuzz.data {
269 builder.Command().Text("cp").
270 Input(entry).
271 Output(intermediateDir.Join(ctx, entry.Rel()))
272 }
Colin Crossf1a035e2020-11-16 17:32:30 -0800273 builder.Build("copy_data", "copy data")
Tri Voad172d82019-11-27 13:45:45 -0800274 fuzz.dataIntermediateDir = intermediateDir
275
Mitch Phillips4e4ab8a2019-09-13 17:32:50 -0700276 if fuzz.Properties.Dictionary != nil {
277 fuzz.dictionary = android.PathForModuleSrc(ctx, *fuzz.Properties.Dictionary)
278 if fuzz.dictionary.Ext() != ".dict" {
279 ctx.PropertyErrorf("dictionary",
280 "Fuzzer dictionary %q does not have '.dict' extension",
281 fuzz.dictionary.String())
282 }
283 }
Kris Alderf979ee32019-10-22 10:52:01 -0700284
285 if fuzz.Properties.Fuzz_config != nil {
Kris Alderdb97af42019-10-30 10:17:04 -0700286 configPath := android.PathForModuleOut(ctx, "config").Join(ctx, "config.json")
Colin Crosscf371cc2020-11-13 11:48:42 -0800287 android.WriteFileRule(ctx, configPath, fuzz.Properties.Fuzz_config.String())
Kris Alderf979ee32019-10-22 10:52:01 -0700288 fuzz.config = configPath
289 }
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700290
291 // Grab the list of required shared libraries.
Mitch Phillipsc0b442f2020-04-27 16:44:58 -0700292 seen := make(map[string]bool)
Colin Crossdc809f92019-11-20 15:58:32 -0800293 var sharedLibraries android.Paths
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700294 ctx.WalkDeps(func(child, parent android.Module) bool {
Mitch Phillipsc0b442f2020-04-27 16:44:58 -0700295 if seen[child.Name()] {
Colin Crossdc809f92019-11-20 15:58:32 -0800296 return false
297 }
Mitch Phillipsc0b442f2020-04-27 16:44:58 -0700298 seen[child.Name()] = true
Colin Crossdc809f92019-11-20 15:58:32 -0800299
300 if isValidSharedDependency(child) {
301 sharedLibraries = append(sharedLibraries, child.(*Module).UnstrippedOutputFile())
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700302 return true
303 }
304 return false
305 })
306
307 for _, lib := range sharedLibraries {
308 fuzz.installedSharedDeps = append(fuzz.installedSharedDeps,
309 sharedLibraryInstallLocation(
310 lib, ctx.Host(), ctx.Arch().ArchType.String()))
Mitch Phillips0bf97132020-03-06 09:38:12 -0800311
312 // Also add the dependency on the shared library symbols dir.
313 if !ctx.Host() {
314 fuzz.installedSharedDeps = append(fuzz.installedSharedDeps,
315 sharedLibrarySymbolsInstallLocation(lib, ctx.Arch().ArchType.String()))
316 }
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700317 }
Mitch Phillipsda9a4632019-07-15 09:34:09 -0700318}
319
320func NewFuzz(hod android.HostOrDeviceSupported) *Module {
321 module, binary := NewBinary(hod)
322
Mitch Phillipsda9a4632019-07-15 09:34:09 -0700323 binary.baseInstaller = NewFuzzInstaller()
324 module.sanitize.SetSanitizer(fuzzer, true)
325
326 fuzz := &fuzzBinary{
327 binaryDecorator: binary,
328 baseCompiler: NewBaseCompiler(),
329 }
330 module.compiler = fuzz
331 module.linker = fuzz
332 module.installer = fuzz
Colin Crosseec9b282019-07-18 16:20:52 -0700333
334 // The fuzzer runtime is not present for darwin host modules, disable cc_fuzz modules when targeting darwin.
335 android.AddLoadHook(module, func(ctx android.LoadHookContext) {
Alex Light71123ec2019-07-24 13:34:19 -0700336 disableDarwinAndLinuxBionic := struct {
Colin Crosseec9b282019-07-18 16:20:52 -0700337 Target struct {
338 Darwin struct {
339 Enabled *bool
340 }
Alex Light71123ec2019-07-24 13:34:19 -0700341 Linux_bionic struct {
342 Enabled *bool
343 }
Colin Crosseec9b282019-07-18 16:20:52 -0700344 }
345 }{}
Alex Light71123ec2019-07-24 13:34:19 -0700346 disableDarwinAndLinuxBionic.Target.Darwin.Enabled = BoolPtr(false)
347 disableDarwinAndLinuxBionic.Target.Linux_bionic.Enabled = BoolPtr(false)
348 ctx.AppendProperties(&disableDarwinAndLinuxBionic)
Colin Crosseec9b282019-07-18 16:20:52 -0700349 })
350
Mitch Phillipsda9a4632019-07-15 09:34:09 -0700351 return module
352}
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700353
354// Responsible for generating GNU Make rules that package fuzz targets into
355// their architecture & target/host specific zip file.
356type fuzzPackager struct {
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700357 packages android.Paths
358 sharedLibInstallStrings []string
359 fuzzTargets map[string]bool
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700360}
361
362func fuzzPackagingFactory() android.Singleton {
363 return &fuzzPackager{}
364}
365
366type fileToZip struct {
367 SourceFilePath android.Path
368 DestinationPathPrefix string
369}
370
Colin Crossdc809f92019-11-20 15:58:32 -0800371type archOs struct {
372 hostOrTarget string
373 arch string
374 dir string
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700375}
376
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700377func (s *fuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
378 // Map between each architecture + host/device combination, and the files that
379 // need to be packaged (in the tuple of {source file, destination folder in
380 // archive}).
Colin Crossdc809f92019-11-20 15:58:32 -0800381 archDirs := make(map[archOs][]fileToZip)
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700382
Colin Crossdc809f92019-11-20 15:58:32 -0800383 // Map tracking whether each shared library has an install rule to avoid duplicate install rules from
384 // multiple fuzzers that depend on the same shared library.
385 sharedLibraryInstalled := make(map[string]bool)
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700386
387 // List of individual fuzz targets, so that 'make fuzz' also installs the targets
388 // to the correct output directories as well.
389 s.fuzzTargets = make(map[string]bool)
390
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700391 ctx.VisitAllModules(func(module android.Module) {
392 // Discard non-fuzz targets.
393 ccModule, ok := module.(*Module)
394 if !ok {
395 return
396 }
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700397
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700398 fuzzModule, ok := ccModule.compiler.(*fuzzBinary)
399 if !ok {
400 return
401 }
402
Yifan Hong60e0cfb2020-10-21 15:17:56 -0700403 // Discard ramdisk + vendor_ramdisk + recovery modules, they're duplicates of
Mitch Phillips2edbe8e2019-11-13 08:36:07 -0800404 // fuzz targets we're going to package anyway.
405 if !ccModule.Enabled() || ccModule.Properties.PreventInstall ||
Yifan Hong60e0cfb2020-10-21 15:17:56 -0700406 ccModule.InRamdisk() || ccModule.InVendorRamdisk() || ccModule.InRecovery() {
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700407 return
408 }
409
Mitch Phillips6a9bf212019-12-05 07:36:11 -0800410 // Discard modules that are in an unavailable namespace.
411 if !ccModule.ExportedToMake() {
412 return
413 }
414
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700415 hostOrTargetString := "target"
416 if ccModule.Host() {
417 hostOrTargetString = "host"
418 }
419
420 archString := ccModule.Arch().ArchType.String()
421 archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString)
Colin Crossdc809f92019-11-20 15:58:32 -0800422 archOs := archOs{hostOrTarget: hostOrTargetString, arch: archString, dir: archDir.String()}
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700423
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700424 // Grab the list of required shared libraries.
Colin Crossdc809f92019-11-20 15:58:32 -0800425 sharedLibraries := collectAllSharedDependencies(ctx, module)
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700426
Mitch Phillips2edbe8e2019-11-13 08:36:07 -0800427 var files []fileToZip
Colin Crossf1a035e2020-11-16 17:32:30 -0800428 builder := android.NewRuleBuilder(pctx, ctx)
Mitch Phillips2edbe8e2019-11-13 08:36:07 -0800429
430 // Package the corpora into a zipfile.
431 if fuzzModule.corpus != nil {
432 corpusZip := archDir.Join(ctx, module.Name()+"_seed_corpus.zip")
Colin Crossf1a035e2020-11-16 17:32:30 -0800433 command := builder.Command().BuiltTool("soong_zip").
Mitch Phillips2edbe8e2019-11-13 08:36:07 -0800434 Flag("-j").
435 FlagWithOutput("-o ", corpusZip)
Colin Cross053fca12020-08-19 13:51:47 -0700436 command.FlagWithRspFileInputList("-r ", fuzzModule.corpus)
Mitch Phillips2edbe8e2019-11-13 08:36:07 -0800437 files = append(files, fileToZip{corpusZip, ""})
438 }
439
Tri Voad172d82019-11-27 13:45:45 -0800440 // Package the data into a zipfile.
441 if fuzzModule.data != nil {
442 dataZip := archDir.Join(ctx, module.Name()+"_data.zip")
Colin Crossf1a035e2020-11-16 17:32:30 -0800443 command := builder.Command().BuiltTool("soong_zip").
Tri Voad172d82019-11-27 13:45:45 -0800444 FlagWithOutput("-o ", dataZip)
445 for _, f := range fuzzModule.data {
446 intermediateDir := strings.TrimSuffix(f.String(), f.Rel())
447 command.FlagWithArg("-C ", intermediateDir)
448 command.FlagWithInput("-f ", f)
449 }
450 files = append(files, fileToZip{dataZip, ""})
451 }
452
Mitch Phillips2edbe8e2019-11-13 08:36:07 -0800453 // Find and mark all the transiently-dependent shared libraries for
454 // packaging.
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700455 for _, library := range sharedLibraries {
Mitch Phillips2edbe8e2019-11-13 08:36:07 -0800456 files = append(files, fileToZip{library, "lib"})
Mitch Phillips13ed3f52019-11-12 11:12:10 -0800457
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700458 // For each architecture-specific shared library dependency, we need to
459 // install it to the output directory. Setup the install destination here,
460 // which will be used by $(copy-many-files) in the Make backend.
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700461 installDestination := sharedLibraryInstallLocation(
462 library, ccModule.Host(), archString)
Colin Crossdc809f92019-11-20 15:58:32 -0800463 if sharedLibraryInstalled[installDestination] {
464 continue
465 }
466 sharedLibraryInstalled[installDestination] = true
Mitch Phillips0bf97132020-03-06 09:38:12 -0800467
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700468 // Escape all the variables, as the install destination here will be called
469 // via. $(eval) in Make.
470 installDestination = strings.ReplaceAll(
471 installDestination, "$", "$$")
472 s.sharedLibInstallStrings = append(s.sharedLibInstallStrings,
473 library.String()+":"+installDestination)
Mitch Phillips0bf97132020-03-06 09:38:12 -0800474
475 // Ensure that on device, the library is also reinstalled to the /symbols/
476 // dir. Symbolized DSO's are always installed to the device when fuzzing, but
477 // we want symbolization tools (like `stack`) to be able to find the symbols
478 // in $ANDROID_PRODUCT_OUT/symbols automagically.
479 if !ccModule.Host() {
480 symbolsInstallDestination := sharedLibrarySymbolsInstallLocation(library, archString)
481 symbolsInstallDestination = strings.ReplaceAll(symbolsInstallDestination, "$", "$$")
482 s.sharedLibInstallStrings = append(s.sharedLibInstallStrings,
483 library.String()+":"+symbolsInstallDestination)
484 }
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700485 }
486
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700487 // The executable.
Mitch Phillips2edbe8e2019-11-13 08:36:07 -0800488 files = append(files, fileToZip{ccModule.UnstrippedOutputFile(), ""})
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700489
490 // The dictionary.
491 if fuzzModule.dictionary != nil {
Mitch Phillips2edbe8e2019-11-13 08:36:07 -0800492 files = append(files, fileToZip{fuzzModule.dictionary, ""})
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700493 }
Kris Alderf979ee32019-10-22 10:52:01 -0700494
495 // Additional fuzz config.
496 if fuzzModule.config != nil {
Mitch Phillips2edbe8e2019-11-13 08:36:07 -0800497 files = append(files, fileToZip{fuzzModule.config, ""})
Kris Alderf979ee32019-10-22 10:52:01 -0700498 }
Mitch Phillips2edbe8e2019-11-13 08:36:07 -0800499
500 fuzzZip := archDir.Join(ctx, module.Name()+".zip")
Colin Crossf1a035e2020-11-16 17:32:30 -0800501 command := builder.Command().BuiltTool("soong_zip").
Mitch Phillips2edbe8e2019-11-13 08:36:07 -0800502 Flag("-j").
503 FlagWithOutput("-o ", fuzzZip)
504 for _, file := range files {
505 if file.DestinationPathPrefix != "" {
506 command.FlagWithArg("-P ", file.DestinationPathPrefix)
507 } else {
508 command.Flag("-P ''")
509 }
510 command.FlagWithInput("-f ", file.SourceFilePath)
511 }
512
Colin Crossf1a035e2020-11-16 17:32:30 -0800513 builder.Build("create-"+fuzzZip.String(),
Mitch Phillips2edbe8e2019-11-13 08:36:07 -0800514 "Package "+module.Name()+" for "+archString+"-"+hostOrTargetString)
515
Mitch Phillips18e67192020-02-24 08:26:20 -0800516 // Don't add modules to 'make haiku' that are set to not be exported to the
517 // fuzzing infrastructure.
518 if config := fuzzModule.Properties.Fuzz_config; config != nil {
519 if ccModule.Host() && !BoolDefault(config.Fuzz_on_haiku_host, true) {
520 return
521 } else if !BoolDefault(config.Fuzz_on_haiku_device, true) {
522 return
523 }
524 }
525
526 s.fuzzTargets[module.Name()] = true
Colin Crossdc809f92019-11-20 15:58:32 -0800527 archDirs[archOs] = append(archDirs[archOs], fileToZip{fuzzZip, ""})
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700528 })
529
Colin Crossdc809f92019-11-20 15:58:32 -0800530 var archOsList []archOs
531 for archOs := range archDirs {
532 archOsList = append(archOsList, archOs)
533 }
534 sort.Slice(archOsList, func(i, j int) bool { return archOsList[i].dir < archOsList[j].dir })
535
536 for _, archOs := range archOsList {
537 filesToZip := archDirs[archOs]
538 arch := archOs.arch
539 hostOrTarget := archOs.hostOrTarget
Colin Crossf1a035e2020-11-16 17:32:30 -0800540 builder := android.NewRuleBuilder(pctx, ctx)
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700541 outputFile := android.PathForOutput(ctx, "fuzz-"+hostOrTarget+"-"+arch+".zip")
Mitch Phillipsa0a5e192019-09-27 14:00:06 -0700542 s.packages = append(s.packages, outputFile)
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700543
Colin Crossf1a035e2020-11-16 17:32:30 -0800544 command := builder.Command().BuiltTool("soong_zip").
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700545 Flag("-j").
Mitch Phillips2edbe8e2019-11-13 08:36:07 -0800546 FlagWithOutput("-o ", outputFile).
547 Flag("-L 0") // No need to try and re-compress the zipfiles.
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700548
549 for _, fileToZip := range filesToZip {
Mitch Phillips2edbe8e2019-11-13 08:36:07 -0800550 if fileToZip.DestinationPathPrefix != "" {
551 command.FlagWithArg("-P ", fileToZip.DestinationPathPrefix)
552 } else {
553 command.Flag("-P ''")
554 }
555 command.FlagWithInput("-f ", fileToZip.SourceFilePath)
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700556 }
557
Colin Crossf1a035e2020-11-16 17:32:30 -0800558 builder.Build("create-fuzz-package-"+arch+"-"+hostOrTarget,
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700559 "Create fuzz target packages for "+arch+"-"+hostOrTarget)
560 }
Mitch Phillipsa0a5e192019-09-27 14:00:06 -0700561}
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700562
Mitch Phillipsa0a5e192019-09-27 14:00:06 -0700563func (s *fuzzPackager) MakeVars(ctx android.MakeVarsContext) {
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700564 packages := s.packages.Strings()
565 sort.Strings(packages)
566 sort.Strings(s.sharedLibInstallStrings)
Mitch Phillipsa0a5e192019-09-27 14:00:06 -0700567 // TODO(mitchp): Migrate this to use MakeVarsContext::DistForGoal() when it's
568 // ready to handle phony targets created in Soong. In the meantime, this
569 // exports the phony 'fuzz' target and dependencies on packages to
570 // core/main.mk so that we can use dist-for-goals.
Mitch Phillipse1ee1a12019-10-17 19:20:41 -0700571 ctx.Strict("SOONG_FUZZ_PACKAGING_ARCH_MODULES", strings.Join(packages, " "))
572 ctx.Strict("FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS",
573 strings.Join(s.sharedLibInstallStrings, " "))
574
575 // Preallocate the slice of fuzz targets to minimise memory allocations.
576 fuzzTargets := make([]string, 0, len(s.fuzzTargets))
577 for target, _ := range s.fuzzTargets {
578 fuzzTargets = append(fuzzTargets, target)
579 }
580 sort.Strings(fuzzTargets)
581 ctx.Strict("ALL_FUZZ_TARGETS", strings.Join(fuzzTargets, " "))
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700582}