diff options
author | Kamil Rytarowski <n54@gmx.com> | 2018-02-15 14:17:15 +0000 |
---|---|---|
committer | Kamil Rytarowski <n54@gmx.com> | 2018-02-15 14:17:15 +0000 |
commit | 8dde6e6cf5a5ac8fcb6894d647322c32491f5f4f (patch) | |
tree | 81b812c62404a151114c5f223d70d0cc527c04d5 | |
parent | 9a797cae14217a85a22fbb2dc3581c56624c5303 (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.cmake | 2 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_internal_defs.h | 3 | ||||
-rw-r--r-- | lib/xray/tests/CMakeLists.txt | 7 | ||||
-rw-r--r-- | lib/xray/tests/unit/fdr_logging_test.cc | 11 | ||||
-rw-r--r-- | lib/xray/xray_fdr_logging_impl.h | 11 | ||||
-rw-r--r-- | lib/xray/xray_flags.inc | 2 | ||||
-rw-r--r-- | lib/xray/xray_inmemory_log.cc | 2 | ||||
-rw-r--r-- | lib/xray/xray_x86_64.cc | 26 | ||||
-rw-r--r-- | lib/xray/xray_x86_64.inc | 5 | ||||
-rw-r--r-- | test/xray/lit.cfg | 12 |
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: |