blob: 4d3852684dee93a9bdc72f9152b38f787133ad80 [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 Phillipsa0a5e192019-09-27 14:00:06 -070020 "strings"
Mitch Phillips4de896e2019-08-28 16:04:36 -070021
22 "github.com/google/blueprint/proptools"
23
Mitch Phillipsda9a4632019-07-15 09:34:09 -070024 "android/soong/android"
25 "android/soong/cc/config"
26)
27
Kris Alderf979ee32019-10-22 10:52:01 -070028type FuzzConfig struct {
29 // Email address of people to CC on bugs or contact about this fuzz target.
30 Cc []string `json:"cc,omitempty"`
31 // Boolean specifying whether to disable the fuzz target from running
32 // automatically in continuous fuzzing infrastructure.
33 Disable *bool `json:"disable,omitempty"`
34 // 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"`
38}
39
40func (f *FuzzConfig) String() string {
41 b, err := json.Marshal(f)
42 if err != nil {
43 panic(err)
44 }
45
46 return string(b)
47}
48
Mitch Phillips4e4ab8a2019-09-13 17:32:50 -070049type FuzzProperties struct {
50 // Optional list of seed files to be installed to the fuzz target's output
51 // directory.
52 Corpus []string `android:"path"`
53 // Optional dictionary to be installed to the fuzz target's output directory.
54 Dictionary *string `android:"path"`
Kris Alderf979ee32019-10-22 10:52:01 -070055 // Config for running the target on fuzzing infrastructure.
56 Fuzz_config *FuzzConfig
Mitch Phillips4e4ab8a2019-09-13 17:32:50 -070057}
58
Mitch Phillipsda9a4632019-07-15 09:34:09 -070059func init() {
60 android.RegisterModuleType("cc_fuzz", FuzzFactory)
Mitch Phillipsd3254b42019-09-24 13:03:28 -070061 android.RegisterSingletonType("cc_fuzz_packaging", fuzzPackagingFactory)
Mitch Phillipsda9a4632019-07-15 09:34:09 -070062}
63
64// cc_fuzz creates a host/device fuzzer binary. Host binaries can be found at
65// $ANDROID_HOST_OUT/fuzz/, and device binaries can be found at /data/fuzz on
66// your device, or $ANDROID_PRODUCT_OUT/data/fuzz in your build tree.
67func FuzzFactory() android.Module {
68 module := NewFuzz(android.HostAndDeviceSupported)
69 return module.Init()
70}
71
72func NewFuzzInstaller() *baseInstaller {
73 return NewBaseInstaller("fuzz", "fuzz", InstallInData)
74}
75
76type fuzzBinary struct {
77 *binaryDecorator
78 *baseCompiler
Mitch Phillips4e4ab8a2019-09-13 17:32:50 -070079
Mitch Phillips8a2bc0b2019-10-17 15:04:01 -070080 Properties FuzzProperties
81 dictionary android.Path
82 corpus android.Paths
83 corpusIntermediateDir android.Path
Kris Alderf979ee32019-10-22 10:52:01 -070084 config android.Path
Mitch Phillipsda9a4632019-07-15 09:34:09 -070085}
86
87func (fuzz *fuzzBinary) linkerProps() []interface{} {
88 props := fuzz.binaryDecorator.linkerProps()
Mitch Phillips4e4ab8a2019-09-13 17:32:50 -070089 props = append(props, &fuzz.Properties)
Mitch Phillipsda9a4632019-07-15 09:34:09 -070090 return props
91}
92
93func (fuzz *fuzzBinary) linkerInit(ctx BaseModuleContext) {
94 // Add ../lib[64] to rpath so that out/host/linux-x86/fuzz/<fuzzer> can
95 // find out/host/linux-x86/lib[64]/library.so
96 runpaths := []string{"../lib"}
97 for _, runpath := range runpaths {
98 if ctx.toolchain().Is64Bit() {
99 runpath += "64"
100 }
101 fuzz.binaryDecorator.baseLinker.dynamicProperties.RunPaths = append(
102 fuzz.binaryDecorator.baseLinker.dynamicProperties.RunPaths, runpath)
103 }
104
105 // add "" to rpath so that fuzzer binaries can find libraries in their own fuzz directory
106 fuzz.binaryDecorator.baseLinker.dynamicProperties.RunPaths = append(
107 fuzz.binaryDecorator.baseLinker.dynamicProperties.RunPaths, "")
108
109 fuzz.binaryDecorator.linkerInit(ctx)
110}
111
112func (fuzz *fuzzBinary) linkerDeps(ctx DepsContext, deps Deps) Deps {
113 deps.StaticLibs = append(deps.StaticLibs,
114 config.LibFuzzerRuntimeLibrary(ctx.toolchain()))
115 deps = fuzz.binaryDecorator.linkerDeps(ctx, deps)
116 return deps
117}
118
119func (fuzz *fuzzBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags {
120 flags = fuzz.binaryDecorator.linkerFlags(ctx, flags)
121 return flags
122}
123
124func (fuzz *fuzzBinary) install(ctx ModuleContext, file android.Path) {
Mitch Phillips4e4ab8a2019-09-13 17:32:50 -0700125 fuzz.binaryDecorator.baseInstaller.dir = filepath.Join(
126 "fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
127 fuzz.binaryDecorator.baseInstaller.dir64 = filepath.Join(
128 "fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
Mitch Phillipsda9a4632019-07-15 09:34:09 -0700129 fuzz.binaryDecorator.baseInstaller.install(ctx, file)
Mitch Phillips4e4ab8a2019-09-13 17:32:50 -0700130
131 fuzz.corpus = android.PathsForModuleSrc(ctx, fuzz.Properties.Corpus)
Mitch Phillips8a2bc0b2019-10-17 15:04:01 -0700132 builder := android.NewRuleBuilder()
133 intermediateDir := android.PathForModuleOut(ctx, "corpus")
134 for _, entry := range fuzz.corpus {
135 builder.Command().Text("cp").
136 Input(entry).
137 Output(intermediateDir.Join(ctx, entry.Base()))
138 }
139 builder.Build(pctx, ctx, "copy_corpus", "copy corpus")
140 fuzz.corpusIntermediateDir = intermediateDir
141
Mitch Phillips4e4ab8a2019-09-13 17:32:50 -0700142 if fuzz.Properties.Dictionary != nil {
143 fuzz.dictionary = android.PathForModuleSrc(ctx, *fuzz.Properties.Dictionary)
144 if fuzz.dictionary.Ext() != ".dict" {
145 ctx.PropertyErrorf("dictionary",
146 "Fuzzer dictionary %q does not have '.dict' extension",
147 fuzz.dictionary.String())
148 }
149 }
Kris Alderf979ee32019-10-22 10:52:01 -0700150
151 if fuzz.Properties.Fuzz_config != nil {
152 configPath := android.PathForModuleOut(ctx, "config").Join(ctx, "config.txt")
153 ctx.Build(pctx, android.BuildParams{
154 Rule: android.WriteFile,
155 Description: "fuzzer infrastructure configuration",
156 Output: configPath,
157 Args: map[string]string{
158 "content": fuzz.Properties.Fuzz_config.String(),
159 },
160 })
161 fuzz.config = configPath
162 }
Mitch Phillipsda9a4632019-07-15 09:34:09 -0700163}
164
165func NewFuzz(hod android.HostOrDeviceSupported) *Module {
166 module, binary := NewBinary(hod)
167
Mitch Phillipsda9a4632019-07-15 09:34:09 -0700168 binary.baseInstaller = NewFuzzInstaller()
169 module.sanitize.SetSanitizer(fuzzer, true)
170
171 fuzz := &fuzzBinary{
172 binaryDecorator: binary,
173 baseCompiler: NewBaseCompiler(),
174 }
175 module.compiler = fuzz
176 module.linker = fuzz
177 module.installer = fuzz
Colin Crosseec9b282019-07-18 16:20:52 -0700178
179 // The fuzzer runtime is not present for darwin host modules, disable cc_fuzz modules when targeting darwin.
180 android.AddLoadHook(module, func(ctx android.LoadHookContext) {
Alex Light71123ec2019-07-24 13:34:19 -0700181 disableDarwinAndLinuxBionic := struct {
Colin Crosseec9b282019-07-18 16:20:52 -0700182 Target struct {
183 Darwin struct {
184 Enabled *bool
185 }
Alex Light71123ec2019-07-24 13:34:19 -0700186 Linux_bionic struct {
187 Enabled *bool
188 }
Colin Crosseec9b282019-07-18 16:20:52 -0700189 }
190 }{}
Alex Light71123ec2019-07-24 13:34:19 -0700191 disableDarwinAndLinuxBionic.Target.Darwin.Enabled = BoolPtr(false)
192 disableDarwinAndLinuxBionic.Target.Linux_bionic.Enabled = BoolPtr(false)
193 ctx.AppendProperties(&disableDarwinAndLinuxBionic)
Colin Crosseec9b282019-07-18 16:20:52 -0700194 })
195
Mitch Phillipsd0bd16d2019-08-22 15:47:09 -0700196 // Statically link the STL. This allows fuzz target deployment to not have to
197 // include the STL.
198 android.AddLoadHook(module, func(ctx android.LoadHookContext) {
199 staticStlLinkage := struct {
Mitch Phillips302f9642019-10-14 16:40:26 -0700200 Target struct {
201 Linux_glibc struct {
202 Stl *string
203 }
204 }
Mitch Phillipsd0bd16d2019-08-22 15:47:09 -0700205 }{}
206
Mitch Phillips302f9642019-10-14 16:40:26 -0700207 staticStlLinkage.Target.Linux_glibc.Stl = proptools.StringPtr("libc++_static")
Mitch Phillipsd0bd16d2019-08-22 15:47:09 -0700208 ctx.AppendProperties(&staticStlLinkage)
209 })
210
Mitch Phillipsda9a4632019-07-15 09:34:09 -0700211 return module
212}
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700213
214// Responsible for generating GNU Make rules that package fuzz targets into
215// their architecture & target/host specific zip file.
216type fuzzPackager struct {
Mitch Phillipsa0a5e192019-09-27 14:00:06 -0700217 packages android.Paths
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700218}
219
220func fuzzPackagingFactory() android.Singleton {
221 return &fuzzPackager{}
222}
223
224type fileToZip struct {
225 SourceFilePath android.Path
226 DestinationPathPrefix string
227}
228
229func (s *fuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
230 // Map between each architecture + host/device combination, and the files that
231 // need to be packaged (in the tuple of {source file, destination folder in
232 // archive}).
233 archDirs := make(map[android.OutputPath][]fileToZip)
234
235 ctx.VisitAllModules(func(module android.Module) {
236 // Discard non-fuzz targets.
237 ccModule, ok := module.(*Module)
238 if !ok {
239 return
240 }
241 fuzzModule, ok := ccModule.compiler.(*fuzzBinary)
242 if !ok {
243 return
244 }
245
246 // Discard vendor-NDK-linked modules, they're duplicates of fuzz targets
247 // we're going to package anyway.
248 if ccModule.useVndk() || !ccModule.Enabled() {
249 return
250 }
251
252 hostOrTargetString := "target"
253 if ccModule.Host() {
254 hostOrTargetString = "host"
255 }
256
257 archString := ccModule.Arch().ArchType.String()
258 archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString)
259
260 // The executable.
261 archDirs[archDir] = append(archDirs[archDir],
262 fileToZip{ccModule.outputFile.Path(), ccModule.Name()})
263
264 // The corpora.
265 for _, corpusEntry := range fuzzModule.corpus {
266 archDirs[archDir] = append(archDirs[archDir],
Mitch Phillips641575a2019-10-09 17:34:42 -0700267 fileToZip{corpusEntry, ccModule.Name() + "/corpus"})
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700268 }
269
270 // The dictionary.
271 if fuzzModule.dictionary != nil {
272 archDirs[archDir] = append(archDirs[archDir],
273 fileToZip{fuzzModule.dictionary, ccModule.Name()})
274 }
Kris Alderf979ee32019-10-22 10:52:01 -0700275
276 // Additional fuzz config.
277 if fuzzModule.config != nil {
278 archDirs[archDir] = append(archDirs[archDir],
279 fileToZip{fuzzModule.config, ccModule.Name()})
280 }
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700281 })
282
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700283 for archDir, filesToZip := range archDirs {
284 arch := archDir.Base()
285 hostOrTarget := filepath.Base(filepath.Dir(archDir.String()))
286 builder := android.NewRuleBuilder()
287 outputFile := android.PathForOutput(ctx, "fuzz-"+hostOrTarget+"-"+arch+".zip")
Mitch Phillipsa0a5e192019-09-27 14:00:06 -0700288 s.packages = append(s.packages, outputFile)
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700289
290 command := builder.Command().BuiltTool(ctx, "soong_zip").
291 Flag("-j").
292 FlagWithOutput("-o ", outputFile)
293
294 for _, fileToZip := range filesToZip {
295 command.FlagWithArg("-P ", fileToZip.DestinationPathPrefix).
296 FlagWithInput("-f ", fileToZip.SourceFilePath)
297 }
298
299 builder.Build(pctx, ctx, "create-fuzz-package-"+arch+"-"+hostOrTarget,
300 "Create fuzz target packages for "+arch+"-"+hostOrTarget)
301 }
Mitch Phillipsa0a5e192019-09-27 14:00:06 -0700302}
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700303
Mitch Phillipsa0a5e192019-09-27 14:00:06 -0700304func (s *fuzzPackager) MakeVars(ctx android.MakeVarsContext) {
305 // TODO(mitchp): Migrate this to use MakeVarsContext::DistForGoal() when it's
306 // ready to handle phony targets created in Soong. In the meantime, this
307 // exports the phony 'fuzz' target and dependencies on packages to
308 // core/main.mk so that we can use dist-for-goals.
309 ctx.Strict("SOONG_FUZZ_PACKAGING_ARCH_MODULES", strings.Join(s.packages.Strings(), " "))
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700310}