[XRay][compiler-rt][Darwin] Minimal XRay build support in Darwin

This change is the first in a series of changes to get the XRay runtime
building on macOS. This first allows us to build the minimal parts of
XRay to get us started on supporting macOS development. These include:

  - CMake changes to allow targeting x86_64 initially.
  - Allowing for building the initialisation routines without
    `.preinit_array` support.
  - Use __sanitizer::SleepForMillis() to work around the lack of
    clock_nanosleep on macOS.
  - Deprecate the xray_fdr_log_grace_period_us flag, and introduce
    the xray_fdr_log_grace_period_ms flag instead, to use
    milliseconds across platforms.

Reviewers: kubamracek

Subscribers: llvm-commits, krytarowski, nglevin, mgorny

Differential Review: https://reviews.llvm.org/D39114

llvm-svn: 319165
This commit is contained in:
Dean Michael Berris 2017-11-28 11:49:22 +00:00
parent c34f789e38
commit 542485f29c
7 changed files with 109 additions and 70 deletions

View File

@ -211,7 +211,11 @@ set(ALL_SAFESTACK_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM64} ${MIPS32} ${MIPS64})
set(ALL_CFI_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${MIPS64})
set(ALL_ESAN_SUPPORTED_ARCH ${X86_64} ${MIPS64})
set(ALL_SCUDO_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64})
if(APPLE)
set(ALL_XRAY_SUPPORTED_ARCH ${X86_64})
else()
set(ALL_XRAY_SUPPORTED_ARCH ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64} powerpc64le)
endif()
if(APPLE)
include(CompilerRTDarwinUtils)
@ -256,6 +260,7 @@ if(APPLE)
set(SANITIZER_COMMON_SUPPORTED_OS osx)
set(PROFILE_SUPPORTED_OS osx)
set(TSAN_SUPPORTED_OS osx)
set(XRAY_SUPPORTED_OS osx)
if(NOT SANITIZER_MIN_OSX_VERSION)
string(REGEX MATCH "-mmacosx-version-min=([.0-9]+)"
MACOSX_VERSION_MIN_FLAG "${CMAKE_CXX_FLAGS}")
@ -412,12 +417,12 @@ if(APPLE)
list_intersect(SCUDO_SUPPORTED_ARCH
ALL_SCUDO_SUPPORTED_ARCH
SANITIZER_COMMON_SUPPORTED_ARCH)
list_intersect(XRAY_SUPPORTED_ARCH
ALL_XRAY_SUPPORTED_ARCH
SANITIZER_COMMON_SUPPORTED_ARCH)
list_intersect(FUZZER_SUPPORTED_ARCH
ALL_FUZZER_SUPPORTED_ARCH
ALL_SANITIZER_COMMON_SUPPORTED_ARCH)
list_intersect(XRAY_SUPPORTED_ARCH
ALL_XRAY_SUPPORTED_ARCH
SANITIZER_COMMON_SUPPORTED_ARCH)
else()
# Architectures supported by compiler-rt libraries.
@ -580,7 +585,7 @@ else()
endif()
if (COMPILER_RT_HAS_SANITIZER_COMMON AND XRAY_SUPPORTED_ARCH AND
OS_NAME MATCHES "Linux")
OS_NAME MATCHES "Darwin|Linux")
set(COMPILER_RT_HAS_XRAY TRUE)
else()
set(COMPILER_RT_HAS_XRAY FALSE)

View File

