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