Index: include/xray/xray_interface.h =================================================================== --- include/xray/xray_interface.h +++ include/xray/xray_interface.h @@ -41,26 +41,18 @@ enum XRayPatchingStatus { NOT_INITIALIZED = 0, - NOTIFIED = 1, + SUCCESS = 1, ONGOING = 2, - FAILED = 3 + FAILED = 3, }; -// This tells XRay to patch the instrumentation points. This is an asynchronous -// process, and returns the following status in specific cases: -// -// - 0 : XRay is not initialized. -// - 1 : We've done the notification. -// - 2 : Patching / un-patching is on-going. +// This tells XRay to patch the instrumentation points. See XRayPatchingStatus +// for possible result values. extern XRayPatchingStatus __xray_patch(); -// Reverses the effect of __xray_patch(). This is an asynchronous process, and -// returns the following status in specific cases. -// -// - 0 : XRay is not initialized. -// - 1 : We've done the notification. -// - 2 : Patching / un-patching is on-going. -extern int __xray_unpatch(); +// Reverses the effect of __xray_patch(). See XRayPatchingStatus for possible +// result values. +extern XRayPatchingStatus __xray_unpatch(); } #endif Index: lib/xray/xray_init.cc =================================================================== --- lib/xray/xray_init.cc +++ lib/xray/xray_init.cc @@ -22,18 +22,20 @@ #include "xray_interface_internal.h" extern "C" { -extern void __xray_init(); +void __xray_init(); extern const XRaySledEntry __start_xray_instr_map[] __attribute__((weak)); extern const XRaySledEntry __stop_xray_instr_map[] __attribute__((weak)); } using namespace __xray; -// We initialize some global variables that pertain to specific sections of XRay -// data structures in the binary. We do this for the current process using -// /proc/curproc/map and make sure that we're able to get it. We signal failure -// via a global atomic boolean to indicate whether we've initialized properly. +// When set to 'true' this means the XRay runtime has been initialised. We use +// the weak symbols defined above (__start_xray_inst_map and +// __stop_xray_instr_map) to initialise the instrumentation map that XRay uses +// for runtime patching/unpatching of instrumentation points. // +// FIXME: Support DSO instrumentation maps too. The current solution only works +// for statically linked executables. std::atomic XRayInitialized{false}; // This should always be updated before XRayInitialized is updated. Index: lib/xray/xray_interface.cc =================================================================== --- lib/xray/xray_interface.cc +++ lib/xray/xray_interface.cc @@ -14,6 +14,7 @@ //===----------------------------------------------------------------------===// #include "xray_interface_internal.h" + #include #include #include @@ -21,6 +22,8 @@ #include #include +#include "sanitizer_common/sanitizer_common.h" + namespace __xray { // This is the function to call when we encounter the entry or exit sleds. @@ -83,8 +86,25 @@ using namespace __xray; +// FIXME: Figure out whether we can move this class to sanitizer_common instead +// as a generic "scope guard". +template 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(); } +}; + +template CleanupInvoker ScopeCleanup(Function Fn) { + return CleanupInvoker{Fn}; +} + XRayPatchingStatus __xray_patch() { - // FIXME: Make this happen asynchronously. For now just do this sequentially. if (!XRayInitialized.load(std::memory_order_acquire)) return XRayPatchingStatus::NOT_INITIALIZED; // Not initialized. @@ -95,6 +115,13 @@ return XRayPatchingStatus::ONGOING; // Already patching. } + bool PatchingSuccess = false; + auto XRayPatchingStatusResetter = ScopeCleanup([&PatchingSuccess] { + if (!PatchingSuccess) { + XRayPatching.store(false, std::memory_order_release); + } + }); + // Step 1: Compute the function id, as a unique identifier per function in the // instrumentation map. XRaySledMap InstrMap = XRayInstrMap.load(std::memory_order_acquire); @@ -131,6 +158,7 @@ static constexpr int64_t MinOffset{std::numeric_limits::min()}; static constexpr int64_t MaxOffset{std::numeric_limits::max()}; if (Sled.Kind == XRayEntryType::ENTRY) { + // FIXME: Implement this in a more extensible manner, per-platform. // Here we do the dance of replacing the following sled: // // xray_sled_n: @@ -157,7 +185,10 @@ reinterpret_cast(__xray_FunctionEntry) - (static_cast(Sled.Address) + 11); if (TrampolineOffset < MinOffset || TrampolineOffset > MaxOffset) { - // FIXME: Print out an error here. + Report("XRay Entry trampoline (%p) too far from sled (%p); distance = " + "%ld\n", + __xray_FunctionEntry, reinterpret_cast(Sled.Address), + TrampolineOffset); continue; } *reinterpret_cast(Sled.Address + 2) = FuncId; @@ -169,6 +200,7 @@ } if (Sled.Kind == XRayEntryType::EXIT) { + // FIXME: Implement this in a more extensible manner, per-platform. // Here we do the dance of replacing the following sled: // // xray_sled_n: @@ -193,7 +225,10 @@ reinterpret_cast(__xray_FunctionExit) - (static_cast(Sled.Address) + 11); if (TrampolineOffset < MinOffset || TrampolineOffset > MaxOffset) { - // FIXME: Print out an error here. + Report("XRay Exit trampoline (%p) too far from sled (%p); distance = " + "%ld\n", + __xray_FunctionExit, reinterpret_cast(Sled.Address), + TrampolineOffset); continue; } *reinterpret_cast(Sled.Address + 2) = FuncId; @@ -205,5 +240,6 @@ } } XRayPatching.store(false, std::memory_order_release); - return XRayPatchingStatus::NOTIFIED; + PatchingSuccess = true; + return XRayPatchingStatus::SUCCESS; }