summaryrefslogtreecommitdiffstats
path: root/compiler-rt
diff options
context:
space:
mode:
Diffstat (limited to 'compiler-rt')
-rw-r--r--compiler-rt/lib/xray/xray_interface.cc51
-rw-r--r--compiler-rt/test/CMakeLists.txt3
-rw-r--r--compiler-rt/test/xray/CMakeLists.txt37
-rw-r--r--compiler-rt/test/xray/TestCases/Linux/patching-unpatching.cc47
-rw-r--r--compiler-rt/test/xray/lit.cfg34
-rw-r--r--compiler-rt/test/xray/lit.site.cfg.in13
6 files changed, 172 insertions, 13 deletions
diff --git a/compiler-rt/lib/xray/xray_interface.cc b/compiler-rt/lib/xray/xray_interface.cc
index ccbe7e2f2f7..5ef3fc7aac9 100644
--- a/compiler-rt/lib/xray/xray_interface.cc
+++ b/compiler-rt/lib/xray/xray_interface.cc
@@ -82,6 +82,8 @@ int __xray_set_handler(void (*entry)(int32_t, XRayEntryType)) {
return 0;
}
+int __xray_remove_handler() { return __xray_set_handler(nullptr); }
+
std::atomic<bool> XRayPatching{false};
using namespace __xray;
@@ -104,7 +106,10 @@ template <class Function> CleanupInvoker<Function> ScopeCleanup(Function Fn) {
return CleanupInvoker<Function>{Fn};
}
-XRayPatchingStatus __xray_patch() {
+// 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) {
if (!XRayInitialized.load(std::memory_order_acquire))
return XRayPatchingStatus::NOT_INITIALIZED; // Not initialized.
@@ -131,7 +136,9 @@ XRayPatchingStatus __xray_patch() {
int32_t FuncId = 1;
static constexpr uint8_t CallOpCode = 0xe8;
static constexpr uint16_t MovR10Seq = 0xba41;
+ static constexpr uint16_t Jmp9Seq = 0x09eb;
static constexpr uint8_t JmpOpCode = 0xe9;
+ static constexpr uint8_t RetOpCode = 0xc3;
uint64_t CurFun = 0;
for (std::size_t I = 0; I < InstrMap.Entries; I++) {
auto Sled = InstrMap.Sleds[I];
@@ -191,12 +198,19 @@ XRayPatchingStatus __xray_patch() {
TrampolineOffset);
continue;
}
- *reinterpret_cast<uint32_t *>(Sled.Address + 2) = FuncId;
- *reinterpret_cast<uint8_t *>(Sled.Address + 6) = CallOpCode;
- *reinterpret_cast<uint32_t *>(Sled.Address + 7) = TrampolineOffset;
- std::atomic_store_explicit(
- reinterpret_cast<std::atomic<uint16_t> *>(Sled.Address), MovR10Seq,
- std::memory_order_release);
+ if (Enable) {
+ *reinterpret_cast<uint32_t *>(Sled.Address + 2) = FuncId;
+ *reinterpret_cast<uint8_t *>(Sled.Address + 6) = CallOpCode;
+ *reinterpret_cast<uint32_t *>(Sled.Address + 7) = TrampolineOffset;
+ std::atomic_store_explicit(
+ reinterpret_cast<std::atomic<uint16_t> *>(Sled.Address), MovR10Seq,
+ std::memory_order_release);
+ } else {
+ std::atomic_store_explicit(
+ reinterpret_cast<std::atomic<uint16_t> *>(Sled.Address), Jmp9Seq,
+ std::memory_order_release);
+ // FIXME: Write out the nops still?
+ }
}
if (Sled.Kind == XRayEntryType::EXIT) {
@@ -231,15 +245,26 @@ XRayPatchingStatus __xray_patch() {
TrampolineOffset);
continue;
}
- *reinterpret_cast<uint32_t *>(Sled.Address + 2) = FuncId;
- *reinterpret_cast<uint8_t *>(Sled.Address + 6) = JmpOpCode;
- *reinterpret_cast<uint32_t *>(Sled.Address + 7) = TrampolineOffset;
- std::atomic_store_explicit(
- reinterpret_cast<std::atomic<uint16_t> *>(Sled.Address), MovR10Seq,
- std::memory_order_release);
+ if (Enable) {
+ *reinterpret_cast<uint32_t *>(Sled.Address + 2) = FuncId;
+ *reinterpret_cast<uint8_t *>(Sled.Address + 6) = JmpOpCode;
+ *reinterpret_cast<uint32_t *>(Sled.Address + 7) = TrampolineOffset;
+ std::atomic_store_explicit(
+ reinterpret_cast<std::atomic<uint16_t> *>(Sled.Address), MovR10Seq,
+ std::memory_order_release);
+ } else {
+ std::atomic_store_explicit(
+ reinterpret_cast<std::atomic<uint8_t> *>(Sled.Address), RetOpCode,
+ std::memory_order_release);
+ // FIXME: Write out the nops still?
+ }
}
}
XRayPatching.store(false, std::memory_order_release);
PatchingSuccess = true;
return XRayPatchingStatus::SUCCESS;
}
+
+XRayPatchingStatus __xray_patch() { return ControlPatching(true); }
+
+XRayPatchingStatus __xray_unpatch() { return ControlPatching(false); }
diff --git a/compiler-rt/test/CMakeLists.txt b/compiler-rt/test/CMakeLists.txt
index 87548d94d21..3316e002126 100644
--- a/compiler-rt/test/CMakeLists.txt
+++ b/compiler-rt/test/CMakeLists.txt
@@ -79,6 +79,9 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS)
if(COMPILER_RT_HAS_SCUDO)
add_subdirectory(scudo)
endif()
+ if(COMPILER_RT_HAS_XRAY)
+ add_subdirectory(xray)
+ endif()
endif()
if(COMPILER_RT_STANDALONE_BUILD)
diff --git a/compiler-rt/test/xray/CMakeLists.txt b/compiler-rt/test/xray/CMakeLists.txt
new file mode 100644
index 00000000000..d4142e075e9
--- /dev/null
+++ b/compiler-rt/test/xray/CMakeLists.txt
@@ -0,0 +1,37 @@
+set(XRAY_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+
+set(XRAY_TESTSUITES)
+
+set(XRAY_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
+if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND XRAY_TEST_DEPS xray)
+endif()
+
+set(XRAY_TEST_ARCH ${XRAY_SUPPORTED_ARCH})
+foreach(arch ${XRAY_TEST_ARCH})
+ set(XRAY_TEST_TARGET_ARCH ${arch})
+ string(TOLOWER "-${arch}-${OS_NAME}" XRAY_TEST_CONFIG_SUFFIX)
+
+ if(ANDROID OR ${arch} MATCHES "arm|aarch64")
+ # This is only true if we are cross-compiling.
+ # Build all tests with host compiler and use host tools.
+ set(XRAY_TEST_TARGET_CC ${COMPILER_RT_TEST_COMPILER})
+ set(XRAY_TEST_TARGET_CFLAGS ${COMPILER_RT_TEST_COMPILER_CFLAGS})
+ else()
+ get_target_flags_for_arch(${arch} XRAY_TEST_TARGET_CFLAGS)
+ string(REPLACE ";" " " XRAY_TEST_TARGET_CFLAGS "${XRAY_TEST_TARGET_CFLAGS}")
+ endif()
+
+ string(TOUPPER ${arch} ARCH_UPPER_CASE)
+ set(CONFIG_NAME ${ARCH_UPPER_CASE}${OS_NAME}Config)
+
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg)
+ list(APPEND XRAY_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME})
+endforeach()
+
+add_lit_testsuite(check-xray "Running the XRay tests"
+ ${XRAY_TESTSUITES}
+ DEPENDS ${XRAY_TEST_DEPS})
+set_target_properties(check-xray PROPERTIES FOLDER "Compiler-RT Misc")
diff --git a/compiler-rt/test/xray/TestCases/Linux/patching-unpatching.cc b/compiler-rt/test/xray/TestCases/Linux/patching-unpatching.cc
new file mode 100644
index 00000000000..05478a48805
--- /dev/null
+++ b/compiler-rt/test/xray/TestCases/Linux/patching-unpatching.cc
@@ -0,0 +1,47 @@
+// Check that we can patch and un-patch on demand, and that logging gets invoked
+// appropriately.
+//
+// RUN: %clangxx_xray -fxray-instrument -std=c++11 %s -o %t
+// RUN: XRAY_OPTIONS="patch_premain=false" %run %t 2>&1 | FileCheck %s
+
+#include "xray/xray_interface.h"
+
+#include <cstdio>
+
+bool called = false;
+
+void test_handler(int32_t fid, XRayEntryType type) {
+ printf("called: %d, type=%d\n", fid, static_cast<int32_t>(type));
+ called = true;
+}
+
+[[clang::xray_always_instrument]] void always_instrument() {
+ printf("always instrumented called\n");
+}
+
+int main() {
+ __xray_set_handler(test_handler);
+ always_instrument();
+ // CHECK: always instrumented called
+ auto status = __xray_patch();
+ printf("patching status: %d\n", static_cast<int32_t>(status));
+ // CHECK-NEXT: patching status: 1
+ always_instrument();
+ // CHECK-NEXT: called: {{.*}}, type=0
+ // CHECK-NEXT: always instrumented called
+ // CHECK-NEXT: called: {{.*}}, type=1
+ status = __xray_unpatch();
+ printf("patching status: %d\n", static_cast<int32_t>(status));
+ // CHECK-NEXT: patching status: 1
+ always_instrument();
+ // CHECK-NEXT: always instrumented called
+ status = __xray_patch();
+ printf("patching status: %d\n", static_cast<int32_t>(status));
+ // CHECK-NEXT: patching status: 1
+ __xray_remove_handler();
+ always_instrument();
+ // CHECK-NEXT: always instrumented called
+ status = __xray_unpatch();
+ printf("patching status: %d\n", static_cast<int32_t>(status));
+ // CHECK-NEXT: patching status: 1
+}
diff --git a/compiler-rt/test/xray/lit.cfg b/compiler-rt/test/xray/lit.cfg
new file mode 100644
index 00000000000..04e21f1c4cb
--- /dev/null
+++ b/compiler-rt/test/xray/lit.cfg
@@ -0,0 +1,34 @@
+# -*- Python -*-
+
+import os
+
+# Setup config name.
+config.name = 'XRay' + config.name_suffix
+
+# Setup source root.
+config.test_source_root = os.path.dirname(__file__)
+
+# Setup default compiler flags use with -fxray-instrument option.
+clang_xray_cflags = (['-fxray-instrument', config.target_cflags])
+clang_xray_cxxflags = config.cxx_mode_flags + clang_xray_cflags
+
+
+def build_invocation(compile_flags):
+ return ' ' + ' '.join([config.clang] + compile_flags) + ' '
+
+# Setup substitutions.
+config.substitutions.append(
+ ('%clang ', build_invocation([config.target_cflags])))
+config.substitutions.append(
+ ('%clangxx ',
+ build_invocation(config.cxx_mode_flags + [config.target_cflags])))
+config.substitutions.append(
+ ('%clang_xray ', build_invocation(clang_xray_cflags)))
+config.substitutions.append(
+ ('%clangxx_xray', build_invocation(clang_xray_cxxflags)))
+
+# Default test suffixes.
+config.suffixes = ['.c', '.cc', '.cpp']
+
+if config.host_os not in ['Linux'] or config.host_arch.find('64') == -1:
+ config.unsupported = True
diff --git a/compiler-rt/test/xray/lit.site.cfg.in b/compiler-rt/test/xray/lit.site.cfg.in
new file mode 100644
index 00000000000..ee0ffcad4d9
--- /dev/null
+++ b/compiler-rt/test/xray/lit.site.cfg.in
@@ -0,0 +1,13 @@
+@LIT_SITE_CFG_IN_HEADER@
+
+# Tool-specific config options.
+config.name_suffix = "@XRAY_TEST_CONFIG_SUFFIX@"
+config.xray_lit_source_dir = "@XRAY_LIT_SOURCE_DIR@"
+config.target_cflags = "@XRAY_TEST_TARGET_CFLAGS@"
+config.target_arch = "@XRAY_TEST_TARGET_ARCH@"
+
+# Load common config for all compiler-rt lit tests
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
+
+# Load tool-specific config that would do the real work.
+lit_config.load_config(config, "@XRAY_LIT_SOURCE_DIR@/lit.cfg")
OpenPOWER on IntegriCloud