blob: ff6bff7d3bb6f4ca25ab0ebdd64f37dda77cc0f5 [file] [log] [blame]
# Copyright 2018 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/fuzzing/fuzzer_component.gni")
import("//build/fuzzing/fuzzer_corpus.gni")
import("//build/fuzzing/fuzzer_dictionary.gni")
import("//build/fuzzing/fuzzer_test_component.gni")
import("//build/test.gni")
# TODO(fxbug.dev/60168): Consumers should import fuzzer_package explicitly. Remove once all are
# migrated.
import("//build/fuzzing/fuzzer_package.gni")
# A list of configs present in fuzzer toolchain variants.
#
# GN logic that needs to behave differently between fuzzer and non-fuzzer variants can determine the
# variant type by checking the `toolchain_variant.configs`, e.g.
# if (toolchain_variant.configs + fuzzer_configs - fuzzer_configs == toolchain_variant.configs) {
# # Not using a fuzzer toolchain variant.
# } else {
# # Using a fuzzer toolchain variant.
# }
#
# This approach works even with the way `import` caches this file.
#
fuzzer_configs = [ "//build/config/fuzzer" ]
# Defines a fuzzer binary.
#
# The fuzzer template is used to create components containing binaries which leverage LLVM's
# libFuzzer to perform fuzz testing. It also creates a unit test that exercises the fuzzer code
# without libFuzzer, simply trying each corpus element without mutation.
#
# Parameters are precisely those of an `executable`, along with:
#
# corpus (optional)
# [path] If specified, a directory containing elements of a seed corpus. These should be a
# combination of hand-crafted fuzzer inputs that increase coverage, and artifacts from
# previous fuzzing runs, e.g. fuzzer inputs that triggered crashes. These will be used to seed
# new fuzzing runs, and as regression unit tests.
#
# dictionary (optional)
# [file] If specified, a file containing quoted inputs, one per line, that the fuzzer will use
# to generate new mutations.
#
# features, services (optional)
# [list of strings] Extra (v1) sandbox features/services for the fuzzer and test components.
#
# options (optional)
# [list of strings] Each option is of the form "key=value" and indicates command line options
# that the fuzzer should be invoked with. Valid keys are libFuzzer options
# (https://llvm.org/docs/LibFuzzer.html#options).
#
template("fuzzer") {
# Dummy target to catch incorrect dependencies. If fuzzer_package is not used, the executable
# won't ever be built with proper instrumentation.
#
# If a GN error led you here, you probably have a group with a dep on a `fuzzer("...")` target.
# You should include those deps in a `fuzzer_package` instead, and depend on that. This will
# ensure things are built correctly when a supported fuzzing variant toolchain is selected.
#
# See https://fuchsia.dev/fuchsia-src/development/testing/fuzzing/build-a-fuzzer for more info.
group(target_name) {
visibility = []
}
# The component target names MUST match the deps of the package created by the `fuzzer_package`
# GN template in //build/fuzzing/fuzzer_package.gni. That template dispatches these targets to the
# correct toolchain variant, and references them by constructing these names.
component_target = "${target_name}_component"
component_deps = []
test_component_target = "${target_name}_test_component"
test_component_deps = []
if (defined(invoker.output_name)) {
fuzzer_name = invoker.output_name
} else {
fuzzer_name = target_name
}
fuzzer_label = get_label_info(":$target_name", "label_no_toolchain")
# Explicitly forward visibility for nested scopes. Visibility is forwarded for both components and
# binaries, as the latter may be copied directly as host tools.
exclude_from_mass_forwards = [
"corpus",
"dictionary",
"features",
"options",
"output_name",
"services",
"target_name",
"visibility",
]
# Generate fuzzer resources with metadata.
if (defined(invoker.corpus)) {
corpus_target = "${target_name}_corpus"
fuzzer_corpus(corpus_target) {
label = fuzzer_label
corpus = invoker.corpus
}
component_deps += [ ":$corpus_target" ]
test_component_deps += [ ":$corpus_target" ]
}
if (defined(invoker.dictionary)) {
dictionary_target = "${target_name}_dictionary"
fuzzer_dictionary(dictionary_target) {
label = fuzzer_label
fuzzer = fuzzer_name
dictionary = invoker.dictionary
}
component_deps += [ ":$dictionary_target" ]
}
# Generate the fuzzer binary and component.
executable_target = "${target_name}_executable"
executable_output = fuzzer_name
executable(executable_target) {
deps = []
forward_variables_from(invoker, "*", exclude_from_mass_forwards)
forward_variables_from(invoker, [ "visibility" ])
variant_selector_target_type = "fuzzed_executable"
output_name = executable_output
testonly = true
# TODO(fxbug.dev/27011): This shouldn't be necessary, but libzircon isn't currently linked into
# libFuzzer on Fuchsia.
if (is_fuchsia) {
deps += [ "//src/zircon/lib/zircon" ]
}
}
component_deps += [ ":$executable_target" ]
fuzzer_component(component_target) {
forward_variables_from(invoker,
[
"features",
"options",
"services",
"visibility",
])
fuzzer = fuzzer_name
label = fuzzer_label
deps = component_deps
}
# Generate the fuzzer test binary and component.
test_executable_target = "${target_name}_test_executable"
test_executable_output = "${fuzzer_name}_test"
test(test_executable_target) {
deps = []
forward_variables_from(invoker, "*", exclude_from_mass_forwards)
forward_variables_from(invoker, [ "visibility" ])
output_name = test_executable_output
configs -= [ "//build/config/fuzzer:engine" ]
deps += [ "//src/lib/fuzzing/cpp:fuzzer_test" ]
}
test_component_deps += [ ":$test_executable_target" ]
fuzzer_test_component(test_component_target) {
forward_variables_from(invoker,
[
"features",
"corpus",
"services",
"visibility",
])
fuzzer = fuzzer_name
label = fuzzer_label
deps = test_component_deps
}
}
set_defaults("fuzzer") {
configs = default_executable_configs + [ "//build/config/fuzzer:engine" ]
}