Home | History | Annotate | Line # | Download | only in xray
      1 //===-- xray_log_interface.cc ---------------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file is a part of XRay, a function call tracing system.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 #include "xray/xray_log_interface.h"
     14 
     15 #include "sanitizer_common/sanitizer_allocator_internal.h"
     16 #include "sanitizer_common/sanitizer_atomic.h"
     17 #include "sanitizer_common/sanitizer_mutex.h"
     18 #include "xray/xray_interface.h"
     19 #include "xray_defs.h"
     20 
     21 namespace __xray {
     22 static SpinMutex XRayImplMutex;
     23 static XRayLogImpl CurrentXRayImpl{nullptr, nullptr, nullptr, nullptr};
     24 static XRayLogImpl *GlobalXRayImpl = nullptr;
     25 
     26 // This is the default implementation of a buffer iterator, which always yields
     27 // a null buffer.
     28 XRayBuffer NullBufferIterator(XRayBuffer) XRAY_NEVER_INSTRUMENT {
     29   return {nullptr, 0};
     30 }
     31 
     32 // This is the global function responsible for iterating through given buffers.
     33 atomic_uintptr_t XRayBufferIterator{
     34     reinterpret_cast<uintptr_t>(&NullBufferIterator)};
     35 
     36 // We use a linked list of Mode to XRayLogImpl mappings. This is a linked list
     37 // when it should be a map because we're avoiding having to depend on C++
     38 // standard library data structures at this level of the implementation.
     39 struct ModeImpl {
     40   ModeImpl *Next;
     41   const char *Mode;
     42   XRayLogImpl Impl;
     43 };
     44 
     45 static ModeImpl SentinelModeImpl{
     46     nullptr, nullptr, {nullptr, nullptr, nullptr, nullptr}};
     47 static ModeImpl *ModeImpls = &SentinelModeImpl;
     48 static const ModeImpl *CurrentMode = nullptr;
     49 
     50 } // namespace __xray
     51 
     52 using namespace __xray;
     53 
     54 void __xray_log_set_buffer_iterator(XRayBuffer (*Iterator)(XRayBuffer))
     55     XRAY_NEVER_INSTRUMENT {
     56   atomic_store(&__xray::XRayBufferIterator,
     57                reinterpret_cast<uintptr_t>(Iterator), memory_order_release);
     58 }
     59 
     60 void __xray_log_remove_buffer_iterator() XRAY_NEVER_INSTRUMENT {
     61   __xray_log_set_buffer_iterator(&NullBufferIterator);
     62 }
     63 
     64 XRayLogRegisterStatus
     65 __xray_log_register_mode(const char *Mode,
     66                          XRayLogImpl Impl) XRAY_NEVER_INSTRUMENT {
     67   if (Impl.flush_log == nullptr || Impl.handle_arg0 == nullptr ||
     68       Impl.log_finalize == nullptr || Impl.log_init == nullptr)
     69     return XRayLogRegisterStatus::XRAY_INCOMPLETE_IMPL;
     70 
     71   SpinMutexLock Guard(&XRayImplMutex);
     72   // First, look for whether the mode already has a registered implementation.
     73   for (ModeImpl *it = ModeImpls; it != &SentinelModeImpl; it = it->Next) {
     74     if (!internal_strcmp(Mode, it->Mode))
     75       return XRayLogRegisterStatus::XRAY_DUPLICATE_MODE;
     76   }
     77   auto *NewModeImpl = static_cast<ModeImpl *>(InternalAlloc(sizeof(ModeImpl)));
     78   NewModeImpl->Next = ModeImpls;
     79   NewModeImpl->Mode = internal_strdup(Mode);
     80   NewModeImpl->Impl = Impl;
     81   ModeImpls = NewModeImpl;
     82   return XRayLogRegisterStatus::XRAY_REGISTRATION_OK;
     83 }
     84 
     85 XRayLogRegisterStatus
     86 __xray_log_select_mode(const char *Mode) XRAY_NEVER_INSTRUMENT {
     87   SpinMutexLock Guard(&XRayImplMutex);
     88   for (ModeImpl *it = ModeImpls; it != &SentinelModeImpl; it = it->Next) {
     89     if (!internal_strcmp(Mode, it->Mode)) {
     90       CurrentMode = it;
     91       CurrentXRayImpl = it->Impl;
     92       GlobalXRayImpl = &CurrentXRayImpl;
     93       __xray_set_handler(it->Impl.handle_arg0);
     94       return XRayLogRegisterStatus::XRAY_REGISTRATION_OK;
     95     }
     96   }
     97   return XRayLogRegisterStatus::XRAY_MODE_NOT_FOUND;
     98 }
     99 
    100 const char *__xray_log_get_current_mode() XRAY_NEVER_INSTRUMENT {
    101   SpinMutexLock Guard(&XRayImplMutex);
    102   if (CurrentMode != nullptr)
    103     return CurrentMode->Mode;
    104   return nullptr;
    105 }
    106 
    107 void __xray_set_log_impl(XRayLogImpl Impl) XRAY_NEVER_INSTRUMENT {
    108   if (Impl.log_init == nullptr || Impl.log_finalize == nullptr ||
    109       Impl.handle_arg0 == nullptr || Impl.flush_log == nullptr) {
    110     SpinMutexLock Guard(&XRayImplMutex);
    111     GlobalXRayImpl = nullptr;
    112     CurrentMode = nullptr;
    113     __xray_remove_handler();
    114     __xray_remove_handler_arg1();
    115     return;
    116   }
    117 
    118   SpinMutexLock Guard(&XRayImplMutex);
    119   CurrentXRayImpl = Impl;
    120   GlobalXRayImpl = &CurrentXRayImpl;
    121   __xray_set_handler(Impl.handle_arg0);
    122 }
    123 
    124 void __xray_remove_log_impl() XRAY_NEVER_INSTRUMENT {
    125   SpinMutexLock Guard(&XRayImplMutex);
    126   GlobalXRayImpl = nullptr;
    127   __xray_remove_handler();
    128   __xray_remove_handler_arg1();
    129 }
    130 
    131 XRayLogInitStatus __xray_log_init(size_t BufferSize, size_t MaxBuffers,
    132                                   void *Args,
    133                                   size_t ArgsSize) XRAY_NEVER_INSTRUMENT {
    134   SpinMutexLock Guard(&XRayImplMutex);
    135   if (!GlobalXRayImpl)
    136     return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED;
    137   return GlobalXRayImpl->log_init(BufferSize, MaxBuffers, Args, ArgsSize);
    138 }
    139 
    140 XRayLogInitStatus __xray_log_init_mode(const char *Mode, const char *Config)
    141     XRAY_NEVER_INSTRUMENT {
    142   SpinMutexLock Guard(&XRayImplMutex);
    143   if (!GlobalXRayImpl)
    144     return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED;
    145 
    146   if (Config == nullptr)
    147     return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED;
    148 
    149   // Check first whether the current mode is the same as what we expect.
    150   if (CurrentMode == nullptr || internal_strcmp(CurrentMode->Mode, Mode) != 0)
    151     return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED;
    152 
    153   // Here we do some work to coerce the pointer we're provided, so that
    154   // the implementations that still take void* pointers can handle the
    155   // data provided in the Config argument.
    156   return GlobalXRayImpl->log_init(
    157       0, 0, const_cast<void *>(static_cast<const void *>(Config)), 0);
    158 }
    159 
    160 XRayLogInitStatus
    161 __xray_log_init_mode_bin(const char *Mode, const char *Config,
    162                          size_t ConfigSize) XRAY_NEVER_INSTRUMENT {
    163   SpinMutexLock Guard(&XRayImplMutex);
    164   if (!GlobalXRayImpl)
    165     return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED;
    166 
    167   if (Config == nullptr)
    168     return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED;
    169 
    170   // Check first whether the current mode is the same as what we expect.
    171   if (CurrentMode == nullptr || internal_strcmp(CurrentMode->Mode, Mode) != 0)
    172     return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED;
    173 
    174   // Here we do some work to coerce the pointer we're provided, so that
    175   // the implementations that still take void* pointers can handle the
    176   // data provided in the Config argument.
    177   return GlobalXRayImpl->log_init(
    178       0, 0, const_cast<void *>(static_cast<const void *>(Config)), ConfigSize);
    179 }
    180 
    181 XRayLogInitStatus __xray_log_finalize() XRAY_NEVER_INSTRUMENT {
    182   SpinMutexLock Guard(&XRayImplMutex);
    183   if (!GlobalXRayImpl)
    184     return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED;
    185   return GlobalXRayImpl->log_finalize();
    186 }
    187 
    188 XRayLogFlushStatus __xray_log_flushLog() XRAY_NEVER_INSTRUMENT {
    189   SpinMutexLock Guard(&XRayImplMutex);
    190   if (!GlobalXRayImpl)
    191     return XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING;
    192   return GlobalXRayImpl->flush_log();
    193 }
    194 
    195 XRayLogFlushStatus __xray_log_process_buffers(
    196     void (*Processor)(const char *, XRayBuffer)) XRAY_NEVER_INSTRUMENT {
    197   // We want to make sure that there will be no changes to the global state for
    198   // the log by synchronising on the XRayBufferIteratorMutex.
    199   if (!GlobalXRayImpl)
    200     return XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING;
    201   auto Iterator = reinterpret_cast<XRayBuffer (*)(XRayBuffer)>(
    202       atomic_load(&XRayBufferIterator, memory_order_acquire));
    203   auto Buffer = (*Iterator)(XRayBuffer{nullptr, 0});
    204   auto Mode = CurrentMode ? CurrentMode->Mode : nullptr;
    205   while (Buffer.Data != nullptr) {
    206     (*Processor)(Mode, Buffer);
    207     Buffer = (*Iterator)(Buffer);
    208   }
    209   return XRayLogFlushStatus::XRAY_LOG_FLUSHED;
    210 }
    211