[XRay][compiler-rt] Disable XRay instrumentation of the XRay runtime.

Summary:
Adds a CMake check for whether the compiler used to build the XRay
library supports XRay-instrumentation. If the compiler we're using does
support the `-fxray-instrument` flag (i.e. recently-built Clang), we
define the XRAY_NEVER_INSTRUMENT macro that then makes sure that the
XRay runtime functions never get XRay-instrumented.

This prevents potential weirdness involved with building the XRay
library with a Clang that supports XRay-instrumentation, and is
attempting to XRay-instrument the build of compiler-rt.

Reviewers: majnemer, rSerge, echristo

Subscribers: mehdi_amini, llvm-commits, mgorny

Differential Revision: https://reviews.llvm.org/D26597

llvm-svn: 287068
This commit is contained in:
Dean Michael Berris 2016-11-16 01:01:13 +00:00
parent fb1e6d22a3
commit 4031e4b95d
9 changed files with 120 additions and 65 deletions

View File

@ -4,6 +4,7 @@ include(CheckCSourceCompiles)
# Make all the tests only check the compiler
set(TEST_COMPILE_ONLY On)
# Check host compiler support for certain flags
builtin_check_c_compiler_flag(-fPIC COMPILER_RT_HAS_FPIC_FLAG)
builtin_check_c_compiler_flag(-fPIE COMPILER_RT_HAS_FPIE_FLAG)
builtin_check_c_compiler_flag(-fno-builtin COMPILER_RT_HAS_FNO_BUILTIN_FLAG)
@ -11,6 +12,7 @@ builtin_check_c_compiler_flag(-std=c99 COMPILER_RT_HAS_STD_C99_FLAG
builtin_check_c_compiler_flag(-fvisibility=hidden COMPILER_RT_HAS_VISIBILITY_HIDDEN_FLAG)
builtin_check_c_compiler_flag(-fomit-frame-pointer COMPILER_RT_HAS_OMIT_FRAME_POINTER_FLAG)
builtin_check_c_compiler_flag(-ffreestanding COMPILER_RT_HAS_FREESTANDING_FLAG)
builtin_check_c_compiler_flag(-fxray-instrument COMPILER_RT_HAS_XRAY_COMPILER_FLAG)
builtin_check_c_compiler_source(COMPILER_RT_HAS_ATOMIC_KEYWORD
"

View File

@ -2,20 +2,20 @@
set(XRAY_SOURCES
xray_init.cc
xray_interface.cc
xray_flags.cc
xray_interface.cc
xray_flags.cc
xray_inmemory_log.cc
)
set(x86_64_SOURCES
xray_x86_64.cc
xray_trampoline_x86_64.S
${XRAY_SOURCES})
xray_x86_64.cc
xray_trampoline_x86_64.S
${XRAY_SOURCES})
set(arm_SOURCES
xray_arm.cc
xray_trampoline_arm.S
${XRAY_SOURCES})
xray_arm.cc
xray_trampoline_arm.S
${XRAY_SOURCES})
set(armhf_SOURCES ${arm_SOURCES})
@ -25,6 +25,8 @@ include_directories(../../include)
set(XRAY_CFLAGS ${SANITIZER_COMMON_CFLAGS})
set(XRAY_COMMON_DEFINITIONS XRAY_HAS_EXCEPTIONS=1)
append_list_if(
COMPILER_RT_HAS_XRAY_COMPILER_FLAG XRAY_SUPPORTED=1 XRAY_COMMON_DEFINITIONS)
add_compiler_rt_object_libraries(RTXray
ARCHS ${XRAY_SUPPORTED_ARCH}
@ -34,18 +36,18 @@ add_compiler_rt_object_libraries(RTXray
add_compiler_rt_component(xray)
set(XRAY_COMMON_RUNTIME_OBJECT_LIBS
RTSanitizerCommon
RTSanitizerCommonLibc)
RTSanitizerCommon
RTSanitizerCommonLibc)
foreach (arch ${XRAY_SUPPORTED_ARCH})
if (CAN_TARGET_${arch})
add_compiler_rt_runtime(clang_rt.xray
STATIC
ARCHS ${arch}
SOURCES ${${arch}_SOURCES}
CFLAGS ${XRAY_CFLAGS}
DEFS ${XRAY_COMMON_DEFINITIONS}
OBJECT_LIBS ${XRAY_COMMON_RUNTIME_OBJECT_LIBS}
PARENT_TARGET xray)
endif ()
if (CAN_TARGET_${arch})
add_compiler_rt_runtime(clang_rt.xray
STATIC
ARCHS ${arch}
SOURCES ${${arch}_SOURCES}
CFLAGS ${XRAY_CFLAGS}
DEFS ${XRAY_COMMON_DEFINITIONS}
OBJECT_LIBS ${XRAY_COMMON_RUNTIME_OBJECT_LIBS}
PARENT_TARGET xray)
endif ()
endforeach()

View File

@ -28,20 +28,21 @@ enum class PatchOpcodes : uint32_t {
};
// 0xUUUUWXYZ -> 0x000W0XYZ
inline static uint32_t getMovwMask(const uint32_t Value) {
inline static uint32_t getMovwMask(const uint32_t Value) XRAY_NEVER_INSTRUMENT {
return (Value & 0xfff) | ((Value & 0xf000) << 4);
}
// 0xWXYZUUUU -> 0x000W0XYZ
inline static uint32_t getMovtMask(const uint32_t Value) {
inline static uint32_t getMovtMask(const uint32_t Value) XRAY_NEVER_INSTRUMENT {
return getMovwMask(Value >> 16);
}
// Writes the following instructions:
// MOVW R<regNo>, #<lower 16 bits of the |Value|>
// MOVT R<regNo>, #<higher 16 bits of the |Value|>
inline static uint32_t *write32bitLoadReg(uint8_t regNo, uint32_t *Address,
const uint32_t Value) {
inline static uint32_t *
write32bitLoadReg(uint8_t regNo, uint32_t *Address,
const uint32_t Value) XRAY_NEVER_INSTRUMENT {
// This is a fatal error: we cannot just report it and continue execution.
assert(regNo <= 15 && "Register number must be 0 to 15.");
// MOVW R, #0xWXYZ in machine code is 0xE30WRXYZ
@ -55,21 +56,24 @@ inline static uint32_t *write32bitLoadReg(uint8_t regNo, uint32_t *Address,
// Writes the following instructions:
// MOVW r0, #<lower 16 bits of the |Value|>
// MOVT r0, #<higher 16 bits of the |Value|>
inline static uint32_t *Write32bitLoadR0(uint32_t *Address,
const uint32_t Value) {
inline static uint32_t *
Write32bitLoadR0(uint32_t *Address,
const uint32_t Value) XRAY_NEVER_INSTRUMENT {
return write32bitLoadReg(0, Address, Value);
}
// Writes the following instructions:
// MOVW ip, #<lower 16 bits of the |Value|>
// MOVT ip, #<higher 16 bits of the |Value|>
inline static uint32_t *Write32bitLoadIP(uint32_t *Address,
const uint32_t Value) {
inline static uint32_t *
Write32bitLoadIP(uint32_t *Address,
const uint32_t Value) XRAY_NEVER_INSTRUMENT {
return write32bitLoadReg(12, Address, Value);
}
inline static bool patchSled(const bool Enable, const uint32_t FuncId,
const XRaySledEntry &Sled, void (*TracingHook)()) {
const XRaySledEntry &Sled,
void (*TracingHook)()) XRAY_NEVER_INSTRUMENT {
// When |Enable| == true,
// We replace the following compile-time stub (sled):
//
@ -118,17 +122,17 @@ inline static bool patchSled(const bool Enable, const uint32_t FuncId,
}
bool patchFunctionEntry(const bool Enable, const uint32_t FuncId,
const XRaySledEntry &Sled) {
const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
return patchSled(Enable, FuncId, Sled, __xray_FunctionEntry);
}
bool patchFunctionExit(const bool Enable, const uint32_t FuncId,
const XRaySledEntry &Sled) {
const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
return patchSled(Enable, FuncId, Sled, __xray_FunctionExit);
}
bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId,
const XRaySledEntry &Sled) {
const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
// FIXME: In the future we'd need to distinguish between non-tail exits and
// tail exits for better information preservation.
return patchSled(Enable, FuncId, Sled, __xray_FunctionExit);

View File

@ -0,0 +1,22 @@
//===-- xray_defs.h ---------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Common definitions useful for XRay sources.
//
//===----------------------------------------------------------------------===//
#ifndef XRAY_XRAY_DEFS_H
#define XRAY_XRAY_DEFS_H
#if XRAY_SUPPORTED
#define XRAY_NEVER_INSTRUMENT __attribute__((xray_never_instrument))
#else
#define XRAY_NEVER_INSTRUMENT
#endif
#endif // XRAY_XRAY_DEFS_H

View File

@ -16,6 +16,7 @@
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flag_parser.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "xray_defs.h"
using namespace __sanitizer;
@ -23,20 +24,20 @@ namespace __xray {
Flags xray_flags_dont_use_directly; // use via flags().
void Flags::SetDefaults() {
void Flags::SetDefaults() XRAY_NEVER_INSTRUMENT {
#define XRAY_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
#include "xray_flags.inc"
#undef XRAY_FLAG
}
static void RegisterXRayFlags(FlagParser *P, Flags *F) {
static void RegisterXRayFlags(FlagParser *P, Flags *F) XRAY_NEVER_INSTRUMENT {
#define XRAY_FLAG(Type, Name, DefaultValue, Description) \
RegisterFlag(P, #Name, Description, &F->Name);
#include "xray_flags.inc"
#undef XRAY_FLAG
}
void InitializeFlags() {
void InitializeFlags() XRAY_NEVER_INSTRUMENT {
SetCommonFlagsDefaults();
auto *F = flags();
F->SetDefaults();

View File

@ -18,6 +18,7 @@
#include <unistd.h>
#include "sanitizer_common/sanitizer_common.h"
#include "xray_defs.h"
#include "xray_flags.h"
#include "xray_interface_internal.h"
@ -44,7 +45,7 @@ std::atomic<__xray::XRaySledMap> XRayInstrMap{};
// __xray_init() will do the actual loading of the current process' memory map
// and then proceed to look for the .xray_instr_map section/segment.
void __xray_init() {
void __xray_init() XRAY_NEVER_INSTRUMENT {
InitializeFlags();
if (__start_xray_instr_map == nullptr) {
Report("XRay instrumentation map missing. Not initializing XRay.\n");

View File

@ -35,6 +35,7 @@ static const int64_t NanosecondsPerSecond = 1000LL * 1000 * 1000;
#include "sanitizer_common/sanitizer_libc.h"
#include "xray/xray_records.h"
#include "xray_defs.h"
#include "xray_flags.h"
#include "xray_interface_internal.h"
@ -43,14 +44,16 @@ static const int64_t NanosecondsPerSecond = 1000LL * 1000 * 1000;
// events. We store simple fixed-sized entries in the log for external analysis.
extern "C" {
void __xray_InMemoryRawLog(int32_t FuncId, XRayEntryType Type);
void __xray_InMemoryRawLog(int32_t FuncId,
XRayEntryType Type) XRAY_NEVER_INSTRUMENT;
}
namespace __xray {
std::mutex LogMutex;
static void retryingWriteAll(int Fd, char *Begin, char *End) {
static void retryingWriteAll(int Fd, char *Begin,
char *End) XRAY_NEVER_INSTRUMENT {
if (Begin == End)
return;
auto TotalBytes = std::distance(Begin, End);
@ -69,8 +72,8 @@ static void retryingWriteAll(int Fd, char *Begin, char *End) {
}
#if defined(__x86_64__)
static std::pair<ssize_t, bool> retryingReadSome(int Fd, char *Begin,
char *End) {
static std::pair<ssize_t, bool>
retryingReadSome(int Fd, char *Begin, char *End) XRAY_NEVER_INSTRUMENT {
auto BytesToRead = std::distance(Begin, End);
ssize_t BytesRead;
ssize_t TotalBytesRead = 0;
@ -89,7 +92,8 @@ static std::pair<ssize_t, bool> retryingReadSome(int Fd, char *Begin,
return std::make_pair(TotalBytesRead, true);
}
static bool readValueFromFile(const char *Filename, long long *Value) {
static bool readValueFromFile(const char *Filename,
long long *Value) XRAY_NEVER_INSTRUMENT {
int Fd = open(Filename, O_RDONLY | O_CLOEXEC);
if (Fd == -1)
return false;
@ -119,10 +123,13 @@ class ThreadExitFlusher {
size_t &Offset;
public:
explicit ThreadExitFlusher(int Fd, XRayRecord *Start, size_t &Offset)
: Fd(Fd), Start(Start), Offset(Offset) {}
explicit ThreadExitFlusher(int Fd, XRayRecord *Start,
size_t &Offset) XRAY_NEVER_INSTRUMENT
: Fd(Fd),
Start(Start),
Offset(Offset) {}
~ThreadExitFlusher() {
~ThreadExitFlusher() XRAY_NEVER_INSTRUMENT {
std::lock_guard<std::mutex> L(LogMutex);
if (Fd > 0 && Start != nullptr) {
retryingWriteAll(Fd, reinterpret_cast<char *>(Start),
@ -140,9 +147,12 @@ public:
using namespace __xray;
void PrintToStdErr(const char *Buffer) { fprintf(stderr, "%s", Buffer); }
void PrintToStdErr(const char *Buffer) XRAY_NEVER_INSTRUMENT {
fprintf(stderr, "%s", Buffer);
}
void __xray_InMemoryRawLog(int32_t FuncId, XRayEntryType Type) {
void __xray_InMemoryRawLog(int32_t FuncId,
XRayEntryType Type) XRAY_NEVER_INSTRUMENT {
using Buffer =
std::aligned_storage<sizeof(XRayRecord), alignof(XRayRecord)>::type;
static constexpr size_t BuffLen = 1024;

View File

@ -23,6 +23,7 @@
#include <sys/mman.h>
#include "sanitizer_common/sanitizer_common.h"
#include "xray_defs.h"
namespace __xray {
@ -53,11 +54,13 @@ class MProtectHelper {
bool MustCleanup;
public:
explicit MProtectHelper(void *PageAlignedAddr, std::size_t MProtectLen)
: PageAlignedAddr(PageAlignedAddr), MProtectLen(MProtectLen),
explicit MProtectHelper(void *PageAlignedAddr,
std::size_t MProtectLen) XRAY_NEVER_INSTRUMENT
: PageAlignedAddr(PageAlignedAddr),
MProtectLen(MProtectLen),
MustCleanup(false) {}
int MakeWriteable() {
int MakeWriteable() XRAY_NEVER_INSTRUMENT {
auto R = mprotect(PageAlignedAddr, MProtectLen,
PROT_READ | PROT_WRITE | PROT_EXEC);
if (R != -1)
@ -65,7 +68,7 @@ public:
return R;
}
~MProtectHelper() {
~MProtectHelper() XRAY_NEVER_INSTRUMENT {
if (MustCleanup) {
mprotect(PageAlignedAddr, MProtectLen, PROT_READ | PROT_EXEC);
}
@ -77,7 +80,8 @@ public:
extern std::atomic<bool> XRayInitialized;
extern std::atomic<__xray::XRaySledMap> XRayInstrMap;
int __xray_set_handler(void (*entry)(int32_t, XRayEntryType)) {
int __xray_set_handler(void (*entry)(int32_t,
XRayEntryType)) XRAY_NEVER_INSTRUMENT {
if (XRayInitialized.load(std::memory_order_acquire)) {
__xray::XRayPatchedFunction.store(entry, std::memory_order_release);
return 1;
@ -85,7 +89,9 @@ int __xray_set_handler(void (*entry)(int32_t, XRayEntryType)) {
return 0;
}
int __xray_remove_handler() { return __xray_set_handler(nullptr); }
int __xray_remove_handler() XRAY_NEVER_INSTRUMENT {
return __xray_set_handler(nullptr);
}
std::atomic<bool> XRayPatching{false};
@ -97,22 +103,24 @@ template <class Function> class CleanupInvoker {
Function Fn;
public:
explicit CleanupInvoker(Function Fn) : Fn(Fn) {}
CleanupInvoker(const CleanupInvoker &) = default;
CleanupInvoker(CleanupInvoker &&) = default;
CleanupInvoker &operator=(const CleanupInvoker &) = delete;
CleanupInvoker &operator=(CleanupInvoker &&) = delete;
~CleanupInvoker() { Fn(); }
explicit CleanupInvoker(Function Fn) XRAY_NEVER_INSTRUMENT : Fn(Fn) {}
CleanupInvoker(const CleanupInvoker &) XRAY_NEVER_INSTRUMENT = default;
CleanupInvoker(CleanupInvoker &&) XRAY_NEVER_INSTRUMENT = default;
CleanupInvoker &
operator=(const CleanupInvoker &) XRAY_NEVER_INSTRUMENT = delete;
CleanupInvoker &operator=(CleanupInvoker &&) XRAY_NEVER_INSTRUMENT = delete;
~CleanupInvoker() XRAY_NEVER_INSTRUMENT { Fn(); }
};
template <class Function> CleanupInvoker<Function> ScopeCleanup(Function Fn) {
template <class Function>
CleanupInvoker<Function> ScopeCleanup(Function Fn) XRAY_NEVER_INSTRUMENT {
return CleanupInvoker<Function>{Fn};
}
// ControlPatching implements the common internals of the patching/unpatching
// implementation. |Enable| defines whether we're enabling or disabling the
// runtime XRay instrumentation.
XRayPatchingStatus ControlPatching(bool Enable) {
XRayPatchingStatus ControlPatching(bool Enable) XRAY_NEVER_INSTRUMENT {
if (!XRayInitialized.load(std::memory_order_acquire))
return XRayPatchingStatus::NOT_INITIALIZED; // Not initialized.
@ -188,6 +196,10 @@ XRayPatchingStatus ControlPatching(bool Enable) {
return XRayPatchingStatus::SUCCESS;
}
XRayPatchingStatus __xray_patch() { return ControlPatching(true); }
XRayPatchingStatus __xray_patch() XRAY_NEVER_INSTRUMENT {
return ControlPatching(true);
}
XRayPatchingStatus __xray_unpatch() { return ControlPatching(false); }
XRayPatchingStatus __xray_unpatch() XRAY_NEVER_INSTRUMENT {
return ControlPatching(false);
}

View File

@ -1,4 +1,5 @@
#include "sanitizer_common/sanitizer_common.h"
#include "xray_defs.h"
#include "xray_interface_internal.h"
#include <atomic>
#include <cstdint>
@ -16,7 +17,7 @@ static constexpr int64_t MinOffset{std::numeric_limits<int32_t>::min()};
static constexpr int64_t MaxOffset{std::numeric_limits<int32_t>::max()};
bool patchFunctionEntry(const bool Enable, const uint32_t FuncId,
const XRaySledEntry &Sled) {
const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
// Here we do the dance of replacing the following sled:
//
// xray_sled_n:
@ -65,7 +66,7 @@ bool patchFunctionEntry(const bool Enable, const uint32_t FuncId,
}
bool patchFunctionExit(const bool Enable, const uint32_t FuncId,
const XRaySledEntry &Sled) {
const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
// Here we do the dance of replacing the following sled:
//
// xray_sled_n:
@ -112,7 +113,7 @@ bool patchFunctionExit(const bool Enable, const uint32_t FuncId,
}
bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId,
const XRaySledEntry &Sled) {
const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
// Here we do the dance of replacing the tail call sled with a similar
// sequence as the entry sled, but calls the tail exit sled instead.
int64_t TrampolineOffset =