| # 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") | 
 |  | 
 | # 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" ] | 
 |     variant_selector_target_type = "fuzzer_test_executable" | 
 |   } | 
 |   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" ] | 
 | } |