| # 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. |
| # |
| # 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", |
| "options", |
| "output_name", |
| "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, |
| [ |
| "options", |
| "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, |
| [ |
| "corpus", |
| "visibility", |
| ]) |
| fuzzer = fuzzer_name |
| label = fuzzer_label |
| deps = test_component_deps |
| } |
| } |
| |
| set_defaults("fuzzer") { |
| configs = default_executable_configs + [ "//build/config/fuzzer:engine" ] |
| } |