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