aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmake/config-ix.cmake2
-rw-r--r--include/sanitizer/coverage_interface.h7
-rw-r--r--lib/asan/asan_win_dll_thunk.cc1
-rw-r--r--lib/profile/CMakeLists.txt3
-rw-r--r--lib/profile/GCDAProfiling.c6
-rw-r--r--lib/profile/InstrProfData.inc21
-rw-r--r--lib/profile/InstrProfilingFile.c4
-rw-r--r--lib/profile/InstrProfilingPort.h22
-rw-r--r--lib/profile/WindowsMMap.c128
-rw-r--r--lib/profile/WindowsMMap.h65
-rw-r--r--lib/sanitizer_common/sanitizer_coverage_libcdep.cc19
-rw-r--r--lib/sanitizer_common/sanitizer_flags.inc3
-rw-r--r--test/asan/TestCases/coverage-pc-buffer.cc48
13 files changed, 308 insertions, 21 deletions
diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake
index f91530bb4403..ba21238623a5 100644
--- a/cmake/config-ix.cmake
+++ b/cmake/config-ix.cmake
@@ -559,7 +559,7 @@ else()
endif()
if (PROFILE_SUPPORTED_ARCH AND
- OS_NAME MATCHES "Darwin|Linux|FreeBSD")
+ OS_NAME MATCHES "Darwin|Linux|FreeBSD|Windows")
set(COMPILER_RT_HAS_PROFILE TRUE)
else()
set(COMPILER_RT_HAS_PROFILE FALSE)
diff --git a/include/sanitizer/coverage_interface.h b/include/sanitizer/coverage_interface.h
index b93111b859bc..2dcc09fc8499 100644
--- a/include/sanitizer/coverage_interface.h
+++ b/include/sanitizer/coverage_interface.h
@@ -41,6 +41,13 @@ extern "C" {
// Some of the entries in *data will be zero.
uintptr_t __sanitizer_get_coverage_guards(uintptr_t **data);
+ // Set *data to the growing buffer with covered PCs and return the size
+ // of the buffer. The entries are never zero.
+ // When only unique pcs are collected, the size is equal to
+ // __sanitizer_get_total_unique_coverage.
+ // WARNING: EXPERIMENTAL API.
+ uintptr_t __sanitizer_get_coverage_pc_buffer(uintptr_t **data);
+
// The coverage instrumentation may optionally provide imprecise counters.
// Rather than exposing the counter values to the user we instead map
// the counters to a bitset.
diff --git a/lib/asan/asan_win_dll_thunk.cc b/lib/asan/asan_win_dll_thunk.cc
index 308196d307cc..672cabf43ec1 100644
--- a/lib/asan/asan_win_dll_thunk.cc
+++ b/lib/asan/asan_win_dll_thunk.cc
@@ -315,6 +315,7 @@ INTERFACE_FUNCTION(__sanitizer_cov_trace_switch)
INTERFACE_FUNCTION(__sanitizer_cov_with_check)
INTERFACE_FUNCTION(__sanitizer_get_allocated_size)
INTERFACE_FUNCTION(__sanitizer_get_coverage_guards)
+INTERFACE_FUNCTION(__sanitizer_get_coverage_pc_buffer)
INTERFACE_FUNCTION(__sanitizer_get_current_allocated_bytes)
INTERFACE_FUNCTION(__sanitizer_get_estimated_allocated_size)
INTERFACE_FUNCTION(__sanitizer_get_free_bytes)
diff --git a/lib/profile/CMakeLists.txt b/lib/profile/CMakeLists.txt
index 1b10ade0eee6..3f84c0e6db35 100644
--- a/lib/profile/CMakeLists.txt
+++ b/lib/profile/CMakeLists.txt
@@ -35,7 +35,8 @@ set(PROFILE_SOURCES
InstrProfilingPlatformLinux.c
InstrProfilingPlatformOther.c
InstrProfilingRuntime.cc
- InstrProfilingUtil.c)
+ InstrProfilingUtil.c
+ WindowsMMap.c)
if(UNIX)
set(EXTRA_FLAGS
diff --git a/lib/profile/GCDAProfiling.c b/lib/profile/GCDAProfiling.c
index aec232856e74..2338761ae1ab 100644
--- a/lib/profile/GCDAProfiling.c
+++ b/lib/profile/GCDAProfiling.c
@@ -27,8 +27,13 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+
+#if defined(_WIN32)
+#include "WindowsMMap.h"
+#else
#include <sys/mman.h>
#include <sys/file.h>
+#endif
#define I386_FREEBSD (defined(__FreeBSD__) && defined(__i386__))
@@ -37,6 +42,7 @@
#endif
#if defined(_MSC_VER)
+typedef unsigned char uint8_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
#elif I386_FREEBSD
diff --git a/lib/profile/InstrProfData.inc b/lib/profile/InstrProfData.inc
index 48dae506cabb..3a7c0c5f2773 100644
--- a/lib/profile/InstrProfData.inc
+++ b/lib/profile/InstrProfData.inc
@@ -1,4 +1,4 @@
-/*===-- InstrProfData.inc - instr profiling runtime structures -----------=== *\
+/*===-- InstrProfData.inc - instr profiling runtime structures -*- C++ -*-=== *\
|*
|* The LLVM Compiler Infrastructure
|*
@@ -167,6 +167,25 @@ COVMAP_FUNC_RECORD(const uint64_t, llvm::Type::getInt64Ty(Ctx), FuncHash, \
#undef COVMAP_FUNC_RECORD
/* COVMAP_FUNC_RECORD end. */
+/* COVMAP_HEADER start */
+/* Definition of member fields of coverage map header.
+ */
+#ifndef COVMAP_HEADER
+#define COVMAP_HEADER(Type, LLVMType, Name, Initializer)
+#else
+#define INSTR_PROF_DATA_DEFINED
+#endif
+COVMAP_HEADER(uint32_t, Int32Ty, NRecords, \
+ llvm::ConstantInt::get(Int32Ty, FunctionRecords.size()))
+COVMAP_HEADER(uint32_t, Int32Ty, FilenamesSize, \
+ llvm::ConstantInt::get(Int32Ty, FilenamesSize))
+COVMAP_HEADER(uint32_t, Int32Ty, CoverageSize, \
+ llvm::ConstantInt::get(Int32Ty, CoverageMappingSize))
+COVMAP_HEADER(uint32_t, Int32Ty, Version, \
+ llvm::ConstantInt::get(Int32Ty, CoverageMappingVersion1))
+#undef COVMAP_HEADER
+/* COVMAP_HEADER end. */
+
#ifdef INSTR_PROF_VALUE_PROF_DATA
#define INSTR_PROF_DATA_DEFINED
diff --git a/lib/profile/InstrProfilingFile.c b/lib/profile/InstrProfilingFile.c
index 4ea7fbf9738a..bf50c02761d3 100644
--- a/lib/profile/InstrProfilingFile.c
+++ b/lib/profile/InstrProfilingFile.c
@@ -17,6 +17,10 @@
#define UNCONST(ptr) ((void *)(uintptr_t)(ptr))
+#ifdef _MSC_VER
+#define snprintf _snprintf
+#endif
+
/* Return 1 if there is an error, otherwise return 0. */
static uint32_t fileWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs,
void **WriterCtx) {
diff --git a/lib/profile/InstrProfilingPort.h b/lib/profile/InstrProfilingPort.h
index da4f18fcbb46..5da814a4a3d7 100644
--- a/lib/profile/InstrProfilingPort.h
+++ b/lib/profile/InstrProfilingPort.h
@@ -47,26 +47,12 @@
if (GetEnvHook && GetEnvHook("LLVM_PROFILE_VERBOSE_ERRORS")) \
fprintf(stderr, Format, __VA_ARGS__);
-#if defined(__FreeBSD__) && defined(__i386__)
+#if defined(__FreeBSD__)
-/* System headers define 'size_t' incorrectly on x64 FreeBSD (prior to
- * FreeBSD 10, r232261) when compiled in 32-bit mode.
- */
-#define PRIu64 "llu"
-typedef unsigned char uint8_t;
-typedef unsigned short uint16_t;
-typedef unsigned int uint32_t;
-typedef unsigned long long uint64_t;
-typedef uint32_t uintptr_t;
-#elif defined(__FreeBSD__) && defined(__x86_64__)
-#define PRIu64 "lu"
-typedef unsigned char uint8_t;
-typedef unsigned short uint16_t;
-typedef unsigned int uint32_t;
-typedef unsigned long long uint64_t;
-typedef unsigned long int uintptr_t;
+#include <inttypes.h>
+#include <sys/types.h>
-#else /* defined(__FreeBSD__) && defined(__i386__) */
+#else /* defined(__FreeBSD__) */
#include <inttypes.h>
#include <stdint.h>
diff --git a/lib/profile/WindowsMMap.c b/lib/profile/WindowsMMap.c
new file mode 100644
index 000000000000..1f7342050032
--- /dev/null
+++ b/lib/profile/WindowsMMap.c
@@ -0,0 +1,128 @@
+/*
+ * This code is derived from uClibc (original license follows).
+ * https://git.uclibc.org/uClibc/tree/utils/mmap-windows.c
+ */
+ /* mmap() replacement for Windows
+ *
+ * Author: Mike Frysinger <vapier@gentoo.org>
+ * Placed into the public domain
+ */
+
+/* References:
+ * CreateFileMapping: http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx
+ * CloseHandle: http://msdn.microsoft.com/en-us/library/ms724211(VS.85).aspx
+ * MapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366761(VS.85).aspx
+ * UnmapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366882(VS.85).aspx
+ */
+
+#if defined(_WIN32)
+
+#include "WindowsMMap.h"
+#include "InstrProfiling.h"
+
+#ifdef __USE_FILE_OFFSET64
+# define DWORD_HI(x) (x >> 32)
+# define DWORD_LO(x) ((x) & 0xffffffff)
+#else
+# define DWORD_HI(x) (0)
+# define DWORD_LO(x) (x)
+#endif
+
+COMPILER_RT_VISIBILITY
+void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
+{
+ if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
+ return MAP_FAILED;
+ if (fd == -1) {
+ if (!(flags & MAP_ANON) || offset)
+ return MAP_FAILED;
+ } else if (flags & MAP_ANON)
+ return MAP_FAILED;
+
+ DWORD flProtect;
+ if (prot & PROT_WRITE) {
+ if (prot & PROT_EXEC)
+ flProtect = PAGE_EXECUTE_READWRITE;
+ else
+ flProtect = PAGE_READWRITE;
+ } else if (prot & PROT_EXEC) {
+ if (prot & PROT_READ)
+ flProtect = PAGE_EXECUTE_READ;
+ else if (prot & PROT_EXEC)
+ flProtect = PAGE_EXECUTE;
+ } else
+ flProtect = PAGE_READONLY;
+
+ off_t end = length + offset;
+ HANDLE mmap_fd, h;
+ if (fd == -1)
+ mmap_fd = INVALID_HANDLE_VALUE;
+ else
+ mmap_fd = (HANDLE)_get_osfhandle(fd);
+ h = CreateFileMapping(mmap_fd, NULL, flProtect, DWORD_HI(end), DWORD_LO(end), NULL);
+ if (h == NULL)
+ return MAP_FAILED;
+
+ DWORD dwDesiredAccess;
+ if (prot & PROT_WRITE)
+ dwDesiredAccess = FILE_MAP_WRITE;
+ else
+ dwDesiredAccess = FILE_MAP_READ;
+ if (prot & PROT_EXEC)
+ dwDesiredAccess |= FILE_MAP_EXECUTE;
+ if (flags & MAP_PRIVATE)
+ dwDesiredAccess |= FILE_MAP_COPY;
+ void *ret = MapViewOfFile(h, dwDesiredAccess, DWORD_HI(offset), DWORD_LO(offset), length);
+ if (ret == NULL) {
+ CloseHandle(h);
+ ret = MAP_FAILED;
+ }
+ return ret;
+}
+
+COMPILER_RT_VISIBILITY
+void munmap(void *addr, size_t length)
+{
+ UnmapViewOfFile(addr);
+ /* ruh-ro, we leaked handle from CreateFileMapping() ... */
+}
+
+COMPILER_RT_VISIBILITY
+int msync(void *addr, size_t length, int flags)
+{
+ if (flags & MS_INVALIDATE)
+ return -1; /* Not supported. */
+
+ /* Exactly one of MS_ASYNC or MS_SYNC must be specified. */
+ switch (flags & (MS_ASYNC | MS_SYNC)) {
+ case MS_SYNC:
+ case MS_ASYNC:
+ break;
+ default:
+ return -1;
+ }
+
+ if (!FlushViewOfFile(addr, length))
+ return -1;
+
+ if (flags & MS_SYNC) {
+ /* FIXME: No longer have access to handle from CreateFileMapping(). */
+ /*
+ * if (!FlushFileBuffers(h))
+ * return -1;
+ */
+ }
+
+ return 0;
+}
+
+COMPILER_RT_VISIBILITY
+int flock(int fd, int operation)
+{
+ return -1; /* Not supported. */
+}
+
+#undef DWORD_HI
+#undef DWORD_LO
+
+#endif /* _WIN32 */
diff --git a/lib/profile/WindowsMMap.h b/lib/profile/WindowsMMap.h
new file mode 100644
index 000000000000..7b94eb28230c
--- /dev/null
+++ b/lib/profile/WindowsMMap.h
@@ -0,0 +1,65 @@
+/*===- WindowsMMap.h - Support library for PGO instrumentation ------------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#ifndef PROFILE_INSTRPROFILING_WINDOWS_MMAP_H
+#define PROFILE_INSTRPROFILING_WINDOWS_MMAP_H
+
+#if defined(_WIN32)
+
+#include <BaseTsd.h>
+#include <io.h>
+#include <sys/types.h>
+
+/*
+ * mmap() flags
+ */
+#define PROT_READ 0x1
+#define PROT_WRITE 0x2
+/* This flag is only available in WinXP+ */
+#ifdef FILE_MAP_EXECUTE
+#define PROT_EXEC 0x4
+#else
+#define PROT_EXEC 0x0
+#define FILE_MAP_EXECUTE 0
+#endif
+
+#define MAP_FILE 0x00
+#define MAP_SHARED 0x01
+#define MAP_PRIVATE 0x02
+#define MAP_ANONYMOUS 0x20
+#define MAP_ANON MAP_ANONYMOUS
+#define MAP_FAILED ((void *) -1)
+
+/*
+ * msync() flags
+ */
+#define MS_ASYNC 0x0001 /* return immediately */
+#define MS_INVALIDATE 0x0002 /* invalidate all cached data */
+#define MS_SYNC 0x0010 /* msync synchronously */
+
+/*
+ * flock() operations
+ */
+#define LOCK_SH 1 /* shared lock */
+#define LOCK_EX 2 /* exclusive lock */
+#define LOCK_NB 4 /* don't block when locking */
+#define LOCK_UN 8 /* unlock */
+
+void *mmap(void *start, size_t length, int prot, int flags, int fd,
+ off_t offset);
+
+void munmap(void *addr, size_t length);
+
+int msync(void *addr, size_t length, int flags);
+
+int flock(int fd, int operation);
+
+#endif /* _WIN32 */
+
+#endif /* PROFILE_INSTRPROFILING_WINDOWS_MMAP_H */
diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
index b9833c5a1d97..eaa1446afd44 100644
--- a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
@@ -108,6 +108,7 @@ class CoverageData {
uptr *data();
uptr size();
+ uptr *buffer() const { return pc_buffer; }
private:
void DirectOpen();
@@ -133,6 +134,8 @@ class CoverageData {
// Descriptor of the file mapped pc array.
fd_t pc_fd;
+ uptr *pc_buffer;
+
// Vector of coverage guard arrays, protected by mu.
InternalMmapVectorNoCtor<s32*> guard_array_vec;
@@ -209,6 +212,11 @@ void CoverageData::Enable() {
atomic_store(&pc_array_size, kPcArrayMaxSize, memory_order_relaxed);
}
+ pc_buffer = nullptr;
+ if (common_flags()->coverage_pc_buffer)
+ pc_buffer = reinterpret_cast<uptr *>(MmapNoReserveOrDie(
+ sizeof(uptr) * kPcArrayMaxSize, "CovInit::pc_buffer"));
+
cc_array = reinterpret_cast<uptr **>(MmapNoReserveOrDie(
sizeof(uptr *) * kCcArrayMaxSize, "CovInit::cc_array"));
atomic_store(&cc_array_size, kCcArrayMaxSize, memory_order_relaxed);
@@ -246,6 +254,10 @@ void CoverageData::Disable() {
UnmapOrDie(cc_array, sizeof(uptr *) * kCcArrayMaxSize);
cc_array = nullptr;
}
+ if (pc_buffer) {
+ UnmapOrDie(pc_buffer, sizeof(uptr) * kPcArrayMaxSize);
+ pc_buffer = nullptr;
+ }
if (tr_event_array) {
UnmapOrDie(tr_event_array,
sizeof(tr_event_array[0]) * kTrEventArrayMaxSize +
@@ -414,6 +426,7 @@ void CoverageData::Add(uptr pc, u32 *guard) {
atomic_load(&pc_array_size, memory_order_acquire));
uptr counter = atomic_fetch_add(&coverage_counter, 1, memory_order_relaxed);
pc_array[idx] = BundlePcAndCounter(pc, counter);
+ if (pc_buffer) pc_buffer[counter] = pc;
}
// Registers a pair caller=>callee.
@@ -944,6 +957,12 @@ uptr __sanitizer_get_coverage_guards(uptr **data) {
}
SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_coverage_pc_buffer(uptr **data) {
+ *data = coverage_data.buffer();
+ return __sanitizer_get_total_unique_coverage();
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
uptr __sanitizer_get_number_of_counters() {
return coverage_data.GetNumberOf8bitCounters();
}
diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc
index c89273117a5e..c28f7f4a6034 100644
--- a/lib/sanitizer_common/sanitizer_flags.inc
+++ b/lib/sanitizer_common/sanitizer_flags.inc
@@ -144,6 +144,9 @@ COMMON_FLAG(bool, coverage_direct, SANITIZER_ANDROID,
COMMON_FLAG(const char *, coverage_dir, ".",
"Target directory for coverage dumps. Defaults to the current "
"directory.")
+COMMON_FLAG(bool, coverage_pc_buffer, true,
+ "If set (and if 'coverage' is set too), the pcs would be collected "
+ "in a buffer.")
COMMON_FLAG(bool, full_address_space, false,
"Sanitize complete address space; "
"by default kernel area on 32-bit platforms will not be sanitized")
diff --git a/test/asan/TestCases/coverage-pc-buffer.cc b/test/asan/TestCases/coverage-pc-buffer.cc
new file mode 100644
index 000000000000..67b6935ec602
--- /dev/null
+++ b/test/asan/TestCases/coverage-pc-buffer.cc
@@ -0,0 +1,48 @@
+// Test __sanitizer_coverage_pc_buffer().
+
+// RUN: %clangxx_asan -fsanitize-coverage=edge %s -o %t && %run %t
+
+// UNSUPPORTED: android
+
+#include <assert.h>
+#include <sanitizer/coverage_interface.h>
+#include <stdio.h>
+
+static volatile int sink;
+__attribute__((noinline)) void bar() { sink = 2; }
+__attribute__((noinline)) void foo() { sink = 1; }
+
+void assertNotZeroPcs(uintptr_t *buf, uintptr_t size) {
+ assert(buf);
+ for (uintptr_t i = 0; i < size; ++i)
+ assert(buf[i]);
+}
+
+int main() {
+ uintptr_t *buf = NULL;
+ uintptr_t sz = __sanitizer_get_coverage_pc_buffer(&buf);
+ assertNotZeroPcs(buf, sz);
+ assert(sz);
+
+ foo();
+ bar();
+ uintptr_t *buf1 = NULL;
+ uintptr_t sz1 = __sanitizer_get_coverage_pc_buffer(&buf1);
+ assertNotZeroPcs(buf1, sz1);
+ assert(buf1 == buf);
+ assert(sz1 > sz);
+
+ bar();
+ uintptr_t *buf2 = NULL;
+ uintptr_t sz2 = __sanitizer_get_coverage_pc_buffer(&buf2);
+ assertNotZeroPcs(buf2, sz2);
+ assert(buf2 == buf);
+ assert(sz2 > sz1);
+
+ __sanitizer_reset_coverage();
+ uintptr_t *buf3 = NULL;
+ uintptr_t sz3 = __sanitizer_get_coverage_pc_buffer(&buf3);
+ assertNotZeroPcs(buf3, sz3);
+ assert(buf3 == buf);
+ assert(sz3 < sz2);
+}