blob: 91dbcb8e89dabf72433d45d8b66ff0f8f9c38375 [file] [log] [blame]
# Copyright 2019 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("$zx/public/gn/config/standard.gni")
import("$zx/public/gn/toolchain/environment.gni")
import("$zx/public/gn/toolchain/environment_redirect.gni")
# Lists the names of the default set of sanitized variants used to build fuzzer
# binaries. Named lists of useful variant subsets are defined in standard.gni,
# e.g. $standard_sanitizer_variants. If at some point the fuuzers should be
# built with a different set of default variants, the set of named lists should
# be changed there to minimize duplication of individual items here.
_fuzzer_default_variants = []
foreach(sanitizer, standard_sanitizer_variants) {
# Clear from last iteration.
_sanitizer_variant = {
}
_sanitizer_variant = sanitizer.variant
_fuzzer_default_variants += [ _sanitizer_variant.name ]
}
# Produces a component manifest similar to that produces by the $cmx()
# invocation in //build/fuzzing/fuzzer.gni. These manifests don't have
# much meaning in a standalone Zircon, but are most easily generated alongside
# the fuzzers.
template("_zx_fuzzer_cmx") {
assert(defined(invoker.name), "$target_name must define 'name'.")
fuzzer_name = "${invoker.name}.${toolchain.variant}"
generated_file(target_name) {
contents = {
program = {
binary = "bin/$fuzzer_name"
}
sandbox = {
services = [ "fuchsia.process.Launcher" ]
features = [
"isolated-persistent-storage",
"isolated-temp",
]
}
}
outputs = [ "$target_gen_dir/$fuzzer_name.cmx" ]
output_conversion = "json"
source = rebase_path(outputs[0], root_build_dir)
metadata = {
manifest_lines = [ "meta/$fuzzer_name.cmx=$source" ]
}
}
}
# Builds fuzzer binaries using the libFuzzer fuzzing engine.
#
# See [libFuzzer](https://llvm.org/docs/LibFuzzer.html) for background on
# libFuzzer. To create a fuzzer, developers should specify the code being
# fuzzed in $deps, and provide an "LLVMFuzzerTestOneInput" fuzz target
# function for libFuzzer in $sources.
#
# The zx_fuzzer() template below will build the fuzzer binary, link the engine, and
# instrument the $deps in an environment corresponding to an appropriate base
# environment. This means dependents on this target will get fuzzers for their
# base environment (e.g. host dependents will get host fuzzers, etc.).
#
# In order to be properly picked up by the //garnet/tests/zircon:zircon_fuzzers
# package, it is required that Zircon fuzzer names end in "-fuzzer", e.g. a
# fuzzer in $zx/system/ulib/foo might be named "foo-fuzzer".
#
# Parameters
#
# sanitizers
# Optional: A list of variant names as they appear in $variants. This
# controls which toolchain variants are used to build each fuzzer binary.
# This is only needed if a fuzzer should not be built with one or more of
# $fuzzer_default_variants.
# Type: list(string)
# Default: fuzzer_default_variants
#
# See executable() for additional parameters and details.
template("zx_fuzzer") {
# Match any "*.fuzzer" environment ("*" is ${toolchain.base_environment}).
if (get_path_info(toolchain.environment, "extension") == "fuzzer") {
fuzzer_name = target_name
# The test() template is used for programs that verify proper operation of
# associated code if the tests passes. This isn't an appropriate choice for
# fuzzers as they run indefinitely and never "pass".
zx_executable(fuzzer_name) {
testonly = true
# Explicitly forward visibility for nested scope, and ensure the redirect
# is always visible.
forward_variables_from(invoker,
"*",
[
"testonly",
"visibility",
])
forward_variables_from(invoker, [ "visibility" ])
if (defined(visibility)) {
visibility += [ ":$fuzzer_name" ]
}
data_deps = [ ":$fuzzer_name.cmx" ]
metadata = {
fuzzer = [ "$fuzzer_name.${toolchain.variant}" ]
}
}
_zx_fuzzer_cmx("$fuzzer_name.cmx") {
name = fuzzer_name
}
if (defined(invoker.sanitizers)) {
not_needed(invoker.sanitizers)
}
} else {
# Otherwise build sanitized variants in the fuzzer environment.
if (defined(invoker.sanitizers)) {
sanitizer_names = invoker.sanitizers
} else {
sanitizer_names = _fuzzer_default_variants
}
environment_redirect(target_name) {
testonly = true
forward_variables_from(invoker, [ "visibility" ])
environment_label =
"$zx/public/gn/fuzzer:${toolchain.base_environment}.fuzzer"
direct = true
deps = []
foreach(sanitizer, sanitizer_names) {
deps += [ ":$target_name.$sanitizer" ]
}
}
not_needed(invoker, "*")
}
}