blob: 7806e833647818c916b09c6bf7eec533c9d52afb [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"
19
Mitch Phillipsd3254b42019-09-24 13:03:28 -070020 "github.com/google/blueprint"
Mitch Phillips4de896e2019-08-28 16:04:36 -070021 "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
56 Properties FuzzProperties
57 corpus android.Paths
58 dictionary android.Path
Mitch Phillipsda9a4632019-07-15 09:34:09 -070059}
60
61func (fuzz *fuzzBinary) linkerProps() []interface{} {
62 props := fuzz.binaryDecorator.linkerProps()
Mitch Phillips4e4ab8a2019-09-13 17:32:50 -070063 props = append(props, &fuzz.Properties)
Mitch Phillipsda9a4632019-07-15 09:34:09 -070064 return props
65}
66
67func (fuzz *fuzzBinary) linkerInit(ctx BaseModuleContext) {
68 // Add ../lib[64] to rpath so that out/host/linux-x86/fuzz/<fuzzer> can
69 // find out/host/linux-x86/lib[64]/library.so
70 runpaths := []string{"../lib"}
71 for _, runpath := range runpaths {
72 if ctx.toolchain().Is64Bit() {
73 runpath += "64"
74 }
75 fuzz.binaryDecorator.baseLinker.dynamicProperties.RunPaths = append(
76 fuzz.binaryDecorator.baseLinker.dynamicProperties.RunPaths, runpath)
77 }
78
79 // add "" to rpath so that fuzzer binaries can find libraries in their own fuzz directory
80 fuzz.binaryDecorator.baseLinker.dynamicProperties.RunPaths = append(
81 fuzz.binaryDecorator.baseLinker.dynamicProperties.RunPaths, "")
82
83 fuzz.binaryDecorator.linkerInit(ctx)
84}
85
86func (fuzz *fuzzBinary) linkerDeps(ctx DepsContext, deps Deps) Deps {
87 deps.StaticLibs = append(deps.StaticLibs,
88 config.LibFuzzerRuntimeLibrary(ctx.toolchain()))
89 deps = fuzz.binaryDecorator.linkerDeps(ctx, deps)
90 return deps
91}
92
93func (fuzz *fuzzBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags {
94 flags = fuzz.binaryDecorator.linkerFlags(ctx, flags)
95 return flags
96}
97
98func (fuzz *fuzzBinary) install(ctx ModuleContext, file android.Path) {
Mitch Phillips4e4ab8a2019-09-13 17:32:50 -070099 fuzz.binaryDecorator.baseInstaller.dir = filepath.Join(
100 "fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
101 fuzz.binaryDecorator.baseInstaller.dir64 = filepath.Join(
102 "fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
Mitch Phillipsda9a4632019-07-15 09:34:09 -0700103 fuzz.binaryDecorator.baseInstaller.install(ctx, file)
Mitch Phillips4e4ab8a2019-09-13 17:32:50 -0700104
105 fuzz.corpus = android.PathsForModuleSrc(ctx, fuzz.Properties.Corpus)
106 if fuzz.Properties.Dictionary != nil {
107 fuzz.dictionary = android.PathForModuleSrc(ctx, *fuzz.Properties.Dictionary)
108 if fuzz.dictionary.Ext() != ".dict" {
109 ctx.PropertyErrorf("dictionary",
110 "Fuzzer dictionary %q does not have '.dict' extension",
111 fuzz.dictionary.String())
112 }
113 }
Mitch Phillipsda9a4632019-07-15 09:34:09 -0700114}
115
116func NewFuzz(hod android.HostOrDeviceSupported) *Module {
117 module, binary := NewBinary(hod)
118
Mitch Phillipsda9a4632019-07-15 09:34:09 -0700119 binary.baseInstaller = NewFuzzInstaller()
120 module.sanitize.SetSanitizer(fuzzer, true)
121
122 fuzz := &fuzzBinary{
123 binaryDecorator: binary,
124 baseCompiler: NewBaseCompiler(),
125 }
126 module.compiler = fuzz
127 module.linker = fuzz
128 module.installer = fuzz
Colin Crosseec9b282019-07-18 16:20:52 -0700129
130 // The fuzzer runtime is not present for darwin host modules, disable cc_fuzz modules when targeting darwin.
131 android.AddLoadHook(module, func(ctx android.LoadHookContext) {
Alex Light71123ec2019-07-24 13:34:19 -0700132 disableDarwinAndLinuxBionic := struct {
Colin Crosseec9b282019-07-18 16:20:52 -0700133 Target struct {
134 Darwin struct {
135 Enabled *bool
136 }
Alex Light71123ec2019-07-24 13:34:19 -0700137 Linux_bionic struct {
138 Enabled *bool
139 }
Colin Crosseec9b282019-07-18 16:20:52 -0700140 }
141 }{}
Alex Light71123ec2019-07-24 13:34:19 -0700142 disableDarwinAndLinuxBionic.Target.Darwin.Enabled = BoolPtr(false)
143 disableDarwinAndLinuxBionic.Target.Linux_bionic.Enabled = BoolPtr(false)
144 ctx.AppendProperties(&disableDarwinAndLinuxBionic)
Colin Crosseec9b282019-07-18 16:20:52 -0700145 })
146
Mitch Phillipsd0bd16d2019-08-22 15:47:09 -0700147 // Statically link the STL. This allows fuzz target deployment to not have to
148 // include the STL.
149 android.AddLoadHook(module, func(ctx android.LoadHookContext) {
150 staticStlLinkage := struct {
151 Stl *string
152 }{}
153
154 staticStlLinkage.Stl = proptools.StringPtr("libc++_static")
155 ctx.AppendProperties(&staticStlLinkage)
156 })
157
Mitch Phillipsda9a4632019-07-15 09:34:09 -0700158 return module
159}
Mitch Phillipsd3254b42019-09-24 13:03:28 -0700160
161// Responsible for generating GNU Make rules that package fuzz targets into
162// their architecture & target/host specific zip file.
163type fuzzPackager struct {
164}
165
166func fuzzPackagingFactory() android.Singleton {
167 return &fuzzPackager{}
168}
169
170type fileToZip struct {
171 SourceFilePath android.Path
172 DestinationPathPrefix string
173}
174
175func (s *fuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
176 // Map between each architecture + host/device combination, and the files that
177 // need to be packaged (in the tuple of {source file, destination folder in
178 // archive}).
179 archDirs := make(map[android.OutputPath][]fileToZip)
180
181 ctx.VisitAllModules(func(module android.Module) {
182 // Discard non-fuzz targets.
183 ccModule, ok := module.(*Module)
184 if !ok {
185 return
186 }
187 fuzzModule, ok := ccModule.compiler.(*fuzzBinary)
188 if !ok {
189 return
190 }
191
192 // Discard vendor-NDK-linked modules, they're duplicates of fuzz targets
193 // we're going to package anyway.
194 if ccModule.useVndk() || !ccModule.Enabled() {
195 return
196 }
197
198 hostOrTargetString := "target"
199 if ccModule.Host() {
200 hostOrTargetString = "host"
201 }
202
203 archString := ccModule.Arch().ArchType.String()
204 archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString)
205
206 // The executable.
207 archDirs[archDir] = append(archDirs[archDir],
208 fileToZip{ccModule.outputFile.Path(), ccModule.Name()})
209
210 // The corpora.
211 for _, corpusEntry := range fuzzModule.corpus {
212 archDirs[archDir] = append(archDirs[archDir],
213 fileToZip{corpusEntry, ccModule.Name() + "/corpus/" + corpusEntry.Base()})
214 }
215
216 // The dictionary.
217 if fuzzModule.dictionary != nil {
218 archDirs[archDir] = append(archDirs[archDir],
219 fileToZip{fuzzModule.dictionary, ccModule.Name()})
220 }
221 })
222
223 // List of architecture + host/device specific packages to build via. 'make fuzz'.
224 var archDirTargets android.Paths
225
226 for archDir, filesToZip := range archDirs {
227 arch := archDir.Base()
228 hostOrTarget := filepath.Base(filepath.Dir(archDir.String()))
229 builder := android.NewRuleBuilder()
230 outputFile := android.PathForOutput(ctx, "fuzz-"+hostOrTarget+"-"+arch+".zip")
231 archDirTargets = append(archDirTargets, outputFile)
232
233 command := builder.Command().BuiltTool(ctx, "soong_zip").
234 Flag("-j").
235 FlagWithOutput("-o ", outputFile)
236
237 for _, fileToZip := range filesToZip {
238 command.FlagWithArg("-P ", fileToZip.DestinationPathPrefix).
239 FlagWithInput("-f ", fileToZip.SourceFilePath)
240 }
241
242 builder.Build(pctx, ctx, "create-fuzz-package-"+arch+"-"+hostOrTarget,
243 "Create fuzz target packages for "+arch+"-"+hostOrTarget)
244 }
245
246 ctx.Build(pctx, android.BuildParams{
247 Rule: blueprint.Phony,
248 Output: android.PathForPhony(ctx, "fuzz"),
249 Implicits: archDirTargets,
250 Description: "Build all Android fuzz targets, and create packages.",
251 })
252}