summaryrefslogtreecommitdiff
path: root/cc/fuzz.go
diff options
context:
space:
mode:
Diffstat (limited to 'cc/fuzz.go')
-rw-r--r--cc/fuzz.go123
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(), " "))
+}