1#!/usr/bin/env python3 2# 3# Copyright 2015 The Chromium Authors 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6"""Generate or update an existing config (.options file) for libfuzzer test. 7 8Invoked by GN from fuzzer_test.gni. 9""" 10 11import argparse 12import os 13import sys 14 15if sys.version_info.major == 2: 16 from ConfigParser import ConfigParser 17else: 18 from configparser import ConfigParser 19 20 21def AddSectionOptions(config, section_name, options): 22 """Add |options| to the |section_name| section of |config|. 23 24 Throws an 25 assertion error if any option in |options| does not have exactly two 26 elements. 27 """ 28 if not options: 29 return 30 31 config.add_section(section_name) 32 for option_and_value in options: 33 assert len(option_and_value) == 2, ('%s is not an option, value pair' % 34 option_and_value) 35 36 config.set(section_name, *option_and_value) 37 38 39def main(): 40 parser = argparse.ArgumentParser(description='Generate fuzzer config.') 41 parser.add_argument('--config', required=True) 42 parser.add_argument('--dict') 43 parser.add_argument('--libfuzzer_options', nargs='+', default=[]) 44 parser.add_argument('--centipede_options', nargs='+', default=[]) 45 parser.add_argument('--asan_options', nargs='+', default=[]) 46 parser.add_argument('--msan_options', nargs='+', default=[]) 47 parser.add_argument('--ubsan_options', nargs='+', default=[]) 48 parser.add_argument('--grammar_options', nargs='+', default=[]) 49 parser.add_argument('--environment_variables', 50 nargs='+', 51 default=[], 52 choices=['AFL_DRIVER_DONT_DEFER=1']) 53 args = parser.parse_args() 54 55 # Script shouldn't be invoked without any arguments, but just in case. 56 if not (args.dict or args.libfuzzer_options or args.environment_variables 57 or args.asan_options or args.msan_options or args.ubsan_options 58 or args.grammar_options): 59 return 60 61 config = ConfigParser() 62 libfuzzer_options = [] 63 if args.dict: 64 libfuzzer_options.append(('dict', os.path.basename(args.dict))) 65 libfuzzer_options.extend( 66 option.split('=') for option in args.libfuzzer_options) 67 68 AddSectionOptions(config, 'libfuzzer', libfuzzer_options) 69 70 centipede_options = [] 71 if args.dict: 72 centipede_options.append(('dictionary', os.path.basename(args.dict))) 73 centipede_options.extend( 74 option.split('=') for option in args.centipede_options) 75 AddSectionOptions(config, 'centipede', centipede_options) 76 77 AddSectionOptions(config, 'asan', 78 [option.split('=') for option in args.asan_options]) 79 80 AddSectionOptions(config, 'msan', 81 [option.split('=') for option in args.msan_options]) 82 83 AddSectionOptions(config, 'ubsan', 84 [option.split('=') for option in args.ubsan_options]) 85 86 AddSectionOptions(config, 'grammar', 87 [option.split('=') for option in args.grammar_options]) 88 89 AddSectionOptions( 90 config, 'env', 91 [option.split('=') for option in args.environment_variables]) 92 93 # Generate .options file. 94 config_path = args.config 95 with open(config_path, 'w') as options_file: 96 options_file.write( 97 '# This is an automatically generated config for ClusterFuzz.\n') 98 config.write(options_file) 99 100 101if __name__ == '__main__': 102 main() 103