@ -65,19 +65,53 @@ append_list_if(
append_list_if(
COMPILER_RT_BUILD_XRAY_NO_PREINIT XRAY_NO_PREINIT XRAY_COMMON_DEFINITIONS)
add_compiler_rt_object_libraries(RTXray
ARCHS ${XRAY_SUPPORTED_ARCH}
SOURCES ${XRAY_SOURCES} CFLAGS ${XRAY_CFLAGS}
DEFS ${XRAY_COMMON_DEFINITIONS})
add_compiler_rt_component(xray)
set(XRAY_COMMON_RUNTIME_OBJECT_LIBS
RTXray
RTSanitizerCommon
RTSanitizerCommonLibc)
if (APPLE)
set(XRAY_LINK_LIBS ${SANITIZER_COMMON_LINK_LIBS})
set(XRAY_ASM_SOURCES xray_trampoline_x86_64.S)
if (${CMAKE_GENERATOR} STREQUAL "Xcode")
enable_language(ASM)
else()
set_source_files_properties(${XRAY_ASM_SOURCES} PROPERTIES LANGUAGE C)
endif()
add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS)
add_weak_symbols("xray" WEAK_SYMBOL_LINK_FLAGS)
add_compiler_rt_object_libraries(RTXray
OS ${XRAY_SUPPORTED_OS}
ARCHS ${XRAY_SUPPORTED_ARCH}
SOURCES ${x86_64_SOURCES}
CFLAGS ${XRAY_CFLAGS}
DEFS ${XRAY_COMMON_DEFINITIONS})
# We only support running on osx for now.
add_compiler_rt_runtime(clang_rt.xray
STATIC
OS ${XRAY_SUPPORTED_OS}
ARCHS ${XRAY_SUPPORTED_ARCH}
OBJECT_LIBS RTXray
RTSanitizerCommon
RTSanitizerCommonLibc
CFLAGS ${XRAY_CFLAGS}
DEFS ${XRAY_COMMON_DEFINITIONS}
LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS}
LINK_LIBS ${XRAY_LINK_LIBS}
PARENT_TARGET xray)
else()
foreach(arch ${XRAY_SUPPORTED_ARCH})
if(CAN_TARGET_${arch})
add_compiler_rt_object_libraries(RTXray
ARCHS ${XRAY_SUPPORTED_ARCH}
SOURCES ${XRAY_SOURCES} CFLAGS ${XRAY_CFLAGS}
DEFS ${XRAY_COMMON_DEFINITIONS})
add_compiler_rt_runtime(clang_rt.xray
STATIC
ARCHS ${arch}
@ -88,6 +122,7 @@ foreach(arch ${XRAY_SUPPORTED_ARCH})
PARENT_TARGET xray)
endif()
endforeach()
endif()
if(COMPILER_RT_INCLUDE_TESTS)
add_subdirectory(tests)

View File

@ -0,0 +1,4 @@
___start_xray_fn_idx
___start_xray_instr_map
___stop_xray_fn_idx
___stop_xray_instr_map

View File

