summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKamil Rytarowski <n54@gmx.com>2018-02-15 14:17:15 +0000
committerKamil Rytarowski <n54@gmx.com>2018-02-15 14:17:15 +0000
commit8dde6e6cf5a5ac8fcb6894d647322c32491f5f4f (patch)
tree81b812c62404a151114c5f223d70d0cc527c04d5
parent9a797cae14217a85a22fbb2dc3581c56624c5303 (diff)
Add Xray instrumentation support to FreeBSD
Summary: - Enabling the build. - Using assembly for the cpuid parts. - Using thr_self FreeBSD call to get the thread id Patch by: David CARLIER Reviewers: dberris, rnk, krytarowski Reviewed By: dberris, krytarowski Subscribers: emaste, stevecheckoway, nglevin, srhines, kubamracek, dberris, mgorny, krytarowski, llvm-commits, #sanitizers Differential Revision: https://reviews.llvm.org/D43278 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@325240 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--cmake/config-ix.cmake2
-rw-r--r--lib/sanitizer_common/sanitizer_internal_defs.h3
-rw-r--r--lib/xray/tests/CMakeLists.txt7
-rw-r--r--lib/xray/tests/unit/fdr_logging_test.cc11
-rw-r--r--lib/xray/xray_fdr_logging_impl.h11
-rw-r--r--lib/xray/xray_flags.inc2
-rw-r--r--lib/xray/xray_inmemory_log.cc2
-rw-r--r--lib/xray/xray_x86_64.cc26
-rw-r--r--lib/xray/xray_x86_64.inc5
-rw-r--r--test/xray/lit.cfg12
10 files changed, 59 insertions, 22 deletions
diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake
index c7b959e79..ac2465b8b 100644
--- a/cmake/config-ix.cmake
+++ b/cmake/config-ix.cmake
@@ -597,7 +597,7 @@ else()
endif()
if (COMPILER_RT_HAS_SANITIZER_COMMON AND XRAY_SUPPORTED_ARCH AND
- OS_NAME MATCHES "Darwin|Linux")
+ OS_NAME MATCHES "Darwin|Linux|FreeBSD")
set(COMPILER_RT_HAS_XRAY TRUE)
else()
set(COMPILER_RT_HAS_XRAY FALSE)
diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h
index e031f50d7..b91170b40 100644
--- a/lib/sanitizer_common/sanitizer_internal_defs.h
+++ b/lib/sanitizer_common/sanitizer_internal_defs.h
@@ -98,7 +98,8 @@
// We can use .preinit_array section on Linux to call sanitizer initialization
// functions very early in the process startup (unless PIC macro is defined).
// FIXME: do we have anything like this on Mac?
-#if SANITIZER_LINUX && !SANITIZER_ANDROID && !defined(PIC)
+#if ((SANITIZER_LINUX && !SANITIZER_ANDROID) || \
+ SANITIZER_FREEBSD) && !defined(PIC)
# define SANITIZER_CAN_USE_PREINIT_ARRAY 1
// Before Solaris 11.4, .preinit_array is fully supported only with GNU ld.
// FIXME: Check for those conditions.
diff --git a/lib/xray/tests/CMakeLists.txt b/lib/xray/tests/CMakeLists.txt
index e54e63f27..b5c7d8fa7 100644
--- a/lib/xray/tests/CMakeLists.txt
+++ b/lib/xray/tests/CMakeLists.txt
@@ -15,6 +15,10 @@ set(XRAY_TEST_ARCH ${XRAY_SUPPORTED_ARCH})
macro(add_xray_unittest testname)
cmake_parse_arguments(TEST "" "" "SOURCES;HEADERS" ${ARGN})
if(UNIX AND NOT APPLE)
+ set(CMAKE_DL_LIBS_INIT "")
+ foreach(lib ${CMAKE_DL_LIBS})
+ list(APPEND CMAKE_DL_LIBS_INIT -l${lib})
+ endforeach()
foreach(arch ${XRAY_TEST_ARCH})
set(TEST_OBJECTS)
generate_compiler_rt_tests(TEST_OBJECTS
@@ -25,8 +29,7 @@ macro(add_xray_unittest testname)
LINK_FLAGS -fxray-instrument
${TARGET_LINK_FLAGS}
-lstdc++ -lm ${CMAKE_THREAD_LIBS_INIT}
- -lpthread
- -ldl -lrt)
+ ${CMAKE_DL_LIBS_INIT} -lrt)
set_target_properties(XRayUnitTests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
endforeach()
endif()
diff --git a/lib/xray/tests/unit/fdr_logging_test.cc b/lib/xray/tests/unit/fdr_logging_test.cc
index 76738ea4d..98802e0a1 100644
--- a/lib/xray/tests/unit/fdr_logging_test.cc
+++ b/lib/xray/tests/unit/fdr_logging_test.cc
@@ -10,6 +10,7 @@
// This file is a part of XRay, a function call tracing system.
//
//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_common.h"
#include "xray_fdr_logging.h"
#include "gtest/gtest.h"
@@ -154,12 +155,12 @@ TEST(FDRLoggingTest, MultiThreadedCycling) {
// Now we want to create one thread, do some logging, then create another one,
// in succession and making sure that we're able to get thread records from
// the latest thread (effectively being able to recycle buffers).
- std::array<pid_t, 2> Threads;
+ std::array<tid_t, 2> Threads;
for (uint64_t I = 0; I < 2; ++I) {
std::thread t{[I, &Threads] {
fdrLoggingHandleArg0(I + 1, XRayEntryType::ENTRY);
fdrLoggingHandleArg0(I + 1, XRayEntryType::EXIT);
- Threads[I] = syscall(SYS_gettid);
+ Threads[I] = __sanitizer::GetTid();
}};
t.join();
}
@@ -192,9 +193,9 @@ TEST(FDRLoggingTest, MultiThreadedCycling) {
ASSERT_EQ(MDR0.RecordKind,
uint8_t(MetadataRecord::RecordKinds::BufferExtents));
ASSERT_EQ(MDR1.RecordKind, uint8_t(MetadataRecord::RecordKinds::NewBuffer));
- pid_t Latest = 0;
- memcpy(&Latest, MDR1.Data, sizeof(pid_t));
- ASSERT_EQ(Latest, Threads[1]);
+ int32_t Latest = 0;
+ memcpy(&Latest, MDR1.Data, sizeof(int32_t));
+ ASSERT_EQ(Latest, static_cast<int32_t>(Threads[1]));
}
} // namespace
diff --git a/lib/xray/xray_fdr_logging_impl.h b/lib/xray/xray_fdr_logging_impl.h
index d1cbda962..ed0b5ca90 100644
--- a/lib/xray/xray_fdr_logging_impl.h
+++ b/lib/xray/xray_fdr_logging_impl.h
@@ -54,7 +54,7 @@ namespace __xray_fdr_internal {
/// Writes the new buffer record and wallclock time that begin a buffer for the
/// current thread.
-static void writeNewBufferPreamble(pid_t Tid, timespec TS);
+static void writeNewBufferPreamble(tid_t Tid, timespec TS);
/// Writes a Function Record to the buffer associated with the current thread.
static void writeFunctionRecord(int FuncId, uint32_t TSCDelta,
@@ -185,7 +185,7 @@ public:
} // namespace
-static void writeNewBufferPreamble(pid_t Tid,
+static void writeNewBufferPreamble(tid_t Tid,
timespec TS) XRAY_NEVER_INSTRUMENT {
static constexpr int InitRecordsCount = 2;
auto &TLD = getThreadLocalData();
@@ -195,11 +195,12 @@ static void writeNewBufferPreamble(pid_t Tid,
// buffer, associated with a particular thread, with a new CPU. For the
// data, we have 15 bytes to squeeze as much information as we can. At this
// point we only write down the following bytes:
- // - Thread ID (pid_t, 4 bytes)
+ // - Thread ID (tid_t, cast to 4 bytes type due to Darwin being 8 bytes)
auto &NewBuffer = Metadata[0];
NewBuffer.Type = uint8_t(RecordType::Metadata);
NewBuffer.RecordKind = uint8_t(MetadataRecord::RecordKinds::NewBuffer);
- std::memcpy(&NewBuffer.Data, &Tid, sizeof(pid_t));
+ int32_t tid = static_cast<int32_t>(Tid);
+ std::memcpy(&NewBuffer.Data, &tid, sizeof(tid));
}
// Also write the WalltimeMarker record.
@@ -236,7 +237,7 @@ inline void setupNewBuffer(int (*wall_clock_reader)(
auto &TLD = getThreadLocalData();
auto &B = TLD.Buffer;
TLD.RecordPtr = static_cast<char *>(B.Data);
- pid_t Tid = syscall(SYS_gettid);
+ tid_t Tid = __sanitizer::GetTid();
timespec TS{0, 0};
// This is typically clock_gettime, but callers have injection ability.
wall_clock_reader(CLOCK_MONOTONIC, &TS);
diff --git a/lib/xray/xray_flags.inc b/lib/xray/xray_flags.inc
index 29f1fce7d..181ed3d7f 100644
--- a/lib/xray/xray_flags.inc
+++ b/lib/xray/xray_flags.inc
@@ -31,7 +31,7 @@ XRAY_FLAG(int, xray_naive_log_func_duration_threshold_us, 5,
"microseconds than this threshold.")
XRAY_FLAG(int, xray_naive_log_max_stack_depth, 64,
"Naive logging will keep track of at most this deep a call stack, "
- "any more and the recordings will be droppped.")
+ "any more and the recordings will be dropped.")
XRAY_FLAG(int, xray_naive_log_thread_buffer_size, 1024,
"The number of entries to keep on a per-thread buffer.")
diff --git a/lib/xray/xray_inmemory_log.cc b/lib/xray/xray_inmemory_log.cc
index d54fd8f6b..ae437766f 100644
--- a/lib/xray/xray_inmemory_log.cc
+++ b/lib/xray/xray_inmemory_log.cc
@@ -60,7 +60,7 @@ struct alignas(64) ThreadLocalData {
size_t StackSize = 0;
size_t StackEntries = 0;
int Fd = -1;
- pid_t TID = 0;
+ tid_t TID = 0;
};
static pthread_key_t PThreadKey;
diff --git a/lib/xray/xray_x86_64.cc b/lib/xray/xray_x86_64.cc
index e17f00ac3..1504c7b22 100644
--- a/lib/xray/xray_x86_64.cc
+++ b/lib/xray/xray_x86_64.cc
@@ -3,6 +3,10 @@
#include "xray_defs.h"
#include "xray_interface_internal.h"
+#if SANITIZER_FREEBSD
+#include <sys/sysctl.h>
+#endif
+
#include <atomic>
#include <cstdint>
#include <errno.h>
@@ -14,6 +18,7 @@
namespace __xray {
+#if SANITIZER_LINUX
static std::pair<ssize_t, bool>
retryingReadSome(int Fd, char *Begin, char *End) XRAY_NEVER_INSTRUMENT {
auto BytesToRead = std::distance(Begin, End);
@@ -71,6 +76,24 @@ uint64_t getTSCFrequency() XRAY_NEVER_INSTRUMENT {
}
return TSCFrequency == -1 ? 0 : static_cast<uint64_t>(TSCFrequency);
}
+#elif SANITIZER_FREEBSD
+uint64_t getTSCFrequency() XRAY_NEVER_INSTRUMENT {
+ long long TSCFrequency = -1;
+ size_t tscfreqsz = sizeof(TSCFrequency);
+
+ if (sysctlbyname("machdep.tsc_freq", &TSCFrequency, &tscfreqsz,
+ NULL, 0) != -1) {
+ return static_cast<uint64_t>(TSCFrequency);
+ } else {
+ Report("Unable to determine CPU frequency for TSC accounting.\n");
+ }
+
+ return 0;
+
+}
+#else
+#error "Platform not supported"
+#endif
static constexpr uint8_t CallOpCode = 0xe8;
static constexpr uint16_t MovR10Seq = 0xba41;
@@ -259,7 +282,8 @@ bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT {
// We check whether rdtscp support is enabled. According to the x86_64 manual,
// level should be set at 0x80000001, and we should have a look at bit 27 in
// EDX. That's 0x8000000 (or 1u << 27).
- __get_cpuid(0x80000001, &EAX, &EBX, &ECX, &EDX);
+ __asm__ __volatile__("cpuid" : "=a"(EAX), "=b"(EBX), "=c"(ECX), "=d"(EDX)
+ : "0"(0x80000001));
if (!(EDX & (1u << 27))) {
Report("Missing rdtscp support.\n");
return false;
diff --git a/lib/xray/xray_x86_64.inc b/lib/xray/xray_x86_64.inc
index 4ad3f9810..b3c475f91 100644
--- a/lib/xray/xray_x86_64.inc
+++ b/lib/xray/xray_x86_64.inc
@@ -21,9 +21,10 @@ namespace __xray {
ALWAYS_INLINE uint64_t readTSC(uint8_t &CPU) XRAY_NEVER_INSTRUMENT {
unsigned LongCPU;
- uint64_t TSC = __rdtscp(&LongCPU);
+ unsigned long Rax, Rdx;
+ __asm__ __volatile__("rdtscp\n" : "=a"(Rax), "=d"(Rdx), "=c"(LongCPU) ::);
CPU = LongCPU;
- return TSC;
+ return (Rdx << 32) + Rax;
}
uint64_t getTSCFrequency();
diff --git a/test/xray/lit.cfg b/test/xray/lit.cfg
index d5e40975d..c0eeea0cf 100644
--- a/test/xray/lit.cfg
+++ b/test/xray/lit.cfg
@@ -20,6 +20,13 @@ def build_invocation(compile_flags):
llvm_xray = os.path.join(config.llvm_tools_dir, 'llvm-xray')
# Setup substitutions.
+xraylib_flags = '-lm -pthread -lrt'
+if config.host_os == 'Linux':
+ xraylib_flags += ' -ldl'
+
+xraylib_flags += ' -L%s -Wl,-whole-archive -lclang_rt.xray-%s '
+'-Wl,-no-whole-archive'
+
config.substitutions.append(
('%clang ', build_invocation([config.target_cflags])))
config.substitutions.append(
@@ -33,14 +40,13 @@ config.substitutions.append(
('%llvm_xray', llvm_xray))
config.substitutions.append(
('%xraylib',
- ('-lm -lpthread -ldl -lrt -L%s '
- '-Wl,-whole-archive -lclang_rt.xray-%s -Wl,-no-whole-archive')
+ (xraylib_flags)
% (config.compiler_rt_libdir, config.host_arch)))
# Default test suffixes.
config.suffixes = ['.c', '.cc', '.cpp']
-if config.host_os not in ['Linux']:
+if config.host_os not in ['Linux', 'FreeBSD']:
config.unsupported = True
elif '64' not in config.host_arch:
if 'arm' in config.host_arch: