• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2# -*- coding:utf-8 -*-
3#
4# Copyright (c) 2021 Huawei Device Co., Ltd.
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#     http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18from __future__ import print_function
19import argparse
20import os
21import re
22import sys
23import subprocess
24import zipfile
25import errno
26import pipes
27import traceback
28import time
29import copy
30import shutil
31from pprint import pprint
32
33from tools.colored import Colored
34from tools.templates import GN_ENTRY_TEMPLATE
35from tools.templates import PROJECT_GN_TEMPLATE
36from tools.templates import PROJECT_DEMO_TEMPLATE
37from tools.templates import PROJECT_HEADER_TEMPLATE
38from tools.templates import PROJECT_XML_TEMPLATE
39from tools.run_result import RunResult
40
41CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
42SOURCE_ROOT_DIR = os.path.dirname(
43    os.path.dirname(
44        os.path.dirname(os.path.dirname(CURRENT_DIR))
45        )
46    )
47SOURCE_OUT_DIR = os.path.join(SOURCE_ROOT_DIR, "out")
48
49TDD_BUILD_GN_PATH = os.path.join(
50    SOURCE_ROOT_DIR,
51    "test/testfwk/developer_test/BUILD.gn"
52    )
53###project name must end with _fuzzer. eg. my_fuzzer,extrator_fuzzer.
54VALID_PROJECT_NAME_REGEX = re.compile(r'^[a-zA-Z0-9_-]+(_fuzzer)+$')
55
56
57def _add_environment_args(parser):
58    """Add common environment args."""
59    parser.add_argument(
60        '-t',
61        '--target_platform',
62        default='phone',
63        choices=["phone", "ivi", "plato"],
64        help="set target_platform value, default:phone")
65
66    parser.add_argument(
67        '-f',
68        '--filter',
69        default=None,
70        help="subsystem filter")
71
72
73def _get_command_string(command):
74    """Returns a shell escaped command string."""
75    return ' '.join(pipes.quote(part) for part in command)
76
77
78def parse_projects_path():
79    path_list = []
80    with open(TDD_BUILD_GN_PATH, 'r') as gn_file:
81        for line in gn_file.readlines()[4:]:
82            striped_str = line.strip()
83            if striped_str.endswith("]"):
84                break
85            path_list.append(striped_str.split(":")[0][3:])
86    return path_list
87
88
89def _get_fuzzer_yaml_config(fuzzer_name):
90    project_yaml_path = os.path.join(
91        CURRENT_DIR,
92        "projects",
93        fuzzer_name,
94        "project.yaml")
95    if not os.path.exists(project_yaml_path):
96        return
97    #log run stdout to fuzzlog dir
98    with open(project_yaml_path) as filehandle:
99        yaml_config = yaml.safe_load(filehandle)
100    return yaml_config
101
102
103#generate template fuzzer project
104def generate(args):
105    print("project name %s." % args.project_name)
106    print("project path %s." % args.project_path)
107    color_logger = Colored.get_project_logger()
108
109    if not VALID_PROJECT_NAME_REGEX.match(args.project_name):
110        print('Invalid project name.', file=sys.stderr)
111        return 1
112
113    template_args = {
114        'project_name': args.project_name,
115        'author': "",
116        'email': ""
117    }
118
119    project_dir_path = os.path.join(args.project_path, args.project_name)
120    print("project_dir_path %s." % project_dir_path)
121    try:
122        os.mkdir(project_dir_path)
123    except OSError as os_exception:
124        if os_exception.errno != errno.EEXIST:
125            raise
126        print(color_logger.red('%s already exists.' % project_dir_path),
127            file=sys.stderr)
128        return 1
129    color_logger.green('Writing new files to %s' % project_dir_path)
130
131    file_path = os.path.join(project_dir_path, 'project.xml')
132    with open(file_path, 'w') as filehandle:
133        filehandle.write(PROJECT_XML_TEMPLATE % template_args)
134
135    file_path = os.path.join(project_dir_path, "%s.cpp" % args.project_name)
136    with open(file_path, 'w') as filehandle:
137        filehandle.write(PROJECT_DEMO_TEMPLATE % template_args)
138
139    file_path = os.path.join(project_dir_path, "%s.h" % args.project_name)
140    with open(file_path, 'w') as filehandle:
141        filehandle.write(PROJECT_HEADER_TEMPLATE % template_args)
142    file_path = os.path.join(project_dir_path, "BUILD.gn")
143    with open(file_path, 'w') as filehandle:
144        filehandle.write(PROJECT_GN_TEMPLATE % template_args)
145
146    corpus_dir = os.path.join(project_dir_path, 'corpus')
147    if not os.path.exists(corpus_dir):
148        os.mkdir(corpus_dir)
149        with open(os.path.join(corpus_dir, 'init'), 'w') as filehandle:
150            filehandle.write("FUZZ")
151
152
153#complie fuzzer project
154def make(args,  stdout=None):
155    """make fuzzer module."""
156    color_logger = Colored.get_project_logger()
157
158    pre_cmd = ['cd', SOURCE_ROOT_DIR]
159    build_target_platform = "build_platform=\"%s\""
160
161    build_script = [
162        './build.sh',
163        '--gn-args',
164        'build_example=true',
165        '--build-target'
166    ]
167    build_script.append(args.project_name)
168    build_script.append("--gn-args")
169    build_script.append(build_target_platform % args.build_platform)
170    build_script.append("--product-name")
171    build_script.append(args.build_platform)
172    build_script.append("--export-para")
173    build_script.append("PYCACHE_ENABLE:true")
174    build_script.append("--export-para")
175    build_script.append("BUILD_AOSP:false")
176    print("BUILD_SCRIPT %s" % build_script)
177    final_cmd = "%s && %s" % (
178        _get_command_string(pre_cmd),
179        _get_command_string(build_script)
180        )
181
182    color_logger.green('Running:%s' % final_cmd)
183
184    subsystem_src_flag_file_path = os.path.join(
185        SOURCE_OUT_DIR,
186        "release/current_build_fuzz_target.txt"
187    )
188    if not os.path.exists(os.path.dirname(subsystem_src_flag_file_path)):
189        os.makedirs(os.path.dirname(subsystem_src_flag_file_path))
190    with open(subsystem_src_flag_file_path, "wb") as file_handle:
191        file_handle.write(args.project_name.encode())
192
193    try:
194        if stdout:
195            ret = subprocess.check_call(build_script, cwd=SOURCE_ROOT_DIR,
196                                        stdout=stdout)
197        else:
198            ret = subprocess.check_call(build_script, cwd=SOURCE_ROOT_DIR)
199        return ret
200    except subprocess.CalledProcessError:
201        print("*" * 50)
202        print("*" * 50)
203        print(
204            'fuzzers {} build failed.'.format(args.project_name),
205            file=sys.stdout
206        )
207        return -1
208
209
210def report(args):
211    pass
212
213
214def coverage_all(args):
215    pass
216
217
218def main():
219    parser = argparse.ArgumentParser(
220        'fuzzer_helper.py',
221        description='hydra-fuzz helpers'
222    )
223    subparsers = parser.add_subparsers(dest='command')
224
225    generate_parser = subparsers.add_parser(
226        'generate',
227        help='Generate files for new project.name must end with "_fuzzer".')
228    generate_parser.add_argument('project_name')
229    generate_parser.add_argument('project_path')
230    _add_environment_args(generate_parser)
231
232    make_parser = subparsers.add_parser(
233        'make', help='Build a single fuzzer module project. ')
234    make_parser.add_argument('project_name')
235    make_parser.add_argument('build_platform')
236    _add_environment_args(make_parser)
237
238    report_parser = subparsers.add_parser(
239       'report', help='Report fuzzer log'
240    )
241    _add_environment_args(report_parser)
242    report_parser.add_argument(
243        'subfunc',
244        default="list",
245        choices=["list", "coverage", "all"]
246    )
247    report_parser.add_argument(
248        "-i",
249        "--id",
250        required=False,
251        help="report ID, e.g. empty_fuzzer.20200211184850"
252    )
253
254    args = parser.parse_args()
255
256    if args.command == 'generate':
257        return generate(args)
258    elif args.command == 'make':
259        return make(args)
260
261    elif args.command == 'report':
262        report(args)
263
264if __name__ == "__main__":
265    main()
266