@ -70,15 +70,9 @@ XRayLogFlushStatus fdrLoggingFlush() XRAY_NEVER_INSTRUMENT {
return XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING;
}
// We wait a number of microseconds to allow threads to see that we've
// We wait a number of milliseconds to allow threads to see that we've
// finalised before attempting to flush the log.
struct timespec TS;
TS.tv_sec = flags()->xray_fdr_log_grace_period_us / 1000000;
TS.tv_nsec = (flags()->xray_fdr_log_grace_period_us % 1000000) * 1000;
struct timespec Rem;
while (clock_nanosleep(CLOCK_REALTIME, 0, &TS, &Rem) &&
(Rem.tv_sec != 0 || Rem.tv_nsec != 0))
TS = Rem;
__sanitizer::SleepForMillis(flags()->xray_fdr_log_grace_period_ms);
// We write out the file in the following format:
//
@ -374,9 +368,7 @@ static auto UNUSED Unused = [] {
using namespace __xray;
if (flags()->xray_fdr_log) {
XRayLogImpl Impl{
fdrLoggingInit,
fdrLoggingFinalize,
fdrLoggingHandleArg0,
fdrLoggingInit, fdrLoggingFinalize, fdrLoggingHandleArg0,
fdrLoggingFlush,
};
__xray_set_log_impl(Impl);

View File

@ -37,7 +37,9 @@ XRAY_FLAG(bool, xray_fdr_log, false,
XRAY_FLAG(int, xray_fdr_log_func_duration_threshold_us, 5,
"FDR logging will try to skip functions that execute for fewer "
"microseconds than this threshold.")
XRAY_FLAG(int, xray_fdr_log_grace_period_us, 100000,
XRAY_FLAG(int, xray_fdr_log_grace_period_us, 0,
"DEPRECATED: use xray_fdr_log_grace_period_ms instead.")
XRAY_FLAG(int, xray_fdr_log_grace_period_ms, 100,
"FDR logging will wait this much time in microseconds before "
"actually flushing the log; this gives a chance for threads to "
"notice that the log has been finalized and clean up.")

View File

@ -88,7 +88,8 @@ void __xray_init() XRAY_NEVER_INSTRUMENT {
#endif
}
#ifndef XRAY_NO_PREINIT
// Only add the preinit array initialization if the sanitizers can.
#if !defined(XRAY_NO_PREINIT) && SANITIZER_CAN_USE_PREINIT_ARRAY
__attribute__((section(".preinit_array"),
used)) void (*__local_xray_preinit)(void) = __xray_init;
#endif

View File

@ -14,10 +14,13 @@
//===----------------------------------------------------------------------===//
#include "../builtins/assembly.h"
#include "../sanitizer_common/sanitizer_asm.h"
.macro SAVE_REGISTERS
subq $192, %rsp
.cfi_def_cfa_offset 200
CFI_DEF_CFA_OFFSET(200)
// At this point, the stack pointer should be aligned to an 8-byte boundary,
// because any call instructions that come after this will add another 8
// bytes and therefore align it to 16-bytes.
@ -57,7 +60,7 @@
movq 8(%rsp), %r8
movq 0(%rsp), %r9
addq $192, %rsp
.cfi_def_cfa_offset 8
CFI_DEF_CFA_OFFSET(8)
.endm
.macro ALIGNED_CALL_RAX
@ -75,21 +78,25 @@
.endm
.text
#if !defined(__APPLE__)
.section .text
#else
.section __TEXT,__text
#endif
.file "xray_trampoline_x86.S"
//===----------------------------------------------------------------------===//
.globl __xray_FunctionEntry
.globl ASM_TSAN_SYMBOL(__xray_FunctionEntry)
.align 16, 0x90
.type __xray_FunctionEntry,@function
__xray_FunctionEntry:
.cfi_startproc
ASM_TYPE_FUNCTION(__xray_FunctionEntry)
ASM_TSAN_SYMBOL(__xray_FunctionEntry):
CFI_STARTPROC
SAVE_REGISTERS
// This load has to be atomic, it's concurrent with __xray_patch().
// On x86/amd64, a simple (type-aligned) MOV instruction is enough.
movq _ZN6__xray19XRayPatchedFunctionE(%rip), %rax
movq ASM_TSAN_SYMBOL(_ZN6__xray19XRayPatchedFunctionE)(%rip), %rax
testq %rax, %rax
je .Ltmp0
@ -101,28 +108,27 @@ __xray_FunctionEntry:
.Ltmp0:
RESTORE_REGISTERS
retq
.Ltmp1:
.size __xray_FunctionEntry, .Ltmp1-__xray_FunctionEntry
.cfi_endproc
ASM_SIZE(__xray_FunctionEntry)
CFI_ENDPROC
//===----------------------------------------------------------------------===//
.globl __xray_FunctionExit
.globl ASM_TSAN_SYMBOL(__xray_FunctionExit)
.align 16, 0x90
.type __xray_FunctionExit,@function
__xray_FunctionExit:
.cfi_startproc
ASM_TYPE_FUNCTION(__xray_FunctionExit)
ASM_TSAN_SYMBOL(__xray_FunctionExit):
CFI_STARTPROC
// Save the important registers first. Since we're assuming that this
// function is only jumped into, we only preserve the registers for
// returning.
subq $56, %rsp
.cfi_def_cfa_offset 64
CFI_DEF_CFA_OFFSET(64)
movq %rbp, 48(%rsp)
movupd %xmm0, 32(%rsp)
movupd %xmm1, 16(%rsp)
movq %rax, 8(%rsp)
movq %rdx, 0(%rsp)
movq _ZN6__xray19XRayPatchedFunctionE(%rip), %rax
movq ASM_TSAN_SYMBOL(_ZN6__xray19XRayPatchedFunctionE)(%rip), %rax
testq %rax,%rax
je .Ltmp2
@ -138,22 +144,21 @@ __xray_FunctionExit:
movq 8(%rsp), %rax
movq 0(%rsp), %rdx
addq $56, %rsp
.cfi_def_cfa_offset 8
CFI_DEF_CFA_OFFSET(8)
retq
.Ltmp3:
.size __xray_FunctionExit, .Ltmp3-__xray_FunctionExit
.cfi_endproc
ASM_SIZE(__xray_FunctionExit)
CFI_ENDPROC
//===----------------------------------------------------------------------===//
.global __xray_FunctionTailExit
.globl ASM_TSAN_SYMBOL(__xray_FunctionTailExit)
.align 16, 0x90
.type __xray_FunctionTailExit,@function
__xray_FunctionTailExit:
.cfi_startproc
ASM_TYPE_FUNCTION(__xray_FunctionTailExit)
ASM_TSAN_SYMBOL(__xray_FunctionTailExit):
CFI_STARTPROC
SAVE_REGISTERS
movq _ZN6__xray19XRayPatchedFunctionE(%rip), %rax
movq ASM_TSAN_SYMBOL(_ZN6__xray19XRayPatchedFunctionE)(%rip), %rax
testq %rax,%rax
je .Ltmp4
@ -165,26 +170,25 @@ __xray_FunctionTailExit:
.Ltmp4:
RESTORE_REGISTERS
retq
.Ltmp5:
.size __xray_FunctionTailExit, .Ltmp5-__xray_FunctionTailExit
.cfi_endproc
ASM_SIZE(__xray_FunctionTailExit)
CFI_ENDPROC
//===----------------------------------------------------------------------===//
.globl __xray_ArgLoggerEntry
.globl ASM_TSAN_SYMBOL(__xray_ArgLoggerEntry)
.align 16, 0x90
.type __xray_ArgLoggerEntry,@function
__xray_ArgLoggerEntry:
.cfi_startproc
ASM_TYPE_FUNCTION(__xray_ArgLoggerEntry)
ASM_TSAN_SYMBOL(__xray_ArgLoggerEntry):
CFI_STARTPROC
SAVE_REGISTERS
// Again, these function pointer loads must be atomic; MOV is fine.
movq _ZN6__xray13XRayArgLoggerE(%rip), %rax
movq ASM_TSAN_SYMBOL(_ZN6__xray13XRayArgLoggerE)(%rip), %rax
testq %rax, %rax
jne .Larg1entryLog
// If [arg1 logging handler] not set, defer to no-arg logging.
movq _ZN6__xray19XRayPatchedFunctionE(%rip), %rax
movq ASM_TSAN_SYMBOL(_ZN6__xray19XRayPatchedFunctionE)(%rip), %rax
testq %rax, %rax
je .Larg1entryFail
@ -203,24 +207,22 @@ __xray_ArgLoggerEntry:
.Larg1entryFail:
RESTORE_REGISTERS
retq
.Larg1entryEnd:
.size __xray_ArgLoggerEntry, .Larg1entryEnd-__xray_ArgLoggerEntry
.cfi_endproc
ASM_SIZE(__xray_ArgLoggerEntry)
CFI_ENDPROC
//===----------------------------------------------------------------------===//
.global __xray_CustomEvent
.global ASM_TSAN_SYMBOL(__xray_CustomEvent)
.align 16, 0x90
.type __xray_CustomEvent,@function
__xray_CustomEvent:
.cfi_startproc
ASM_TYPE_FUNCTION(__xray_CustomEvent)
ASM_TSAN_SYMBOL(__xray_CustomEvent):
CFI_STARTPROC
SAVE_REGISTERS
// We take two arguments to this trampoline, which should be in rdi and rsi
// already. We also make sure that we stash %rax because we use that register
// to call the logging handler.
movq _ZN6__xray22XRayPatchedCustomEventE(%rip), %rax
movq ASM_TSAN_SYMBOL(_ZN6__xray22XRayPatchedCustomEventE)(%rip), %rax
testq %rax,%rax
je .LcustomEventCleanup
@ -229,9 +231,7 @@ __xray_CustomEvent:
.LcustomEventCleanup:
RESTORE_REGISTERS
retq
.Ltmp8:
.size __xray_CustomEvent, .Ltmp8-__xray_CustomEvent
.cfi_endproc
ASM_SIZE(__xray_CustomEvent)
CFI_ENDPROC
NO_EXEC_STACK_DIRECTIVE