|  | # 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/cpp/fidl_cpp.gni") | 
|  | import("//build/host.gni") | 
|  | import("//build/package.gni") | 
|  | import("//build/test.gni") | 
|  |  | 
|  | # TODO(aarongreen): SEC-224.  Add tests to catch fuzzer building/packaging | 
|  | # regressions. | 
|  |  | 
|  | # Defines a fuzzer binary. | 
|  | # | 
|  | # The fuzzer template is used to create components containing binaries which leverage LLVM's | 
|  | # libFuzzer to perform fuzz testing. | 
|  | # | 
|  | # Parameters are precisely those of an `executable`, along with: | 
|  | # | 
|  | #   cmx (optional) | 
|  | #     [file] If specified, a file containing a component manifest to start from when generating | 
|  | #       manifests for fuzzers. | 
|  | # | 
|  | #   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") { | 
|  | base_output_name = target_name | 
|  | if (defined(invoker.output_name)) { | 
|  | base_output_name = invoker.output_name | 
|  | } | 
|  |  | 
|  | # Generate the component binary | 
|  | executable(target_name) { | 
|  | forward_variables_from(invoker, | 
|  | "*", | 
|  | [ | 
|  | "cmx", | 
|  | "corpus", | 
|  | "dictionary", | 
|  | "options", | 
|  | "visibility", | 
|  | ]) | 
|  |  | 
|  | # Explicitly forward visibility for nested scopes. | 
|  | forward_variables_from(invoker, [ "visibility" ]) | 
|  | testonly = true | 
|  | _target_type = "fuzzed_executable" | 
|  | } | 
|  |  | 
|  | # Generate the fuzzer component manifest | 
|  | cmx_target = "${target_name}_cmx" | 
|  | cmx_output = "$target_gen_dir/${base_output_name}.cmx" | 
|  | generated_file(cmx_target) { | 
|  | if (defined(invoker.cmx)) { | 
|  | cmx = read_file(invoker.cmx, "json") | 
|  | } else { | 
|  | cmx = { | 
|  | program = { | 
|  | } | 
|  | sandbox = { | 
|  | } | 
|  | } | 
|  | } | 
|  | contents = { | 
|  | program = { | 
|  | forward_variables_from(cmx.program, "*") | 
|  | binary = "bin/$base_output_name" | 
|  | } | 
|  | sandbox = { | 
|  | services = [] | 
|  | features = [] | 
|  | forward_variables_from(cmx.sandbox, "*") | 
|  | services += [ "fuchsia.process.Launcher" ] | 
|  | features += [ | 
|  | "isolated-persistent-storage", | 
|  | "isolated-temp", | 
|  | ] | 
|  | } | 
|  | forward_variables_from(cmx, | 
|  | [ | 
|  | "dev", | 
|  | "runner", | 
|  | "facets", | 
|  | ]) | 
|  | } | 
|  | outputs = [ cmx_output ] | 
|  | output_conversion = "json" | 
|  | } | 
|  |  | 
|  | # Generate seed corpus. See https://llvm.org/docs/LibFuzzer.html#corpus | 
|  | # TODO(fxb/58940): Move away from invoking add_corpus.py and towards using | 
|  | # in-tree corpus manifests. | 
|  | corpus_target = "${target_name}_corpus" | 
|  | corpus_output = "${target_gen_dir}/${base_output_name}/corpus.manifest" | 
|  | action(corpus_target) { | 
|  | script = "//build/fuzzing/add_corpus.py" | 
|  | depfile = "$corpus_output.d" | 
|  | outputs = [ corpus_output ] | 
|  | args = [ | 
|  | "--fuzzer", | 
|  | base_output_name, | 
|  | "--depfile", | 
|  | rebase_path(depfile, root_build_dir), | 
|  | "--manifest", | 
|  | rebase_path(corpus_output, root_build_dir), | 
|  | ] | 
|  | if (defined(invoker.corpus)) { | 
|  | args += [ | 
|  | "--corpus", | 
|  | rebase_path(invoker.corpus, root_build_dir), | 
|  | ] | 
|  | } | 
|  | } | 
|  |  | 
|  | # Generate dictionary. See https://llvm.org/docs/LibFuzzer.html#dictionaries | 
|  | dictionary_target = "${target_name}_dictionary" | 
|  | dictionary_output = "${target_gen_dir}/${base_output_name}/dictionary" | 
|  | if (defined(invoker.dictionary)) { | 
|  | copy(dictionary_target) { | 
|  | sources = [ invoker.dictionary ] | 
|  | outputs = [ dictionary_output ] | 
|  | } | 
|  | } else { | 
|  | generated_file(dictionary_target) { | 
|  | contents = [ "# empty dictionary" ] | 
|  | outputs = [ dictionary_output ] | 
|  | } | 
|  | } | 
|  |  | 
|  | # Generate options. See https://llvm.org/docs/LibFuzzer.html#options | 
|  | options_target = "${target_name}_options" | 
|  | options_output = "${target_gen_dir}/${base_output_name}/options" | 
|  | generated_file(options_target) { | 
|  | contents = [] | 
|  | if (defined(invoker.options)) { | 
|  | contents = invoker.options | 
|  | } | 
|  | outputs = [ options_output ] | 
|  | } | 
|  |  | 
|  | # Generate a unit test for the fuzzer. | 
|  | test_target = "${target_name}_test" | 
|  | test_output = "${base_output_name}_test" | 
|  | test(test_target) { | 
|  | output_name = test_output | 
|  | sources = [] | 
|  | deps = [] | 
|  | forward_variables_from(invoker, | 
|  | "*", | 
|  | [ | 
|  | "cmx", | 
|  | "corpus", | 
|  | "dictionary", | 
|  | "options", | 
|  | "output_name", | 
|  | "target_name", | 
|  | "visibility", | 
|  | ]) | 
|  |  | 
|  | # Explicitly forward visibility for nested scopes. | 
|  | forward_variables_from(invoker, [ "visibility" ]) | 
|  | deps += [ | 
|  | ":$corpus_target", | 
|  | "//src/lib/fuzzing/cpp:fuzzer_test", | 
|  | ] | 
|  | } | 
|  |  | 
|  | # Generate the fuzzer test component manifest | 
|  | test_cmx_target = "${test_target}_cmx" | 
|  | test_cmx_output = "$target_gen_dir/${test_output}.cmx" | 
|  | generated_file(test_cmx_target) { | 
|  | contents = { | 
|  | program = { | 
|  | binary = "test/$test_output" | 
|  | args = [ | 
|  | # Suppress warnings about missing directories | 
|  | "-q", | 
|  |  | 
|  | # Seed corpus | 
|  | "pkg/data/${base_output_name}/corpus", | 
|  |  | 
|  | # Live corpus | 
|  | "data/${base_output_name}/corpus", | 
|  | ] | 
|  | } | 
|  | sandbox = { | 
|  | services = [ "fuchsia.logger.LogSink" ] | 
|  | } | 
|  | } | 
|  | outputs = [ test_cmx_output ] | 
|  | output_conversion = "json" | 
|  | deps = [] | 
|  | } | 
|  | } | 
|  |  | 
|  | # See https://llvm.org/docs/LibFuzzer.html#fuzzer-friendly-build-mode | 
|  | set_defaults("fuzzer") { | 
|  | configs = default_executable_configs + | 
|  | [ "//build/fuzzing:fuzzing_build_mode_unsafe_for_production" ] | 
|  | } | 
|  |  | 
|  | # TODO(48118): Add LSan | 
|  | _cpp_sanitizers = [ | 
|  | "asan", | 
|  | "ubsan", | 
|  | ] | 
|  |  | 
|  | # Currently, Go doesn't have any *San specific callbacks beyond those in the dynamic linker. Still, | 
|  | # all of the C/C++ sanitizers should link and run. | 
|  | _go_sanitizers = _cpp_sanitizers | 
|  |  | 
|  | _rust_sanitizers = [ "asan" ] | 
|  |  | 
|  | # Defines a package of fuzzers | 
|  | # | 
|  | # The `fuzzers_package` template is used to bundle several fuzzers and their associated data into a | 
|  | # single Fuchsia package. See //examples/fuzzer/BUILD.gn for examples. | 
|  | # | 
|  | # Parameters | 
|  | #   fuzz_host (optional) | 
|  | #     [boolean] Indicates whether to also build fuzzer binaries on host. Defaults to false. | 
|  | # | 
|  | #   host_only (optional) | 
|  | #     [boolean] Indicates whether to skip the Fuchsia fuzzers package. Implies `fuzz_host`. | 
|  | #     Defaults to false. | 
|  | # | 
|  | #   fuzzers (optional) | 
|  | #   cpp_fuzzers (optional) | 
|  | #   go_fuzzers (optional) | 
|  | #   rust_fuzzers (optional) | 
|  | #     [list] A list of fuzzers for targets in the indicated language. Each list is asscoiated with | 
|  | #       the corresponding list of sanitizers, e.g. each label in `cpp_fuzzers` is built as a fuzzer | 
|  | #       when the toolchain variant selected for that label matches an element of `_cpp_sanitizers`. | 
|  | #       `fuzzers` (with no language prefix) imples C++, and is folded into `cpp_fuzzers`. | 
|  | # | 
|  | #       Each element of `fuzzers` is either a label or a scope. Label elements act as "shortcuts" | 
|  | #       that use default values for each field in a scope element. The scope elements can include | 
|  | #       the following fields: | 
|  | # | 
|  | #         label (required) | 
|  | #           [label] The fuzzer() target to include. | 
|  | # | 
|  | #         name (optional) | 
|  | #         output_name (optional) | 
|  | #           [string] Same as for fuzzer(), and should match the value(s) for the associated `label`. | 
|  | #           For label elements, these are both set to simple name of the label. | 
|  | # | 
|  | #         sanitizers (optional) | 
|  | #           [list of strings] Overrides the default, per-language sanitizers. This should be omitted | 
|  | #           unless necessary. | 
|  | # | 
|  | #       fuzz_host (optional) | 
|  | #         [boolean] Overrides the value of `fuzz_host` in the outer scope. | 
|  | # | 
|  | #       host_only (optional) | 
|  | #         [boolean] Overrides the value of `host_only` in the outer scope. | 
|  | # | 
|  | #   fuzzers_manifest (optional) | 
|  | #     [scope] Specifies how to read fuzzer names from a manifest file. This parameter is useful for | 
|  | #     including fuzzers from another build, e.g. pre-unification Zircon fuzzers. The scope has two | 
|  | #     fields: | 
|  | # | 
|  | #        target (required) | 
|  | #           [label] The GN target that produces the manifest. | 
|  | # | 
|  | #        output (required) | 
|  | #           [path] The path to the generated manifest file. | 
|  | # | 
|  | #   meta (optional) | 
|  | #   binaries (optional) | 
|  | #   components (optional) | 
|  | #   tests (optional) | 
|  | #   drivers (optional) | 
|  | #   loadable_modules (optional) | 
|  | #   resources (optional) | 
|  | #   extra (optional) | 
|  | #     Same meanings as in //build/package.gni | 
|  | # | 
|  | #   deps (optional) | 
|  | #   public_deps (optional) | 
|  | #   data_deps (optional) | 
|  | #     Usual GN meanings. | 
|  | template("fuzzers_package") { | 
|  | # This target will create a group with up to three parts: a package of fuzzers and/or fuzzer | 
|  | # tests, a set of host fuzzers treated as host tools, and a group of host fuzzer tests. Which | 
|  | # fuzzers are included in each part depends of the associated fuzzer profile and current | 
|  | # toolchain variant. | 
|  | group_target_name = target_name | 
|  | group_deps = [] | 
|  |  | 
|  | # Step 1: Gather up lists of fuzzers by language, and associated them with that language's | 
|  | # sanitizers. | 
|  | by_language = [] | 
|  | invoker_fuzz_host = defined(invoker.fuzz_host) && invoker.fuzz_host | 
|  | invoker_host_only = defined(invoker.host_only) && invoker.host_only | 
|  | if (defined(invoker.fuzzers)) { | 
|  | by_language += [ | 
|  | { | 
|  | fuzzers = invoker.fuzzers | 
|  | fuzz_host = invoker_fuzz_host | 
|  | host_only = invoker_host_only | 
|  | sanitizers = _cpp_sanitizers | 
|  | }, | 
|  | ] | 
|  | } | 
|  | if (defined(invoker.cpp_fuzzers)) { | 
|  | by_language += [ | 
|  | { | 
|  | fuzzers = invoker.cpp_fuzzers | 
|  | fuzz_host = invoker_fuzz_host | 
|  | host_only = invoker_host_only | 
|  | sanitizers = _cpp_sanitizers | 
|  | }, | 
|  | ] | 
|  | } | 
|  | if (defined(invoker.go_fuzzers)) { | 
|  | not_needed([ | 
|  | "invoker_fuzz_host", | 
|  | "invoker_host_only", | 
|  | ]) | 
|  | by_language += [ | 
|  | { | 
|  | fuzzers = invoker.go_fuzzers | 
|  |  | 
|  | # TODO(44551): go host fuzzers fail to link on mac-x64 | 
|  | fuzz_host = false | 
|  | host_only = false | 
|  | sanitizers = _go_sanitizers | 
|  | }, | 
|  | ] | 
|  | } | 
|  | if (defined(invoker.rust_fuzzers)) { | 
|  | not_needed([ | 
|  | "invoker_fuzz_host", | 
|  | "invoker_host_only", | 
|  | ]) | 
|  | by_language += [ | 
|  | { | 
|  | fuzzers = invoker.rust_fuzzers | 
|  |  | 
|  | # TODO(48624): rustc segfaults when building hostlibs. | 
|  | fuzz_host = false | 
|  | host_only = false | 
|  | sanitizers = _rust_sanitizers | 
|  | }, | 
|  | ] | 
|  | } | 
|  | assert(by_language != [], "no fuzzers specified") | 
|  |  | 
|  | # Step 2: "Normalize" the fuzzers by making each one into a scope with the same fields. | 
|  | normalized = [] | 
|  | foreach(language, by_language) { | 
|  | foreach(fuzzer, language.fuzzers) { | 
|  | if (fuzzer == "$fuzzer") { | 
|  | fuzzer = { | 
|  | label = fuzzer | 
|  | } | 
|  | } else { | 
|  | assert(defined(fuzzer.label), "missing fuzzer label") | 
|  | } | 
|  | normalized += [ | 
|  | { | 
|  | # Convert labels to scopes, if needed | 
|  | label = get_label_info(fuzzer.label, "label_no_toolchain") | 
|  |  | 
|  | # Get the name early in order to set the default `output_name`. | 
|  | if (defined(fuzzer.name)) { | 
|  | name = fuzzer.name | 
|  | } else { | 
|  | name = get_label_info(label, "name") | 
|  | } | 
|  |  | 
|  | # Set defaults | 
|  | output_name = name | 
|  | forward_variables_from(language, "*", [ "fuzzers" ]) | 
|  |  | 
|  | # Allow overrides | 
|  | forward_variables_from(fuzzer, | 
|  | "*", | 
|  | [ | 
|  | "label", | 
|  | "name", | 
|  | ]) | 
|  | }, | 
|  | ] | 
|  | } | 
|  | } | 
|  |  | 
|  | # Step 3: Assign each fuzzer to one or more of the following by matching the fuzzer scope against | 
|  | # the currently selected toolchain variants: | 
|  | #  - A fuzzers package, either as binaries or unit tests | 
|  | #  - A set of host fuzzer tools | 
|  | #  - A set of host unit tests for the host fuzzer tools | 
|  | fuzzed = [] | 
|  | tested = [] | 
|  | host_fuzzed = [] | 
|  | host_tested = [] | 
|  | foreach(fuzzer, normalized) { | 
|  | fuzz = false | 
|  |  | 
|  | # Compare each selected variant with a profile's supported sanitizers. Unselected fuzzers are | 
|  | # built as uninstrumented unit tests instead; see `test("${fuzzer_name}_test")` above. | 
|  | foreach(selector, select_variant_canonical) { | 
|  | foreach(sanitizer, fuzzer.sanitizers) { | 
|  | if (!fuzz && selector.variant == "${sanitizer}-fuzzer") { | 
|  | fuzz = | 
|  | (defined(selector.target_type) && | 
|  | selector.target_type == [ "fuzzed_executable" ]) || | 
|  | (defined(selector.output_name) && | 
|  | selector.output_name == [ fuzzer.output_name ]) || | 
|  | (defined(selector.label) && selector.label == [ fuzzer.label ]) || | 
|  | (defined(selector.name) && selector.name == [ fuzzer.name ]) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | # Add the fuzzers and tests from this profile to the aggregated lists. | 
|  | if (!fuzzer.host_only) { | 
|  | if (fuzz) { | 
|  | fuzzed += [ fuzzer ] | 
|  | } else { | 
|  | tested += [ fuzzer ] | 
|  | } | 
|  | } | 
|  | if (fuzzer.fuzz_host || fuzzer.host_only) { | 
|  | if (fuzz) { | 
|  | host_fuzzed += [ fuzzer ] | 
|  | } else { | 
|  | host_tested += [ fuzzer ] | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | # Fuzzers imported via manifest are always selected. | 
|  | forward_variables_from(invoker, [ "fuzzers_manifest" ]) | 
|  | prebuilt_fuzzed = [] | 
|  | if (defined(fuzzers_manifest)) { | 
|  | prebuilt_fuzzed += read_file(fuzzers_manifest.output, "json") | 
|  | } | 
|  |  | 
|  | # Step 4: Assemble a Fuchsia package of fuzzers and/or unit tests. Many of the package parameter | 
|  | # values need to match the '*_target' and '*_output' values in the `fuzzer` template above. | 
|  | # Ideally this would use `get_target_outputs` to only need the former, but fuzzers and packages | 
|  | # are not required to be defined in the same GN file. | 
|  | if (fuzzed != [] || prebuilt_fuzzed != [] || tested != []) { | 
|  | package_target_name = target_name + "_pkg" | 
|  | package(package_target_name) { | 
|  | package_name = group_target_name | 
|  | testonly = true | 
|  | visibility = [ ":*" ] | 
|  |  | 
|  | # Allow callers to set most package parameters. | 
|  | meta = [] | 
|  | binaries = [] | 
|  | tests = [] | 
|  | resources = [] | 
|  | extra = [] | 
|  | deps = [] | 
|  | forward_variables_from(invoker, | 
|  | "*", | 
|  | [ | 
|  | "fuzzers", | 
|  | "fuzzers_manifest", | 
|  | "fuzzer_profiles", | 
|  | "metadata", | 
|  | "sanitizers", | 
|  | "testonly", | 
|  | "visibility", | 
|  | ]) | 
|  |  | 
|  | # Add selected fuzzers. | 
|  | output_names = [] | 
|  | foreach(fuzzer, fuzzed) { | 
|  | fuzzer_path = get_label_info(fuzzer.label, "target_gen_dir") | 
|  | meta += [ | 
|  | { | 
|  | path = "${fuzzer_path}/${fuzzer.output_name}.cmx" | 
|  | dest = "${fuzzer.output_name}.cmx" | 
|  | }, | 
|  | ] | 
|  | binaries += [ | 
|  | { | 
|  | name = "${fuzzer.output_name}" | 
|  | }, | 
|  | ] | 
|  | extra += [ "${fuzzer_path}/${fuzzer.output_name}/corpus.manifest" ] | 
|  | resources += [ | 
|  | { | 
|  | path = "${fuzzer_path}/${fuzzer.output_name}/dictionary" | 
|  | dest = "${fuzzer.output_name}/dictionary" | 
|  | }, | 
|  | { | 
|  | path = "${fuzzer_path}/${fuzzer.output_name}/options" | 
|  | dest = "${fuzzer.output_name}/options" | 
|  | }, | 
|  | ] | 
|  | deps += [ | 
|  | "${fuzzer.label}", | 
|  | "${fuzzer.label}_cmx", | 
|  | "${fuzzer.label}_corpus", | 
|  | "${fuzzer.label}_dictionary", | 
|  | "${fuzzer.label}_options", | 
|  | ] | 
|  | output_names += [ fuzzer.output_name ] | 
|  | } | 
|  | foreach(fuzzer, prebuilt_fuzzed) { | 
|  | output_names += [ get_label_info(fuzzer, "name") ] | 
|  | } | 
|  |  | 
|  | # Add fuzzer tests for those not selected. | 
|  | foreach(fuzzer, tested) { | 
|  | fuzzer_path = get_label_info(fuzzer.label, "target_gen_dir") | 
|  | meta += [ | 
|  | { | 
|  | path = "${fuzzer_path}/${fuzzer.output_name}_test.cmx" | 
|  | dest = "${fuzzer.output_name}_test.cmx" | 
|  | }, | 
|  | ] | 
|  | tests += [ | 
|  | { | 
|  | name = "${fuzzer.output_name}_test" | 
|  |  | 
|  | # Fuzzers may produce errors so long as they do not crash. | 
|  | log_settings = { | 
|  | max_severity = "ERROR" | 
|  | } | 
|  | }, | 
|  | ] | 
|  | extra += [ "${fuzzer_path}/${fuzzer.output_name}/corpus.manifest" ] | 
|  | deps += [ | 
|  | "${fuzzer.label}_corpus", | 
|  | "${fuzzer.label}_test", | 
|  | "${fuzzer.label}_test_cmx", | 
|  | ] | 
|  | } | 
|  |  | 
|  | if (defined(fuzzers_manifest)) { | 
|  | deps += [ fuzzers_manifest.target ] | 
|  | extra += get_target_outputs(fuzzers_manifest.target) | 
|  | } | 
|  |  | 
|  | # This metadata will be used to generate out/default/fuzzers.json | 
|  | metadata = { | 
|  | if (defined(invoker.metadata)) { | 
|  | forward_variables_from(invoker.metadata, "*", [ "fuzz_spec" ]) | 
|  | } | 
|  | fuzz_spec = [ | 
|  | { | 
|  | fuzzers_package = package_name | 
|  | fuzzers = output_names | 
|  | }, | 
|  | ] | 
|  | } | 
|  | } | 
|  | group_deps += [ ":$package_target_name" ] | 
|  | } | 
|  |  | 
|  | # Step 5: Treat host fuzzers as tools. If we get to the point of having name collisions, we'll | 
|  | # need to extend `install_host_tools` to allow copying to specific subdirectories of | 
|  | # `host_tools_dir`. | 
|  | if (host_fuzzed != []) { | 
|  | host_fuzzers_target_name = target_name + "_host" | 
|  | install_host_tools(host_fuzzers_target_name) { | 
|  | testonly = true | 
|  | visibility = [ ":*" ] | 
|  | deps = [] | 
|  | outputs = [] | 
|  | foreach(fuzzer, host_fuzzed) { | 
|  | deps += [ | 
|  | "${fuzzer.label}", | 
|  | "${fuzzer.label}_corpus", | 
|  | ] | 
|  | outputs += [ fuzzer.output_name ] | 
|  | } | 
|  | } | 
|  | group_deps += [ ":$host_fuzzers_target_name" ] | 
|  | } | 
|  |  | 
|  | # Step 6: For host fuzzer tests, ensure the deps build with the correct toolchain. | 
|  | if (host_tested != []) { | 
|  | host_tests_target_name = target_name + "_host_tests" | 
|  | group(host_tests_target_name) { | 
|  | testonly = true | 
|  | visibility = [ ":*" ] | 
|  | deps = [] | 
|  | foreach(fuzzer, host_tested) { | 
|  | deps += [ "${fuzzer.label}_test($host_toolchain)" ] | 
|  | } | 
|  | } | 
|  | group_deps += [ ":$host_tests_target_name" ] | 
|  | } | 
|  |  | 
|  | # Step 7: Include everything in the group | 
|  | group(group_target_name) { | 
|  | forward_variables_from(invoker, [ "visibility" ]) | 
|  | testonly = true | 
|  | deps = group_deps | 
|  | } | 
|  | } | 
|  |  | 
|  | # Defines service provider for a generated FIDL fuzzer | 
|  | # | 
|  | # The fidl() template supports a list of `fuzzers` that contain a `protocol` | 
|  | # string and optional list of `methods`. Each of the fidl()'s `fuzzers` | 
|  | # generates a library target of the form: | 
|  | # | 
|  | # [fidl() target name]_libfuzzer_[protocol]_[method1 name]_[method2 name]... | 
|  | # | 
|  | # The target contains the core fuzzer logic, but relies on symbols that must be | 
|  | # defined by the FIDL service implementer for providing an instance of the | 
|  | # service to fuzz. | 
|  | # | 
|  | # This template is a helper for tying together the above-mentioned target and | 
|  | # the sources and/or deps necessary to provide the above-mentioned symbols. | 
|  | # | 
|  | # NOTE: The `protocol` and `methods` passed to this template must _exactly_ | 
|  | # match one of the `fuzzers` defined on the corresponding fidl() rule. | 
|  | # | 
|  | # Parameters | 
|  | # | 
|  | #   fidl (required) | 
|  | #     [label] The `fidl()` label that includes the protocol to be fuzzed. | 
|  | # | 
|  | #   protocol (required) | 
|  | #     [fully-qualified FIDL protocol name] The fully-qualified name of the FIDL | 
|  | #     protocol to be fuzzed. | 
|  | # | 
|  | #   methods (optional) | 
|  | #     [list of strings] The names of the methods to be fuzzed, as they appear in | 
|  | #     the FIDL file. These are translated into defines that enable fuzzing code | 
|  | #     for the appropriate methods. Defaults to special define value for fuzzing | 
|  | #     all methods of the specified protocol. | 
|  | # | 
|  | # Other parameters are precisely those of an `executable`, with their usual GN | 
|  | # meanings; these parameters are forwarded to the generated fuzzer() template. | 
|  | template("fidl_protocol_fuzzer") { | 
|  | assert( | 
|  | defined(invoker.protocol), | 
|  | "FIDL fuzzer service provider must set protocol: the fully-qualified name of the protocol to be fuzzed.") | 
|  | assert( | 
|  | defined(invoker.fidl), | 
|  | "FIDL fuzzer service provider must set fidl: the fidl() target defining the corresponding fuzzer.") | 
|  |  | 
|  | protocol_suffix = string_replace(invoker.protocol, ".", "_") | 
|  | if (defined(invoker.methods)) { | 
|  | foreach(method, invoker.methods) { | 
|  | protocol_suffix = "${protocol_suffix}_${method}" | 
|  | } | 
|  | } | 
|  |  | 
|  | if (defined(invoker.deps)) { | 
|  | fuzzer_deps = invoker.deps | 
|  | } else { | 
|  | fuzzer_deps = [] | 
|  | } | 
|  | fuzzer_deps += [ | 
|  | "${invoker.fidl}_libfuzzer_${protocol_suffix}", | 
|  | "//sdk/lib/fidl/cpp/fuzzing", | 
|  | ] | 
|  |  | 
|  | fuzzer(target_name) { | 
|  | forward_variables_from(invoker, | 
|  | [ | 
|  | "aliased_deps", | 
|  | "all_dependent_configs", | 
|  | "asmflags", | 
|  | "cflags_c", | 
|  | "cflags_cc", | 
|  | "cflags_objc", | 
|  | "cflags_objcc", | 
|  | "cflags", | 
|  | "check_includes", | 
|  | "cmx", | 
|  | "configs", | 
|  | "crate_name", | 
|  | "crate_root", | 
|  | "data_deps", | 
|  | "data", | 
|  | "dictionary", | 
|  | "edition", | 
|  | "friend", | 
|  | "include_dirs", | 
|  | "inputs", | 
|  | "inputs", | 
|  | "ldflags", | 
|  | "lib_dirs", | 
|  | "libs", | 
|  | "metadata", | 
|  | "options", | 
|  | "output_extension", | 
|  | "output_name", | 
|  | "precompiled_header", | 
|  | "precompiled_source", | 
|  | "public_configs", | 
|  | "public_deps", | 
|  | "public", | 
|  | "rustenv", | 
|  | "rustflags", | 
|  | "sources", | 
|  | "testonly", | 
|  | "visibility", | 
|  | ]) | 
|  | deps = fuzzer_deps | 
|  | } | 
|  | } |