blob: a99b0bb12979814115fa6a44ee24e2cc232972af [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 (
Mitch Phillips4de896e2019-08-28 16:04:36 -070018 "path/filepath"
Mitch Phillipsa0a5e192019-09-27 14:00:06 -070019 "strings"
Mitch Phillips4de896e2019-08-28 16:04:36 -070020
21 "github.com/google/blueprint/proptools"
22
Mitch Phillipsda9a4632019-07-15 09:34:09 -070023 "android/soong/android"
24 "android/soong/cc/config"
25)
26
Mitch Phillips4e4ab8a2019-09-13 17:32:50 -070027type FuzzProperties struct {
28 // Optional list of seed files to be installed to the fuzz target's output
29 // directory.
30 Corpus []string `android:"path"`
31 // Optional dictionary to be installed to the fuzz target's output directory.
32 Dictionary *string `android:"path"`
33}
34
Mitch Phillipsda9a4632019-07-15 09:34:09 -070035func init() {
36 android.RegisterModuleType("cc_fuzz", FuzzFactory)
Mitch Phillipsd3254b42019-09-24 13:03:28 -070037 android.RegisterSingletonType("cc_fuzz_packaging", fuzzPackagingFactory)
Mitch Phillipsda9a4632019-07-15 09:34:09 -070038}
39
40// cc_fuzz creates a host/device fuzzer binary. Host binaries can be found at
41// $ANDROID_HOST_OUT/fuzz/, and device binaries can be found at /data/fuzz on
42// your device, or $ANDROID_PRODUCT_OUT/data/fuzz in your build tree.
43func FuzzFactory() android.Module {
44 module := NewFuzz(android.HostAndDeviceSupported)
45 return module.Init()
46}
47
48func NewFuzzInstaller() *baseInstaller {
49 return NewBaseInstaller("fuzz", "fuzz", InstallInData)
50}
51
52type fuzzBinary struct {
53 *binaryDecorator
54 *baseCompiler
Mitch Phillips4e4ab8a2019-09-13 17:32:50 -070055
Mitch Phillips8a2bc0b2019-10-17 15:04:01 -070056 Properties FuzzProperties
57 dictionary android.Path
58 corpus android.Paths
59 corpusIntermediateDir android.Path
Mitch Phillipsda9a4632019-07-15 09:34:09 -070060}
61
62func (fuzz *fuzzBinary) linkerProps() []interface{} {
63 props := fuzz.binaryDecorator.linkerProps()
Mitch Phillips4e4ab8a2019-09-13 17:32:50 -070064 props = append(props, &fuzz.Properties)
Mitch Phillipsda9a4632019-07-15 09:34:09 -070065 return props
66}
67
68func (fuzz *fuzzBinary) linkerInit(ctx BaseModuleContext) {
69 // Add ../lib[64] to rpath so that out/host/linux-x86/fuzz/<fuzzer> can
70 // find out/host/linux-x86/lib[64]/library.so
71 runpaths := []string{"../lib"}
72 for _, runpath := range runpaths {
73 if ctx.toolchain().Is64Bit() {
74 runpath += "64"
75 }
76 fuzz.binaryDecorator.baseLinker.dynamicProperties.RunPaths = append(
77 fuzz.binaryDecorator.baseLinker.dynamicProperties.RunPaths, runpath)
78 }
79
80 // add "" to rpath so that fuzzer binaries can find libraries in their own fuzz directory
81 fuzz.binaryDecorator.baseLinker.dynamicProperties.RunPaths = append(
82 fuzz.binaryDecorator.baseLinker.dynamicProperties.RunPaths, "")
83
84 fuzz.binaryDecorator.linkerInit(ctx)
85}
86
87func (fuzz *fuzzBinary) linkerDeps(ctx DepsContext, deps Deps) Deps {
88 deps.StaticLibs = append(deps.StaticLibs,
89 config.LibFuzzerRuntimeLibrary(ctx.toolchain()))
90 deps = fuzz.binaryDecorator.linkerDeps(ctx, deps)
91 return deps
92}
93
94func (fuzz *fuzzBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags {
95 flags = fuzz.binaryDecorator.linkerFlags(ctx, flags)
96 return flags
97}
98
99func (fuzz *fuzzBinary) install(ctx ModuleContext, file android.Path) {
Mitch Phillips4e4ab8a2019-09-13 17:32:50 -0700100 fuzz.binaryDecorator.baseInstaller.dir = filepath.Join(
101 "fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
102 fuzz.binaryDecorator.baseInstaller.dir64 = filepath.Join(
103 "fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
Mitch Phillipsda9a4632019-07-15 09:34:09 -0700104 fuzz.binaryDecorator.baseInstaller.install(ctx, file)
Mitch Phillips4e4ab8a2019-09-13 17:32:50 -0700105
106 fuzz.corpus = android.PathsForModuleSrc(ctx, fuzz.Properties.Corpus)
Mitch Phillips8a2bc0b2019-10-17 15:04:01 -0700107 builder := android.NewRuleBuilder()
108 intermediateDir := android.PathForModuleOut(ctx, "corpus")
109 for _, entry := range fuzz.corpus {
110 builder.Command().Text("cp").
111 Input(entry).
112 Output(intermediateDir.Join(ctx, entry.Base()))
113 }
114 builder.Build(pctx, ctx, "copy_corpus", "copy corpus")
115 fuzz.corpusIntermediateDir = intermediateDir
116
Mitch Phillips4e4ab8a2019-09-13 17:32:50 -0700117 if fuzz.Properties.Dictionary != nil {
118 fuzz.dictionary = android.PathForModuleSrc(ctx, *fuzz.Properties.Dictionary)
119 if fuzz.dictionary.Ext() != ".dict" {
120 ctx.PropertyErrorf("dictionary",
121 "Fuzzer dictionary %q does not have '.dict' extension",
122 fuzz.dictionary.String())
123 }
124 }
Mitch Phillipsda9a4632019-07-15 09:34:09 -0700125}
126
127func NewFuzz(hod android.HostOrDeviceSupported) *Module {
128 module, binary := NewBinary(hod)
129
Mitch Phillipsda9a4632019-07-15 09:34:09 -0700130 binary.baseInstaller = NewFuzzInstaller()
131 module.sanitize.SetSanitizer(fuzzer, true)
132
133 fuzz := &fuzzBinary{
134 binaryDecorator: binary,
135 baseCompiler: NewBaseCompiler(),
136 }
137 module.compiler = fuzz
138 module.linker = fuzz
139 module.installer = fuzz
Colin Crosseec9b282019-07-18 16:20:52 -0700140
141 // The fuzzer runtime is not present for darwin host modules, disable cc_fuzz modules when targeting darwin.
142 android.AddLoadHook(module, func(ctx android.LoadHookContext) {
Alex Light71123ec2019-07-24 13:34:19 -0700143 disableDarwinAndLinuxBionic := struct {
Colin Crosseec9b282019-07-18 16:20:52 -0700144 Target struct {
145 Darwin struct {
146 Enabled *bool
147 }
Alex Light71123ec2019-07-24 13:34:19 -0700148 Linux_bionic struct {
149 Enabled *bool
150 }
Colin Crosseec9b282019-07-18 16:20:52 -0700151 }
152 }{}
Alex Light71123ec2019-07-24 13:34:19 -0700153 disableDarwinAndLinuxBionic.Target.Darwin.Enabled = BoolPtr(false)
154 disableDarwinAndLinuxBionic.Target.Linux_bionic.Enabled = BoolPtr(false)
155 ctx.AppendProperties(&disableDarwinAndLinuxBionic)
Colin Crosseec9b282019-07-18 16:20:52 -0700156 })
157
Mitch Phillipsd0bd16d2019-08-22 15:47:09 -0700158 // Statically link the STL. This allows fuzz target deployment to not have to
159 // include the STL.
160 android.AddLoadHook(module, func(ctx android.LoadHookContext) {
161 staticStlLinkage := struct {
Mitch Phillips302f9642019-10-14 16:40:26 -0700162 Target struct {
163 Linux_glibc struct {
164 Stl *string
165 }
166 }
Mitch Phillipsd0bd16d2019-08-22 15:47:09 -0700167 }{}
168
Mitch Phillips302f9642019-10-14 16:40:26 -0700169 staticStlLinkage.Target.Linux_glibc.Stl = proptools.StringPtr("libc++_static")
Mitch Phillipsd0bd16d2019-08-22 15:47:09 -0700170 ctx.AppendProperties(&staticStlLinkage)
171 })
172
Mitch Phillipsda9a4632019-07-15 09:34:09 -0700173 return module
174}
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700175
176// Responsible for generating GNU Make rules that package fuzz targets into
177// their architecture & target/host specific zip file.
178type fuzzPackager struct {
Mitch Phillipsa0a5e192019-09-27 14:00:06 -0700179 packages android.Paths
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700180}
181
182func fuzzPackagingFactory() android.Singleton {
183 return &fuzzPackager{}
184}
185
186type fileToZip struct {
187 SourceFilePath android.Path
188 DestinationPathPrefix string
189}
190
191func (s *fuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
192 // Map between each architecture + host/device combination, and the files that
193 // need to be packaged (in the tuple of {source file, destination folder in
194 // archive}).
195 archDirs := make(map[android.OutputPath][]fileToZip)
196
197 ctx.VisitAllModules(func(module android.Module) {
198 // Discard non-fuzz targets.
199 ccModule, ok := module.(*Module)
200 if !ok {
201 return
202 }
203 fuzzModule, ok := ccModule.compiler.(*fuzzBinary)
204 if !ok {
205 return
206 }
207
208 // Discard vendor-NDK-linked modules, they're duplicates of fuzz targets
209 // we're going to package anyway.
210 if ccModule.useVndk() || !ccModule.Enabled() {
211 return
212 }
213
214 hostOrTargetString := "target"
215 if ccModule.Host() {
216 hostOrTargetString = "host"
217 }
218
219 archString := ccModule.Arch().ArchType.String()
220 archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString)
221
222 // The executable.
223 archDirs[archDir] = append(archDirs[archDir],
224 fileToZip{ccModule.outputFile.Path(), ccModule.Name()})
225
226 // The corpora.
227 for _, corpusEntry := range fuzzModule.corpus {
228 archDirs[archDir] = append(archDirs[archDir],
Mitch Phillips641575a2019-10-09 17:34:42 -0700229 fileToZip{corpusEntry, ccModule.Name() + "/corpus"})
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700230 }
231
232 // The dictionary.
233 if fuzzModule.dictionary != nil {
234 archDirs[archDir] = append(archDirs[archDir],
235 fileToZip{fuzzModule.dictionary, ccModule.Name()})
236 }
237 })
238
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700239 for archDir, filesToZip := range archDirs {
240 arch := archDir.Base()
241 hostOrTarget := filepath.Base(filepath.Dir(archDir.String()))
242 builder := android.NewRuleBuilder()
243 outputFile := android.PathForOutput(ctx, "fuzz-"+hostOrTarget+"-"+arch+".zip")
Mitch Phillipsa0a5e192019-09-27 14:00:06 -0700244 s.packages = append(s.packages, outputFile)
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700245
246 command := builder.Command().BuiltTool(ctx, "soong_zip").
247 Flag("-j").
248 FlagWithOutput("-o ", outputFile)
249
250 for _, fileToZip := range filesToZip {
251 command.FlagWithArg("-P ", fileToZip.DestinationPathPrefix).
252 FlagWithInput("-f ", fileToZip.SourceFilePath)
253 }
254
255 builder.Build(pctx, ctx, "create-fuzz-package-"+arch+"-"+hostOrTarget,
256 "Create fuzz target packages for "+arch+"-"+hostOrTarget)
257 }
Mitch Phillipsa0a5e192019-09-27 14:00:06 -0700258}
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700259
Mitch Phillipsa0a5e192019-09-27 14:00:06 -0700260func (s *fuzzPackager) MakeVars(ctx android.MakeVarsContext) {
261 // TODO(mitchp): Migrate this to use MakeVarsContext::DistForGoal() when it's
262 // ready to handle phony targets created in Soong. In the meantime, this
263 // exports the phony 'fuzz' target and dependencies on packages to
264 // core/main.mk so that we can use dist-for-goals.
265 ctx.Strict("SOONG_FUZZ_PACKAGING_ARCH_MODULES", strings.Join(s.packages.Strings(), " "))
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700266}