summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Aizatsky <aizatsky@chromium.org>2016-01-27 23:51:36 +0000
committerMike Aizatsky <aizatsky@chromium.org>2016-01-27 23:51:36 +0000
commit331b8d08ba07668ce06a15a8f310ba4fa9543296 (patch)
tree595a5532d236f23dd162ff355f8dc7287f0d3e94
parentcce3227b8684952f19f3fb184c819f721e4e19b3 (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.h3
-rw-r--r--lib/sanitizer_common/sanitizer_coverage_libcdep.cc35
-rw-r--r--lib/sanitizer_common/sanitizer_flags.inc2
-rw-r--r--lib/sanitizer_common/sanitizer_posix_libcdep.cc11
-rw-r--r--lib/sanitizer_common/sanitizer_win.cc2
-rw-r--r--test/CMakeLists.txt2
-rw-r--r--test/asan/TestCases/Posix/coverage_html_report.cc24
-rw-r--r--test/asan/lit.cfg2
-rw-r--r--test/lit.common.cfg5
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'))