diff options
Diffstat (limited to 'cc/fuzz.go')
-rw-r--r-- | cc/fuzz.go | 123 |
1 files changed, 121 insertions, 2 deletions
diff --git a/cc/fuzz.go b/cc/fuzz.go index b0fb262df..c19fdc5b0 100644 --- a/cc/fuzz.go +++ b/cc/fuzz.go @@ -16,6 +16,7 @@ package cc import ( "path/filepath" + "strings" "github.com/google/blueprint/proptools" @@ -23,8 +24,17 @@ import ( "android/soong/cc/config" ) +type FuzzProperties struct { + // Optional list of seed files to be installed to the fuzz target's output + // directory. + Corpus []string `android:"path"` + // Optional dictionary to be installed to the fuzz target's output directory. + Dictionary *string `android:"path"` +} + func init() { android.RegisterModuleType("cc_fuzz", FuzzFactory) + android.RegisterSingletonType("cc_fuzz_packaging", fuzzPackagingFactory) } // cc_fuzz creates a host/device fuzzer binary. Host binaries can be found at @@ -42,10 +52,15 @@ func NewFuzzInstaller() *baseInstaller { type fuzzBinary struct { *binaryDecorator *baseCompiler + + Properties FuzzProperties + corpus android.Paths + dictionary android.Path } func (fuzz *fuzzBinary) linkerProps() []interface{} { props := fuzz.binaryDecorator.linkerProps() + props = append(props, &fuzz.Properties) return props } @@ -81,9 +96,21 @@ func (fuzz *fuzzBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags { } func (fuzz *fuzzBinary) install(ctx ModuleContext, file android.Path) { - fuzz.binaryDecorator.baseInstaller.dir = filepath.Join("fuzz", ctx.Target().Arch.ArchType.String()) - fuzz.binaryDecorator.baseInstaller.dir64 = filepath.Join("fuzz", ctx.Target().Arch.ArchType.String()) + fuzz.binaryDecorator.baseInstaller.dir = filepath.Join( + "fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName()) + fuzz.binaryDecorator.baseInstaller.dir64 = filepath.Join( + "fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName()) fuzz.binaryDecorator.baseInstaller.install(ctx, file) + + fuzz.corpus = android.PathsForModuleSrc(ctx, fuzz.Properties.Corpus) + if fuzz.Properties.Dictionary != nil { + fuzz.dictionary = android.PathForModuleSrc(ctx, *fuzz.Properties.Dictionary) + if fuzz.dictionary.Ext() != ".dict" { + ctx.PropertyErrorf("dictionary", + "Fuzzer dictionary %q does not have '.dict' extension", + fuzz.dictionary.String()) + } + } } func NewFuzz(hod android.HostOrDeviceSupported) *Module { @@ -130,3 +157,95 @@ func NewFuzz(hod android.HostOrDeviceSupported) *Module { return module } + +// Responsible for generating GNU Make rules that package fuzz targets into +// their architecture & target/host specific zip file. +type fuzzPackager struct { + packages android.Paths +} + +func fuzzPackagingFactory() android.Singleton { + return &fuzzPackager{} +} + +type fileToZip struct { + SourceFilePath android.Path + DestinationPathPrefix string +} + +func (s *fuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { + // Map between each architecture + host/device combination, and the files that + // need to be packaged (in the tuple of {source file, destination folder in + // archive}). + archDirs := make(map[android.OutputPath][]fileToZip) + + ctx.VisitAllModules(func(module android.Module) { + // Discard non-fuzz targets. + ccModule, ok := module.(*Module) + if !ok { + return + } + fuzzModule, ok := ccModule.compiler.(*fuzzBinary) + if !ok { + return + } + + // Discard vendor-NDK-linked modules, they're duplicates of fuzz targets + // we're going to package anyway. + if ccModule.useVndk() || !ccModule.Enabled() { + return + } + + hostOrTargetString := "target" + if ccModule.Host() { + hostOrTargetString = "host" + } + + archString := ccModule.Arch().ArchType.String() + archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString) + + // The executable. + archDirs[archDir] = append(archDirs[archDir], + fileToZip{ccModule.outputFile.Path(), ccModule.Name()}) + + // The corpora. + for _, corpusEntry := range fuzzModule.corpus { + archDirs[archDir] = append(archDirs[archDir], + fileToZip{corpusEntry, ccModule.Name() + "/corpus/" + corpusEntry.Base()}) + } + + // The dictionary. + if fuzzModule.dictionary != nil { + archDirs[archDir] = append(archDirs[archDir], + fileToZip{fuzzModule.dictionary, ccModule.Name()}) + } + }) + + for archDir, filesToZip := range archDirs { + arch := archDir.Base() + hostOrTarget := filepath.Base(filepath.Dir(archDir.String())) + builder := android.NewRuleBuilder() + outputFile := android.PathForOutput(ctx, "fuzz-"+hostOrTarget+"-"+arch+".zip") + s.packages = append(s.packages, outputFile) + + command := builder.Command().BuiltTool(ctx, "soong_zip"). + Flag("-j"). + FlagWithOutput("-o ", outputFile) + + for _, fileToZip := range filesToZip { + command.FlagWithArg("-P ", fileToZip.DestinationPathPrefix). + FlagWithInput("-f ", fileToZip.SourceFilePath) + } + + builder.Build(pctx, ctx, "create-fuzz-package-"+arch+"-"+hostOrTarget, + "Create fuzz target packages for "+arch+"-"+hostOrTarget) + } +} + +func (s *fuzzPackager) MakeVars(ctx android.MakeVarsContext) { + // TODO(mitchp): Migrate this to use MakeVarsContext::DistForGoal() when it's + // ready to handle phony targets created in Soong. In the meantime, this + // exports the phony 'fuzz' target and dependencies on packages to + // core/main.mk so that we can use dist-for-goals. + ctx.Strict("SOONG_FUZZ_PACKAGING_ARCH_MODULES", strings.Join(s.packages.Strings(), " ")) +} |