13f085823Sopenharmony_ci#!/usr/bin/env python
23f085823Sopenharmony_ci# -*- coding:utf-8 -*-
33f085823Sopenharmony_ci#
43f085823Sopenharmony_ci# Copyright (c) 2021 Huawei Device Co., Ltd.
53f085823Sopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License");
63f085823Sopenharmony_ci# you may not use this file except in compliance with the License.
73f085823Sopenharmony_ci# You may obtain a copy of the License at
83f085823Sopenharmony_ci#
93f085823Sopenharmony_ci#     http://www.apache.org/licenses/LICENSE-2.0
103f085823Sopenharmony_ci#
113f085823Sopenharmony_ci# Unless required by applicable law or agreed to in writing, software
123f085823Sopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS,
133f085823Sopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
143f085823Sopenharmony_ci# See the License for the specific language governing permissions and
153f085823Sopenharmony_ci# limitations under the License.
163f085823Sopenharmony_ci#
173f085823Sopenharmony_ci
183f085823Sopenharmony_cifrom __future__ import print_function
193f085823Sopenharmony_ciimport argparse
203f085823Sopenharmony_ciimport os
213f085823Sopenharmony_ciimport re
223f085823Sopenharmony_ciimport sys
233f085823Sopenharmony_ciimport subprocess
243f085823Sopenharmony_ciimport zipfile
253f085823Sopenharmony_ciimport errno
263f085823Sopenharmony_ciimport pipes
273f085823Sopenharmony_ciimport traceback
283f085823Sopenharmony_ciimport time
293f085823Sopenharmony_ciimport copy
303f085823Sopenharmony_ciimport shutil
313f085823Sopenharmony_cifrom pprint import pprint
323f085823Sopenharmony_ciimport stat
333f085823Sopenharmony_ci
343f085823Sopenharmony_cifrom tools.colored import Colored
353f085823Sopenharmony_cifrom tools.templates import GN_ENTRY_TEMPLATE
363f085823Sopenharmony_cifrom tools.templates import PROJECT_GN_TEMPLATE
373f085823Sopenharmony_cifrom tools.templates import PROJECT_DEMO_TEMPLATE
383f085823Sopenharmony_cifrom tools.templates import PROJECT_HEADER_TEMPLATE
393f085823Sopenharmony_cifrom tools.templates import PROJECT_XML_TEMPLATE
403f085823Sopenharmony_cifrom tools.run_result import RunResult
413f085823Sopenharmony_ci
423f085823Sopenharmony_ciFLAGS = os.O_WRONLY | os.O_CREAT | os.O_EXCL
433f085823Sopenharmony_ciMODES = stat.S_IWUSR | stat.S_IRUSR
443f085823Sopenharmony_ci
453f085823Sopenharmony_ciCURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
463f085823Sopenharmony_ciSOURCE_ROOT_DIR = os.path.dirname(
473f085823Sopenharmony_ci    os.path.dirname(
483f085823Sopenharmony_ci        os.path.dirname(os.path.dirname(CURRENT_DIR))
493f085823Sopenharmony_ci        )
503f085823Sopenharmony_ci    )
513f085823Sopenharmony_ciSOURCE_OUT_DIR = os.path.join(SOURCE_ROOT_DIR, "out")
523f085823Sopenharmony_ci
533f085823Sopenharmony_ciTDD_BUILD_GN_PATH = os.path.join(
543f085823Sopenharmony_ci    SOURCE_ROOT_DIR,
553f085823Sopenharmony_ci    "test/testfwk/developer_test/BUILD.gn"
563f085823Sopenharmony_ci    )
573f085823Sopenharmony_ci###project name must end with _fuzzer. eg. my_fuzzer,extrator_fuzzer.
583f085823Sopenharmony_ciVALID_PROJECT_NAME_REGEX = re.compile(r'^[a-zA-Z0-9_-]+(_fuzzer)+$')
593f085823Sopenharmony_ci
603f085823Sopenharmony_ci
613f085823Sopenharmony_cidef _add_environment_args(parser):
623f085823Sopenharmony_ci    """Add common environment args."""
633f085823Sopenharmony_ci    parser.add_argument(
643f085823Sopenharmony_ci        '-t',
653f085823Sopenharmony_ci        '--target_platform',
663f085823Sopenharmony_ci        default='phone',
673f085823Sopenharmony_ci        choices=["phone", "ivi", "plato"],
683f085823Sopenharmony_ci        help="set target_platform value, default:phone")
693f085823Sopenharmony_ci
703f085823Sopenharmony_ci    parser.add_argument(
713f085823Sopenharmony_ci        '-f',
723f085823Sopenharmony_ci        '--filter',
733f085823Sopenharmony_ci        default=None,
743f085823Sopenharmony_ci        help="subsystem filter")
753f085823Sopenharmony_ci
763f085823Sopenharmony_ci
773f085823Sopenharmony_cidef _get_command_string(command):
783f085823Sopenharmony_ci    """Returns a shell escaped command string."""
793f085823Sopenharmony_ci    return ' '.join(pipes.quote(part) for part in command)
803f085823Sopenharmony_ci
813f085823Sopenharmony_ci
823f085823Sopenharmony_cidef parse_projects_path():
833f085823Sopenharmony_ci    path_list = []
843f085823Sopenharmony_ci    with open(TDD_BUILD_GN_PATH, 'r') as gn_file:
853f085823Sopenharmony_ci        for line in gn_file.readlines()[4:]:
863f085823Sopenharmony_ci            striped_str = line.strip()
873f085823Sopenharmony_ci            if striped_str.endswith("]"):
883f085823Sopenharmony_ci                break
893f085823Sopenharmony_ci            path_list.append(striped_str.split(":")[0][3:])
903f085823Sopenharmony_ci    return path_list
913f085823Sopenharmony_ci
923f085823Sopenharmony_ci
933f085823Sopenharmony_cidef _get_fuzzer_yaml_config(fuzzer_name):
943f085823Sopenharmony_ci    project_yaml_path = os.path.join(
953f085823Sopenharmony_ci        CURRENT_DIR,
963f085823Sopenharmony_ci        "projects",
973f085823Sopenharmony_ci        fuzzer_name,
983f085823Sopenharmony_ci        "project.yaml")
993f085823Sopenharmony_ci    if not os.path.exists(project_yaml_path):
1003f085823Sopenharmony_ci        return {}
1013f085823Sopenharmony_ci    #log run stdout to fuzzlog dir
1023f085823Sopenharmony_ci    with open(project_yaml_path) as filehandle:
1033f085823Sopenharmony_ci        yaml_config = yaml.safe_load(filehandle)
1043f085823Sopenharmony_ci    return yaml_config
1053f085823Sopenharmony_ci
1063f085823Sopenharmony_ci
1073f085823Sopenharmony_ci#generate template fuzzer project
1083f085823Sopenharmony_cidef generate(args):
1093f085823Sopenharmony_ci    print("project name %s." % args.project_name)
1103f085823Sopenharmony_ci    print("project path %s." % args.project_path)
1113f085823Sopenharmony_ci    color_logger = Colored.get_project_logger()
1123f085823Sopenharmony_ci
1133f085823Sopenharmony_ci    if not VALID_PROJECT_NAME_REGEX.match(args.project_name):
1143f085823Sopenharmony_ci        print('Invalid project name.', file=sys.stderr)
1153f085823Sopenharmony_ci        return 1
1163f085823Sopenharmony_ci
1173f085823Sopenharmony_ci    template_args = {
1183f085823Sopenharmony_ci        'project_name': args.project_name,
1193f085823Sopenharmony_ci        'author': "",
1203f085823Sopenharmony_ci        'email': ""
1213f085823Sopenharmony_ci    }
1223f085823Sopenharmony_ci
1233f085823Sopenharmony_ci    project_dir_path = os.path.join(args.project_path, args.project_name)
1243f085823Sopenharmony_ci    print("project_dir_path %s." % project_dir_path)
1253f085823Sopenharmony_ci    try:
1263f085823Sopenharmony_ci        os.mkdir(project_dir_path)
1273f085823Sopenharmony_ci    except OSError as os_exception:
1283f085823Sopenharmony_ci        if os_exception.errno != errno.EEXIST:
1293f085823Sopenharmony_ci            raise
1303f085823Sopenharmony_ci        print(color_logger.red('%s already exists.' % project_dir_path),
1313f085823Sopenharmony_ci            file=sys.stderr)
1323f085823Sopenharmony_ci        return 1
1333f085823Sopenharmony_ci    color_logger.green('Writing new files to %s' % project_dir_path)
1343f085823Sopenharmony_ci
1353f085823Sopenharmony_ci    file_path = os.path.join(project_dir_path, 'project.xml')
1363f085823Sopenharmony_ci    if os.path.exists(file_path):
1373f085823Sopenharmony_ci        os.remove(file_path)
1383f085823Sopenharmony_ci    with os.fdopen(os.open(file_path, FLAGS, MODES), 'w') as filehandle:
1393f085823Sopenharmony_ci        filehandle.write(PROJECT_XML_TEMPLATE % template_args)
1403f085823Sopenharmony_ci
1413f085823Sopenharmony_ci    file_path = os.path.join(project_dir_path, "%s.cpp" % args.project_name)
1423f085823Sopenharmony_ci    if os.path.exists(file_path):
1433f085823Sopenharmony_ci        os.remove(file_path)
1443f085823Sopenharmony_ci    with os.fdopen(os.open(file_path, FLAGS, MODES), 'w') as filehandle:
1453f085823Sopenharmony_ci        filehandle.write(PROJECT_DEMO_TEMPLATE % template_args)
1463f085823Sopenharmony_ci
1473f085823Sopenharmony_ci    file_path = os.path.join(project_dir_path, "%s.h" % args.project_name)
1483f085823Sopenharmony_ci    if os.path.exists(file_path):
1493f085823Sopenharmony_ci        os.remove(file_path)
1503f085823Sopenharmony_ci    with os.fdopen(os.open(file_path, FLAGS, MODES), 'w') as filehandle:
1513f085823Sopenharmony_ci        filehandle.write(PROJECT_HEADER_TEMPLATE % template_args)
1523f085823Sopenharmony_ci    file_path = os.path.join(project_dir_path, "BUILD.gn")
1533f085823Sopenharmony_ci    if os.path.exists(file_path):
1543f085823Sopenharmony_ci        os.remove(file_path)
1553f085823Sopenharmony_ci    with os.fdopen(os.open(file_path, FLAGS, MODES), 'w') as filehandle:
1563f085823Sopenharmony_ci        filehandle.write(PROJECT_GN_TEMPLATE % template_args)
1573f085823Sopenharmony_ci
1583f085823Sopenharmony_ci    corpus_dir = os.path.join(project_dir_path, 'corpus')
1593f085823Sopenharmony_ci    if not os.path.exists(corpus_dir):
1603f085823Sopenharmony_ci        os.mkdir(corpus_dir)
1613f085823Sopenharmony_ci        if os.path.exists(os.path.join(corpus_dir, 'init')):
1623f085823Sopenharmony_ci            os.remove(os.path.join(corpus_dir, 'init'))
1633f085823Sopenharmony_ci        with os.fdopen(os.open(os.path.join(corpus_dir, 'init'), FLAGS, MODES), 'w') as filehandle:
1643f085823Sopenharmony_ci            filehandle.write("FUZZ")
1653f085823Sopenharmony_ci    return 0
1663f085823Sopenharmony_ci
1673f085823Sopenharmony_ci
1683f085823Sopenharmony_ci#complie fuzzer project
1693f085823Sopenharmony_cidef make(args, stdout=None):
1703f085823Sopenharmony_ci    """make fuzzer module."""
1713f085823Sopenharmony_ci    color_logger = Colored.get_project_logger()
1723f085823Sopenharmony_ci
1733f085823Sopenharmony_ci    pre_cmd = ['cd', SOURCE_ROOT_DIR]
1743f085823Sopenharmony_ci    build_target_platform = "build_platform=\"%s\""
1753f085823Sopenharmony_ci
1763f085823Sopenharmony_ci    build_script = [
1773f085823Sopenharmony_ci        './build.sh',
1783f085823Sopenharmony_ci        '--gn-args',
1793f085823Sopenharmony_ci        'build_example=true',
1803f085823Sopenharmony_ci        '--build-target'
1813f085823Sopenharmony_ci    ]
1823f085823Sopenharmony_ci    build_script.append(args.project_name)
1833f085823Sopenharmony_ci    build_script.append("--gn-args")
1843f085823Sopenharmony_ci    build_script.append(build_target_platform % args.build_platform)
1853f085823Sopenharmony_ci    build_script.append("--product-name")
1863f085823Sopenharmony_ci    build_script.append(args.build_platform)
1873f085823Sopenharmony_ci    build_script.append("--export-para")
1883f085823Sopenharmony_ci    build_script.append("PYCACHE_ENABLE:true")
1893f085823Sopenharmony_ci    print("BUILD_SCRIPT %s" % build_script)
1903f085823Sopenharmony_ci    final_cmd = "%s && %s" % (
1913f085823Sopenharmony_ci        _get_command_string(pre_cmd),
1923f085823Sopenharmony_ci        _get_command_string(build_script)
1933f085823Sopenharmony_ci        )
1943f085823Sopenharmony_ci
1953f085823Sopenharmony_ci    color_logger.green('Running:%s' % final_cmd)
1963f085823Sopenharmony_ci
1973f085823Sopenharmony_ci    subsystem_src_flag_file_path = os.path.join(
1983f085823Sopenharmony_ci        SOURCE_OUT_DIR,
1993f085823Sopenharmony_ci        "release/current_build_fuzz_target.txt"
2003f085823Sopenharmony_ci    )
2013f085823Sopenharmony_ci    if not os.path.exists(os.path.dirname(subsystem_src_flag_file_path)):
2023f085823Sopenharmony_ci        os.makedirs(os.path.dirname(subsystem_src_flag_file_path))
2033f085823Sopenharmony_ci    if os.path.exists(subsystem_src_flag_file_path):
2043f085823Sopenharmony_ci        os.remove(subsystem_src_flag_file_path)
2053f085823Sopenharmony_ci    with os.fdopen(os.open(subsystem_src_flag_file_path, FLAGS, MODES), 'wb') as file_handle:
2063f085823Sopenharmony_ci        file_handle.write(args.project_name.encode())
2073f085823Sopenharmony_ci
2083f085823Sopenharmony_ci    try:
2093f085823Sopenharmony_ci        if stdout:
2103f085823Sopenharmony_ci            ret = subprocess.check_call(build_script, cwd=SOURCE_ROOT_DIR,
2113f085823Sopenharmony_ci                                        stdout=stdout)
2123f085823Sopenharmony_ci        else:
2133f085823Sopenharmony_ci            ret = subprocess.check_call(build_script, cwd=SOURCE_ROOT_DIR)
2143f085823Sopenharmony_ci        return ret
2153f085823Sopenharmony_ci    except subprocess.CalledProcessError:
2163f085823Sopenharmony_ci        print("*" * 50)
2173f085823Sopenharmony_ci        print("*" * 50)
2183f085823Sopenharmony_ci        print(
2193f085823Sopenharmony_ci            'fuzzers {} build failed.'.format(args.project_name),
2203f085823Sopenharmony_ci            file=sys.stdout
2213f085823Sopenharmony_ci        )
2223f085823Sopenharmony_ci        return -1
2233f085823Sopenharmony_ci
2243f085823Sopenharmony_ci
2253f085823Sopenharmony_cidef report(args):
2263f085823Sopenharmony_ci    pass
2273f085823Sopenharmony_ci
2283f085823Sopenharmony_ci
2293f085823Sopenharmony_cidef coverage_all(args):
2303f085823Sopenharmony_ci    pass
2313f085823Sopenharmony_ci
2323f085823Sopenharmony_ci
2333f085823Sopenharmony_cidef main():
2343f085823Sopenharmony_ci    parser = argparse.ArgumentParser(
2353f085823Sopenharmony_ci        'fuzzer_helper.py',
2363f085823Sopenharmony_ci        description='hydra-fuzz helpers'
2373f085823Sopenharmony_ci    )
2383f085823Sopenharmony_ci    subparsers = parser.add_subparsers(dest='command')
2393f085823Sopenharmony_ci
2403f085823Sopenharmony_ci    generate_parser = subparsers.add_parser(
2413f085823Sopenharmony_ci        'generate',
2423f085823Sopenharmony_ci        help='Generate files for new project.name must end with "_fuzzer".')
2433f085823Sopenharmony_ci    generate_parser.add_argument('project_name')
2443f085823Sopenharmony_ci    generate_parser.add_argument('project_path')
2453f085823Sopenharmony_ci    _add_environment_args(generate_parser)
2463f085823Sopenharmony_ci
2473f085823Sopenharmony_ci    make_parser = subparsers.add_parser(
2483f085823Sopenharmony_ci        'make', help='Build a single fuzzer module project. ')
2493f085823Sopenharmony_ci    make_parser.add_argument('project_name')
2503f085823Sopenharmony_ci    make_parser.add_argument('build_platform')
2513f085823Sopenharmony_ci    _add_environment_args(make_parser)
2523f085823Sopenharmony_ci
2533f085823Sopenharmony_ci    report_parser = subparsers.add_parser(
2543f085823Sopenharmony_ci       'report', help='Report fuzzer log'
2553f085823Sopenharmony_ci    )
2563f085823Sopenharmony_ci    _add_environment_args(report_parser)
2573f085823Sopenharmony_ci    report_parser.add_argument(
2583f085823Sopenharmony_ci        'subfunc',
2593f085823Sopenharmony_ci        default="list",
2603f085823Sopenharmony_ci        choices=["list", "coverage", "all"]
2613f085823Sopenharmony_ci    )
2623f085823Sopenharmony_ci    report_parser.add_argument(
2633f085823Sopenharmony_ci        "-i",
2643f085823Sopenharmony_ci        "--id",
2653f085823Sopenharmony_ci        required=False,
2663f085823Sopenharmony_ci        help="report ID, e.g. empty_fuzzer.20200211184850"
2673f085823Sopenharmony_ci    )
2683f085823Sopenharmony_ci
2693f085823Sopenharmony_ci    args = parser.parse_args()
2703f085823Sopenharmony_ci
2713f085823Sopenharmony_ci    if args.command == 'generate':
2723f085823Sopenharmony_ci        return generate(args)
2733f085823Sopenharmony_ci    elif args.command == 'make':
2743f085823Sopenharmony_ci        return make(args)
2753f085823Sopenharmony_ci
2763f085823Sopenharmony_ci    elif args.command == 'report':
2773f085823Sopenharmony_ci        report(args)
2783f085823Sopenharmony_ci        return 1
2793f085823Sopenharmony_ci    else:
2803f085823Sopenharmony_ci        return 0
2813f085823Sopenharmony_ci
2823f085823Sopenharmony_ciif __name__ == "__main__":
2833f085823Sopenharmony_ci    main()
284