diff options
author | Mike Aizatsky <aizatsky@chromium.org> | 2016-01-27 23:51:36 +0000 |
---|---|---|
committer | Mike Aizatsky <aizatsky@chromium.org> | 2016-01-27 23:51:36 +0000 |
commit | 331b8d08ba07668ce06a15a8f310ba4fa9543296 (patch) | |
tree | 595a5532d236f23dd162ff355f8dc7287f0d3e94 | |
parent | cce3227b8684952f19f3fb184c819f721e4e19b3 (diff) |
[sanitizers] generating html report on coverage dump
Subscribers: tberghammer, danalbert, srhines
Differential Revision: http://reviews.llvm.org/D16374
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@258999 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/sanitizer_common/sanitizer_common.h | 3 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_coverage_libcdep.cc | 35 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_flags.inc | 2 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_posix_libcdep.cc | 11 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_win.cc | 2 | ||||
-rw-r--r-- | test/CMakeLists.txt | 2 | ||||
-rw-r--r-- | test/asan/TestCases/Posix/coverage_html_report.cc | 24 | ||||
-rw-r--r-- | test/asan/lit.cfg | 2 | ||||
-rw-r--r-- | test/lit.common.cfg | 5 |
9 files changed, 84 insertions, 2 deletions
diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index c40c1f369..484eca326 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -291,6 +291,9 @@ pid_t StartSubprocess(const char *filename, const char *const argv[], fd_t stderr_fd = kInvalidFd); // Checks if specified process is still running bool IsProcessRunning(pid_t pid); +// Waits for the process to finish and returns its exit code. +// Returns -1 in case of an error. +int WaitForProcess(pid_t pid); u32 GetUid(); void ReExec(); diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc index 5ee55a470..9aa7b924b 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc @@ -783,12 +783,43 @@ void CoverageData::GetRangeOffsets(const NamedPcRange& r, Symbolizer* sym, (*offsets)[i] = UnbundlePc((*offsets)[i]); } +static void GenerateHtmlReport(const InternalMmapVector<char *> &sancov_argv) { + if (!common_flags()->html_cov_report || sancov_argv[0] == nullptr) { + return; + } + + InternalScopedString report_path(kMaxPathLength); + fd_t report_fd = + CovOpenFile(&report_path, false /* packed */, GetProcessName(), "html"); + int pid = StartSubprocess(sancov_argv[0], sancov_argv.data(), + kInvalidFd /* stdin */, report_fd /* std_out */); + if (pid > 0) { + int result = WaitForProcess(pid); + if (result == 0) { + VReport(1, " CovDump: html report generated to %s (%d)\n", + report_path.data(), result); + } + } +} + void CoverageData::DumpOffsets() { auto sym = Symbolizer::GetOrInit(); if (!common_flags()->coverage_pcs) return; CHECK_NE(sym, nullptr); InternalMmapVector<uptr> offsets(0); InternalScopedString path(kMaxPathLength); + + InternalMmapVector<char *> sancov_argv(module_name_vec.size() + 2); + sancov_argv.push_back(FindPathToBinary(common_flags()->sancov_path)); + sancov_argv.push_back(internal_strdup("-obj")); + sancov_argv.push_back(internal_strdup(GetArgv()[0])); + sancov_argv.push_back(internal_strdup("-html-report")); + auto argv_deleter = at_scope_exit([&] { + for (uptr i = 0; i < sancov_argv.size(); ++i) { + InternalFree(sancov_argv[i]); + } + }); + for (uptr m = 0; m < module_name_vec.size(); m++) { auto r = module_name_vec[m]; GetRangeOffsets(r, sym, &offsets); @@ -813,11 +844,15 @@ void CoverageData::DumpOffsets() { if (fd == kInvalidFd) continue; WriteToFile(fd, offsets.data(), offsets.size() * sizeof(offsets[0])); CloseFile(fd); + sancov_argv.push_back(internal_strdup(path.data())); VReport(1, " CovDump: %s: %zd PCs written\n", path.data(), num_offsets); } } if (cov_fd != kInvalidFd) CloseFile(cov_fd); + + sancov_argv.push_back(nullptr); + GenerateHtmlReport(sancov_argv); } void CoverageData::DumpAll() { diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index f9726fe5c..e983c0c76 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -202,3 +202,5 @@ COMMON_FLAG(bool, suppress_equal_pcs, true, "halt_on_error=false mode (asan only).") COMMON_FLAG(bool, print_cmdline, false, "Print command line on crash " "(asan only).") +COMMON_FLAG(bool, html_cov_report, false, "Generate html coverage report.") +COMMON_FLAG(const char *, sancov_path, "sancov", "Sancov tool location.") diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc index 5add77ad3..e280e0734 100644 --- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -383,6 +383,17 @@ bool IsProcessRunning(pid_t pid) { return waitpid_status == 0; } +int WaitForProcess(pid_t pid) { + int process_status; + uptr waitpid_status = internal_waitpid(pid, &process_status, 0); + int local_errno; + if (internal_iserror(waitpid_status, &local_errno)) { + VReport(1, "Waiting on the process failed (errno %d).\n", local_errno); + return -1; + } + return process_status; +} + } // namespace __sanitizer #endif // SANITIZER_POSIX diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index 46bdca6e4..108e855fe 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -789,6 +789,8 @@ bool IsProcessRunning(pid_t pid) { return false; } +int WaitForProcess(pid_t pid) { return -1; } + } // namespace __sanitizer #endif // _WIN32 diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e5c51c8cd..fe2ff49b1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -20,7 +20,7 @@ if(NOT ANDROID) # Use LLVM utils and Clang from the same build tree. list(APPEND SANITIZER_COMMON_LIT_TEST_DEPS clang clang-headers FileCheck count not llvm-config llvm-nm llvm-objdump - llvm-symbolizer compiler-rt-headers) + llvm-symbolizer compiler-rt-headers sancov) if (COMPILER_RT_HAS_PROFILE) list(APPEND SANITIZER_COMMON_LIT_TEST_DEPS profile) endif() diff --git a/test/asan/TestCases/Posix/coverage_html_report.cc b/test/asan/TestCases/Posix/coverage_html_report.cc new file mode 100644 index 000000000..98d78b9be --- /dev/null +++ b/test/asan/TestCases/Posix/coverage_html_report.cc @@ -0,0 +1,24 @@ +// REQUIRES: has_sancovcc +// RUN: %clangxx_asan -fsanitize-coverage=func %s -o %t +// RUN: rm -rf %T/coverage_html_report +// RUN: mkdir -p %T/coverage_html_report +// RUN: cd %T/coverage_html_report +// RUN: %env_asan_opts=coverage=1:verbosity=1:html_cov_report=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-main +// RUN: ls *.html | FileCheck %s --check-prefix=CHECK-ls +// RUN: rm -r %T/coverage_html_report + +#include <stdio.h> +#include <unistd.h> + +void bar() { printf("bar\n"); } + +int main(int argc, char **argv) { + fprintf(stderr, "PID: %d\n", getpid()); + bar(); + return 0; +} + +// CHECK-main: PID: [[PID:[0-9]+]] +// CHECK-main: [[PID]].sancov: 2 PCs written +// CHECK-main: html report generated to ./coverage_html_report.cc.tmp.[[PID]].html +// CHECK-ls: coverage_html_report.cc.tmp.{{[0-9]+}}.html diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg index 835547090..c50559a51 100644 --- a/test/asan/lit.cfg +++ b/test/asan/lit.cfg @@ -138,7 +138,7 @@ sancov = os.path.join(sanitizer_common_source_dir, "scripts", "sancov.py") if not os.path.exists(sancov): lit_config.fatal("Can't find script on path %r" % sancov) python_exec = get_required_attr(config, "python_executable") -config.substitutions.append( ("%sancov", python_exec + " " + sancov + " ") ) +config.substitutions.append( ("%sancov ", python_exec + " " + sancov + " ") ) # Determine kernel bitness if config.host_arch.find('64') != -1 and config.android != "1": diff --git a/test/lit.common.cfg b/test/lit.common.cfg index 1ae41da5e..f19cd363d 100644 --- a/test/lit.common.cfg +++ b/test/lit.common.cfg @@ -115,6 +115,11 @@ if config.can_symbolize: lit.util.usePlatformSdkOnDarwin(config, lit_config) +sancovcc_path = os.path.join(llvm_tools_dir, "sancov") +if os.path.exists(sancovcc_path): + config.available_features.add("has_sancovcc") + config.substitutions.append( ("%sancovcc ", sancovcc_path) ) + def is_darwin_lto_supported(): return os.path.exists(os.path.join(config.llvm_shlib_dir, 'libLTO.dylib')) |