mirror of https://github.com/google/oss-fuzz.git
* [infra] Use coverage utils from Chromium and other fixes (follow-up #1547). * Sort dependencies in an alpha order plus make more readable. * Re-order arguments passed to coverage_helper script. * Rename REPORT_DIR variable and put summary.json into platform specific dir. * Fix -src-root-dir value.
This commit is contained in:
parent
edac5d558c
commit
17a6cfbd40
|
@ -68,7 +68,7 @@ BUILD_CMD="bash -eux $SRC/build.sh"
|
|||
|
||||
# We need to preserve source code files for generating a code coverage report.
|
||||
# We need exact files that were compiled, so copy both $SRC and $WORK dirs.
|
||||
COPY_SOURCES_CMD="cp -r $SRC $WORK $OUT"
|
||||
COPY_SOURCES_CMD="cp -rL $SRC $WORK $OUT"
|
||||
|
||||
if [ "${BUILD_UID-0}" -ne "0" ]; then
|
||||
adduser -u $BUILD_UID --disabled-password --gecos '' builder
|
||||
|
|
|
@ -16,11 +16,37 @@
|
|||
|
||||
FROM gcr.io/oss-fuzz-base/base-image
|
||||
MAINTAINER mike.aizatsky@gmail.com
|
||||
RUN apt-get install -y zip file libunwind8 binutils libblocksruntime0 \
|
||||
fonts-dejavu python3 libcap2 wget
|
||||
COPY bad_build_check coverage coverage_helper.py download_corpus llvm-cov \
|
||||
llvm-profdata llvm-symbolizer reproduce run_fuzzer sancov test_all \
|
||||
minijail0 run_minijail targets_list /usr/local/bin/
|
||||
RUN apt-get install -y \
|
||||
binutils \
|
||||
file \
|
||||
fonts-dejavu \
|
||||
git \
|
||||
libblocksruntime0 \
|
||||
libcap2 \
|
||||
libunwind8 \
|
||||
python3 \
|
||||
python3-pip \
|
||||
wget \
|
||||
zip
|
||||
|
||||
RUN git clone https://chromium.googlesource.com/chromium/src/tools/code_coverage /opt/code_coverage
|
||||
RUN pip3 install -r /opt/code_coverage/requirements.txt
|
||||
|
||||
COPY bad_build_check \
|
||||
coverage \
|
||||
coverage_helper \
|
||||
download_corpus \
|
||||
llvm-cov \
|
||||
llvm-profdata \
|
||||
llvm-symbolizer \
|
||||
minijail0 \
|
||||
reproduce \
|
||||
run_fuzzer \
|
||||
run_minijail \
|
||||
sancov \
|
||||
targets_list \
|
||||
test_all \
|
||||
/usr/local/bin/
|
||||
|
||||
# Default environment options for various sanitizers.
|
||||
# Note that these match the settings used in ClusterFuzz and
|
||||
|
|
|
@ -25,20 +25,24 @@ fi
|
|||
DUMPS_DIR="$OUT/dumps"
|
||||
FUZZER_STATS_DIR="$OUT/fuzzer_stats"
|
||||
LOGS_DIR="$OUT/logs"
|
||||
REPORT_DIR="$OUT/report"
|
||||
REPORT_ROOT_DIR="$OUT/report"
|
||||
REPORT_PLATFORM_DIR="$OUT/report/linux"
|
||||
|
||||
for directory in $DUMPS_DIR $FUZZER_STATS_DIR $LOGS_DIR $REPORT_DIR; do
|
||||
for directory in $DUMPS_DIR $FUZZER_STATS_DIR $LOGS_DIR $REPORT_ROOT_DIR \
|
||||
$REPORT_PLATFORM_DIR; do
|
||||
rm -rf $directory
|
||||
mkdir -p $directory
|
||||
done
|
||||
|
||||
|
||||
PROFILE_FILE="$DUMPS_DIR/merged.profdata"
|
||||
SUMMARY_FILE="$REPORT_DIR/summary.json"
|
||||
SUMMARY_FILE="$REPORT_PLATFORM_DIR/summary.json"
|
||||
|
||||
# Use path mapping, as $SRC directory from the builder is copied into $OUT/$SRC.
|
||||
PATH_EQUIVALENCE_ARGS="-path-equivalence=/,$OUT"
|
||||
|
||||
# It's important to use $COVERAGE_EXTRA_ARGS as the last argument, because it
|
||||
# can contain paths to source files / directories which are positional args.
|
||||
LLVM_COV_COMMON_ARGS="-path-equivalence=/,$OUT \
|
||||
LLVM_COV_COMMON_ARGS="$PATH_EQUIVALENCE_ARGS \
|
||||
-ignore-filename-regex=.*src/libfuzzer/.* $COVERAGE_EXTRA_ARGS"
|
||||
|
||||
# Timeout for running a single fuzz target.
|
||||
|
@ -74,7 +78,7 @@ function run_fuzz_target {
|
|||
# Delete unnecessary and (potentially) large .profraw files.
|
||||
rm $profraw_file_mask
|
||||
|
||||
shared_libraries=$(coverage_helper.py shared_libs -object=$target)
|
||||
shared_libraries=$(coverage_helper shared_libs -build-dir=$OUT -object=$target)
|
||||
llvm-cov export -summary-only -instr-profile=$profdata_file -object=$target \
|
||||
$shared_libraries $LLVM_COV_COMMON_ARGS > $FUZZER_STATS_DIR/$target.json
|
||||
}
|
||||
|
@ -113,7 +117,7 @@ llvm-profdata merge -sparse $DUMPS_DIR/*.profdata -o $PROFILE_FILE
|
|||
|
||||
# TODO(mmoroz): add script from Chromium for rendering directory view reports.
|
||||
# The first path in $objects does not have -object= prefix (llvm-cov format).
|
||||
shared_libraries=$(coverage_helper.py shared_libs -object=$objects)
|
||||
shared_libraries=$(coverage_helper shared_libs -build-dir=$OUT -object=$objects)
|
||||
objects="$objects $shared_libraries"
|
||||
|
||||
# It's important to use $LLVM_COV_COMMON_ARGS as the last argument due to
|
||||
|
@ -121,15 +125,19 @@ objects="$objects $shared_libraries"
|
|||
LLVM_COV_ARGS="-instr-profile=$PROFILE_FILE $objects $LLVM_COV_COMMON_ARGS"
|
||||
|
||||
# Generate HTML report.
|
||||
llvm-cov show -format=html -output-dir=$REPORT_DIR \
|
||||
llvm-cov show -format=html -output-dir=$REPORT_ROOT_DIR \
|
||||
-Xdemangler c++filt -Xdemangler -n $LLVM_COV_ARGS
|
||||
|
||||
# Export coverage summary in JSON format.
|
||||
llvm-cov export -summary-only $LLVM_COV_ARGS > $SUMMARY_FILE
|
||||
|
||||
# Post process HTML report.
|
||||
coverage_helper -v post_process -src-root-dir=$SRC -summary-file=$SUMMARY_FILE \
|
||||
-output-dir=$REPORT_ROOT_DIR $PATH_EQUIVALENCE_ARGS
|
||||
|
||||
if [[ -n $HTTP_PORT ]]; then
|
||||
# Serve the report locally.
|
||||
echo "Serving the report on http://127.0.0.1:$HTTP_PORT/"
|
||||
cd $REPORT_DIR
|
||||
echo "Serving the report on http://127.0.0.1:$HTTP_PORT/linux/index.html"
|
||||
cd $REPORT_ROOT_DIR
|
||||
python3 -m http.server $HTTP_PORT
|
||||
fi
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
#!/bin/bash -u
|
||||
# Copyright 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
################################################################################
|
||||
python3 /opt/code_coverage/coverage_utils.py $@
|
|
@ -1,88 +0,0 @@
|
|||
#!/usr/bin/python3
|
||||
# Copyright 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
def get_shared_libraries(binary_paths):
|
||||
"""Returns list of shared libraries used by specified binaries."""
|
||||
shared_libraries = []
|
||||
cmd = ['ldd']
|
||||
shared_library_path_re = re.compile(
|
||||
r'.*\.so[.0-9]*\s=>\s(.*' + os.getenv('OUT') + r'.*\.so[.0-9]*)\s.*')
|
||||
|
||||
cmd.extend(binary_paths)
|
||||
output = subprocess.check_output(cmd).decode("utf-8", "ignore")
|
||||
|
||||
for line in output.splitlines():
|
||||
match = shared_library_path_re.match(line)
|
||||
if not match:
|
||||
continue
|
||||
|
||||
shared_library_path = match.group(1)
|
||||
if shared_library_path in shared_libraries:
|
||||
continue
|
||||
|
||||
assert os.path.exists(shared_library_path), ('Shared library "%s" used by '
|
||||
'the given target(s) does not '
|
||||
'exist.' % shared_library_path)
|
||||
with open(shared_library_path, 'rb') as f:
|
||||
data = f.read()
|
||||
|
||||
# Do not add non-instrumented libraries. Otherwise, llvm-cov errors outs.
|
||||
if b'__llvm_cov' in data:
|
||||
shared_libraries.append(shared_library_path)
|
||||
|
||||
return shared_libraries
|
||||
|
||||
|
||||
def print_shared_libraries(args):
|
||||
if not args.object:
|
||||
print("ERROR: No binaries are specified.", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
paths = get_shared_libraries(args.object)
|
||||
if not paths:
|
||||
return 0
|
||||
|
||||
# Print output in the format that can be passed to llvm-cov tool.
|
||||
output = ' '.join(['-object=%s' % path for path in paths])
|
||||
print(output)
|
||||
return 0
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser('coverage_helper',
|
||||
description='coverage script helper')
|
||||
subparsers = parser.add_subparsers(dest='command')
|
||||
|
||||
shared_libs_parser = subparsers.add_parser('shared_libs',
|
||||
help='Detect shared libraries.')
|
||||
shared_libs_parser.add_argument('-object', action='append',
|
||||
help='Path to the binary using shared libs.')
|
||||
|
||||
args = parser.parse_args()
|
||||
if args.command == 'shared_libs':
|
||||
return print_shared_libraries(args)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
Loading…
Reference in New Issue